Package manager app started using tkinter

This commit is contained in:
_bryan 2023-02-15 22:27:45 +01:00
parent cf6dd4de24
commit 48a0d4e20c
48 changed files with 343 additions and 124 deletions

View File

@ -1,9 +1,15 @@
import argparse import argparse
from source.game import start_game from source.pkgexplore import start_explorer
def main():
parser = argparse.ArgumentParser(prog='MBH', description='Morrowind with Blackjack and Hookers', epilog='?')
parser.add_argument('-m', '--main', required=True)
parser.add_argument('-p', '--package', nargs='+')
parser.add_argument('-e', '--explore', action='store_true')
args = parser.parse_args()
if args.explore:
start_explorer(args)
if __name__ == '__main__': if __name__ == '__main__':
parser = argparse.ArgumentParser(prog='MBH', description='Morrowind with Blackjack and hookers', epilog='?') main()
parser.add_argument('-p', '--package', nargs='+')
args = parser.parse_args()
start_game(args.package)

View File

@ -1,4 +1,5 @@
{ {
"name": "main-assets", "name": "main-assets",
"version": "0.1-alpha" "version": "0.1-alpha",
"type": "main"
} }

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
assets/models/axis.glb Normal file

Binary file not shown.

BIN
assets/models/box.glb Normal file

Binary file not shown.

Binary file not shown.

View File

BIN
assets/models/suz.glb Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
assets/textures/axis.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

BIN
assets/textures/cursed.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 988 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 458 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 526 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 633 KiB

BIN
icons/application.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 464 B

BIN
icons/brick.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 399 B

BIN
icons/bricks.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 825 B

BIN
icons/color_swatch.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 B

BIN
icons/color_wheel.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 892 B

BIN
icons/computer.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 667 B

BIN
icons/folder.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 537 B

BIN
icons/page_red.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 641 B

BIN
icons/picture.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 606 B

BIN
icons/pictures.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 704 B

BIN
icons/shape_group.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 553 B

BIN
icons/shape_square.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 B

View File

@ -1,100 +0,0 @@
import os
import posixpath
import json
from panda3d.core import VirtualFileSystem
class PackageNotFound(FileNotFoundError):
pass
class PackageMetaNotFound(FileNotFoundError):
pass
class PackageInvalid(FileNotFoundError):
pass
class PackageDuplicate(FileNotFoundError):
pass
class Package:
def __init__(self, name, vfs_dir):
self.name = name
self.vfs_dir = vfs_dir
class Filesystem:
def __init__(self):
self.package_list = []
self.package_map = {}
self.vfs = VirtualFileSystem.getGlobalPtr()
self.include('assets/')
self.mdl_missing = loader.loadModel('/main-assets/models/missing.glb')
self.mdl_missing.setTexture(loader.loadTexture('/main-assets/textures/missing_mdl.png'))
self.tex_missing = loader.loadTexture('/main-assets/textures/missing_tex.png')
def include(self, path):
if not os.path.exists(path):
raise PackageNotFound(path)
gamepkg_path = os.path.join(path, 'gamepackage.json')
if not os.path.exists(gamepkg_path):
raise PackageMetaNotFound(path)
meta = json.load(open(gamepkg_path))
if 'name' not in meta:
raise PackageInvalid(path)
if meta['name'] in self.package_map:
raise PackageDuplicate(meta['name'])
vfs_path = f'/{meta["name"]}'
vfs.mount(path, f'/{meta["name"]}', 0)
new_package = Package(meta["name"], vfs_path)
self.package_map[meta['name']] = new_package
self.package_list.insert(0, new_package)
def find_texture(self, tex_path):
try:
if tex_path[0:2] == '$/':
for package in self.package_list:
path = posixpath.join('/', package.name, 'textures', tex_path[2:])
if self.vfs.exists(path):
return loader.loadTexture(path)
return self.tex_missing
else:
resource_path = model_path.split('/')
path = posixpath.join('/', resource_path[0], 'textures', '/'.join(resource_path[1:]))
return loader.loadTexture(path)
except IOError:
return self.tex_missing
def find_model(self, model_path):
try:
if model_path[0:2] == '$/':
for package in self.package_list:
path = posixpath.join('/', package.name, 'models', model_path[2:])
if self.vfs.exists(path):
return loader.loadModel(path)
return self.mdl_missing
else:
resource_path = model_path.split('/')
path = posixpath.join('/', resource_path[0], 'models', '/'.join(resource_path[1:]))
return loader.loadModel(path)
except IOError:
return self.mdl_missing

View File

@ -1,30 +1,24 @@
from .filesystem import Filesystem from .packages import PackageManager
from direct.showbase.ShowBase import ShowBase from direct.showbase.ShowBase import ShowBase
from panda3d.core import WindowProperties from direct.actor.Actor import Actor
from panda3d.core import WindowProperties, TextureStage, AmbientLight, PointLight
import simplepbr
import gltf
class Game(ShowBase): class Game(ShowBase):
def __init__(self, packages): def __init__(self, packages):
ShowBase.__init__(self) ShowBase.__init__(self)
#self.disableMouse()
self.fs = Filesystem() simplepbr.init()
for package in packages: gltf.patch_loader(self.loader)
self.fs.include(package)
mdl2 = self.fs.find_model('$/arrangements/arrange1.glb') self.camLens.setFov(90)
mdl2.reparentTo(render) self.camera.setPos(0, -4, 1)
mdl2.setTexture(self.fs.find_texture('$/sfsd.png'), 1)
mdl_missing = self.fs.find_model('$/kakahead')
mdl_missing.reparentTo(render)
winprops = WindowProperties() winprops = WindowProperties()
winprops.setSize(1600, 900) winprops.setSize(1600, 900)
self.win.requestProperties(winprops) self.win.requestProperties(winprops)
def start_game(packages):
if not packages:
packages = []
game = Game(packages)
game.run()

33
source/inspector.py Normal file
View File

@ -0,0 +1,33 @@
from .packages import PackageManager
from direct.showbase.ShowBase import ShowBase
from panda3d.core import WindowProperties, TextureStage
class Game(ShowBase):
def __init__(self, packages):
ShowBase.__init__(self)
#self.disableMouse()
self.fs = PackageManager()
for package in packages:
self.fs.include(package)
mdl2 = self.fs.find_model('$/arrangements/arrange3.glb')
mdl2.reparentTo(render)
mdl2.find('origin/wall').setTexture(self.fs.find_texture('$/generic_noise.png'))
mdl_missing = self.fs.find_model('main-assetsz/sword1/sword1.glb')
print(mdl_missing)
mdl_missing.reparentTo(render)
winprops = WindowProperties()
winprops.setSize(1600, 900)
self.win.requestProperties(winprops)
def start_game(packages):
if not packages:
packages = []
game = Game(packages)
game.run()

View File

@ -0,0 +1,2 @@
from .manager import PackageManager

14
source/packages/errors.py Normal file
View File

@ -0,0 +1,14 @@
class FilepathNotFound(Exception):
pass
class GamePackageMissing(Exception):
pass
class GamePackageMalformed(Exception):
pass
class PackageAlreadyLoaded(Exception):
pass
class InvalidPackageType(Exception):
pass

View File

@ -0,0 +1,41 @@
import os, json
from .package import Package
from .errors import *
class PackageManager:
def __init__(self, vfs):
self.vfs = vfs
self.package_map = {}
self.package_list = []
self.main_package = None
def get_package_meta(self, filepath):
if not os.path.exists(filepath):
raise FilepathNotFound(filepath)
gamepkg_path = os.path.join(filepath, 'gamepackage.json')
if not os.path.exists(gamepkg_path):
raise GamePackageMissing(gamepkg_path)
meta = json.load(open(gamepkg_path))
if 'name' not in meta or 'type' not in meta:
raise GamePackageMalformed(gamepkg_path)
return meta
def set_main_package(self, filepath):
meta = self.get_package_meta(filepath)
if meta['type'] != 'main':
raise InvalidPackageType(filepath, meta['type'])
vfs_path = f'/main/'
self.vfs.mount(filepath, vfs_path, 0)
new_package = Package(type('', (object,), meta), vfs_path, self.vfs)
self.main_package = new_package
def include_package(self, filepath):
meta = self.get_package_meta(filepath)
if meta['name'] in self.package_map:
raise PackageAlreadyLoaded(meta['name'])
vfs_path = f'/include/{meta["name"]}'
self.vfs.mount(filepath, vfs_path, 0)
new_package = Package(type('', (object,), meta), vfs_path, self.vfs)
self.package_map[meta['name']] = new_package
self.package_list.insert(0, new_package)

View File

@ -0,0 +1,32 @@
import posixpath
from direct.stdpy.file import walk
class Package:
def __init__(self, meta, mount_dir, vfs):
self.meta = meta
self.mount_dir = mount_dir
self.vfs = vfs
def all_models(self):
models_path = posixpath.join(self.mount_dir, 'models')
output = []
for root, paths, files in walk(models_path):
rel_root = root.replace(f'{models_path}', '').strip()
if len(rel_root) > 0 and rel_root[0] == '/':
rel_root = rel_root[1:]
for filepath in files:
output.append(posixpath.join(rel_root, filepath))
return output
def all_textures(self):
textures_path = posixpath.join(self.mount_dir, 'textures')
output = []
for root, paths, files in walk(textures_path):
rel_root = root.replace(f'{textures_path}', '').strip()
if len(rel_root) > 0 and rel_root[0] == '/':
rel_root = rel_root[1:]
for filepath in files:
output.append(posixpath.join(rel_root, filepath))
return output

191
source/pkgexplore.py Normal file
View File

@ -0,0 +1,191 @@
import posixpath
import tkinter as tk
import tkinter.ttk as ttk
from source.packages import PackageManager
from direct.showbase.ShowBase import ShowBase
from panda3d.core import VirtualFileSystem, Material
from direct.stdpy.file import walk
import simplepbr
import gltf
def get_icons():
return type('', (object,), {
'app': tk.PhotoImage(file="icons/application.png"),
'brick': tk.PhotoImage(file="icons/brick.png"),
'bricks': tk.PhotoImage(file="icons/bricks.png"),
'computer': tk.PhotoImage(file="icons/computer.png"),
'folder': tk.PhotoImage(file="icons/folder.png"),
'shape_group': tk.PhotoImage(file="icons/shape_group.png"),
'pictures': tk.PhotoImage(file="icons/pictures.png"),
'picture': tk.PhotoImage(file='icons/picture.png'),
"page_red": tk.PhotoImage(file='icons/page_red.png'),
'shape_square': tk.PhotoImage(file='icons/shape_square.png'),
'color_wheel': tk.PhotoImage(file='icons/color_wheel.png'),
'color_swatch': tk.PhotoImage(file='icons/color_swatch.png')
})()
class PandaApp(ShowBase):
def __init__(self, fStartDirect=True, windowType=None):
super().__init__(fStartDirect, windowType)
running = True
def on_tk_closed():
global running
running = False
def add_package_contents_to_tree(tree, package, type, name, extensions, icon_folder, icon_group, icon_item):
data_path = posixpath.join(package.mount_dir, type)
tree.insert(package.mount_dir, 'end', data_path, text=f' {name}', image=icon_group)
file_count = 0
for root, paths, files in walk(data_path):
for path in paths:
tree.insert(root, 'end', posixpath.join(root, path), text=f' {path}', image=icon_folder)
for file in files:
if file.lower().endswith(extensions):
file_count += 1
tree.insert(root, 'end', posixpath.join(root, file), text=f' {file}', image=icon_item)
tree.item(data_path, text=f' {name} ({file_count})')
def add_package_models_to_tree(tree, package, icons):
add_package_contents_to_tree(tree, package, 'models/', '3D Models', ('.glb', '.gltf', '.obj', '.egg'), icons.folder, icons.shape_group, icons.shape_square)
def add_package_textures_to_tree(tree, package, icons):
add_package_contents_to_tree(tree, package, 'textures/', 'Image Textures', ('.png', '.jpg', '.bmp'), icons.folder, icons.pictures, icons.picture)
def add_package_materials_to_tree(tree, package, icons):
add_package_contents_to_tree(tree, package, 'materials/', 'Materials', ('.json'), icons.folder, icons.color_wheel, icons.color_swatch)
def add_package_to_tree(tree, package, icons):
add_package_models_to_tree(tree, package, icons)
add_package_textures_to_tree(tree, package, icons)
add_package_materials_to_tree(tree, package, icons)
def create_tk_treeview(parent, packages, icons):
tree = ttk.Treeview(parent, show="tree")
tree.insert('', 'end', '/', text=' /', open=True, image=icons.app)
tree.insert('/', 'end', '/main/', text=f' Main Package "{packages.main_package.meta.name}" - {packages.main_package.meta.version}', image=icons.computer)
tree.insert('/', 'end', '/include/', text=f' Included Packages ({len(packages.package_list)})', image=icons.bricks)
add_package_to_tree(tree, packages.main_package, icons)
for package in packages.package_list:
tree.insert('/include/', 'end', package.mount_dir, text=f' "{package.meta.name}" - {package.meta.version}', image=icons.brick)
add_package_to_tree(tree, package, icons)
#tree.pack(fill='x')
return tree
class TreeEvents:
def __init__(self, tree, panda):
self.tree = tree
self.panda = panda
self.tree.bind('<Double-1>', self.on_double_click)
self.nodes = []
def on_double_click(self, event):
item = self.tree.selection()[0]
if item.lower().endswith(('.glb', '.gltf', '.obj', '.egg')):
mat = Material()
mat.setAmbient((1, 0, 0, 1))
node = self.panda.loader.loadModel(item)
node.reparentTo(self.panda.render)
node.setMaterial(mat)
self.nodes.append(node)
def start_explorer(args):
tk_app = tk.Tk()
tk_app.geometry("700x500")
tk_app.protocol('WM_DELETE_WINDOW', on_tk_closed)
#tk_app = tk.Frame(tk_app, width=500)
tk_app.grid_rowconfigure(0, weight=1)
tk_app.grid_columnconfigure(0, weight=1)
tk_app.grid_columnconfigure(1, weight=1)
package_frame = tk.Frame(tk_app, highlightbackground="black", highlightthickness=1, padx=4, pady=4)
package_frame.grid(column=0, row=0, sticky="news")
package_frame.grid_columnconfigure(0, weight=1)
package_frame.grid_rowconfigure(0, weight=1)
package_frame.grid_rowconfigure(1, weight=1000)
label1 = tk.Label(package_frame, text='Packages')
label1.grid(row=0, column=0, sticky='n')
scene_frame = tk.Frame(tk_app, highlightbackground="black", highlightthickness=1, padx=4, pady=4)
scene_frame.grid(column=1, row=0, sticky="news")
scene_frame.grid_columnconfigure(0, weight=1)
scene_frame.grid_rowconfigure(0, weight=1)
scene_frame.grid_rowconfigure(1, weight=10000)
label2 = tk.Label(scene_frame, text='Scene Graph')
label2.grid(row=0, column=0)
scene_tree = ttk.Treeview(scene_frame)
scene_tree.grid(row=1, column=0, sticky="news")
panda_app = PandaApp()
simplepbr.init()
gltf.patch_loader(panda_app.loader)
packages = PackageManager(VirtualFileSystem.getGlobalPtr())
packages.set_main_package(args.main)
if args.package:
for include in args.package:
packages.include_package(include)
icons = get_icons()
tree = create_tk_treeview(package_frame, packages, icons)
tree.grid(row=1, column=0, sticky="news")
events = TreeEvents(tree, panda_app)
try:
while running:
panda_app.taskMgr.step()
tk_app.update_idletasks()
tk_app.update()
except KeyboardInterrupt as stop:
pass
'''
window = tk.Tk()
icons = get_icons()
fs = PackageManager(VirtualFileSystem.getGlobalPtr())
fs.set_main_package('assets')
mdls = fs.main_package.all_models()
txts = fs.main_package.all_textures()
print(mdls, txts, loader)
menu = tk.Menu(window)
menu.add_command(label="Exit", command=window.quit)
window.config(menu=menu)
mainframe = tk.Frame(window, borderwidth=5)
mainframe.grid(column=0, row=0)
mainframe.columnconfigure(0, weight=3)
packageTree = ttk.Treeview(mainframe, show="tree")
packageTree.insert('', 'end', '/', text=' Virtual FS', image=icons.app)
packageTree.pack()
window.mainloop()
frame = tk.Frame(window, borderwidth=5)
frame.pack()
frame.columnconfigure(0, weight=1)
frame.columnconfigure(1, weight=3)
tree = ttk.Treeview(frame, show="tree")
tree.grid(column=0, row=0, sticky=tk.NW)
tree.insert('', 'end', '/', text=' Virtual Filesystem', open=True, image=icons.app)
tree.insert('/', 'end', '/main/', text=' main/', image=icons.computer)
tree.insert('/main/', 'end', '/main/models/', text=' models/', image=icons.folder)
tree.insert('/main/', 'end', '/main/textures/', text=' textures/', image=icons.folder)
tree.insert('/', 'end', '/packages/', text=' packages/', image=icons.bricks)
tree.insert('/packages/', 'end', '/packages/user-package-1/', text=' user-package-1/', image=icons.brick)
tree.insert('/packages/', 'end', '/packages/user-package-2/', text=' user-package-2/', image=icons.brick)
tree.insert('/packages/', 'end', '/packages/user-package-3/', text=' user-package-3/', image=icons.brick)
window.mainloop()
'''

5
testmod/gamepackage.json Normal file
View File

@ -0,0 +1,5 @@
{
"name": "test-mod",
"version": "1.1-beta",
"type": "include"
}

BIN
testmod/models/axis.glb Normal file

Binary file not shown.

BIN
testmod/models/box.glb Normal file

Binary file not shown.

BIN
testmod/models/missing.glb Normal file

Binary file not shown.