diff --git a/__main__.py b/__main__.py new file mode 100644 index 0000000..bbedd24 --- /dev/null +++ b/__main__.py @@ -0,0 +1,9 @@ + +import argparse +from source.game import start_game + +if __name__ == '__main__': + parser = argparse.ArgumentParser(prog='MBH', description='Morrowind with Blackjack and hookers', epilog='?') + parser.add_argument('-p', '--package', nargs='+') + args = parser.parse_args() + start_game(args.package) diff --git a/assets/gamepackage.json b/assets/gamepackage.json new file mode 100644 index 0000000..df69e31 --- /dev/null +++ b/assets/gamepackage.json @@ -0,0 +1,4 @@ +{ + "name": "main-assets", + "version": "0.1-alpha" +} \ No newline at end of file diff --git a/assets/models/missing.glb b/assets/models/missing.glb index a9e749e..d313646 100644 Binary files a/assets/models/missing.glb and b/assets/models/missing.glb differ diff --git a/assets/textures/missing.png b/assets/textures/missing.png deleted file mode 100644 index dc8573b..0000000 Binary files a/assets/textures/missing.png and /dev/null differ diff --git a/assets/textures/missing_mdl.png b/assets/textures/missing_mdl.png new file mode 100644 index 0000000..5876147 Binary files /dev/null and b/assets/textures/missing_mdl.png differ diff --git a/assets/textures/missing_tex.png b/assets/textures/missing_tex.png new file mode 100644 index 0000000..6b82fa4 Binary files /dev/null and b/assets/textures/missing_tex.png differ diff --git a/source/map/__init__.py b/source/__init__.py similarity index 100% rename from source/map/__init__.py rename to source/__init__.py diff --git a/source/__main__.py b/source/__main__.py deleted file mode 100644 index f7cda49..0000000 --- a/source/__main__.py +++ /dev/null @@ -1,55 +0,0 @@ - -from direct.showbase.ShowBase import ShowBase -from panda3d.core import WindowProperties, GeomVertexArrayFormat, GeomVertexFormat, Geom, GeomVertexData, GeomVertexWriter, GeomTriangles, GeomNode -from panda3d.core import VirtualFileSystem -from panda3d.core import Vec3 - -from map.file import parse_map_file - - -class DungeonCell: - def __init__(self): - self.mesh = None - self.bounds = [None, None] - self.connections = [] - - def getBounds(self): - bmin, bmax = self.mesh.getTightBounds() - self.bounds = [bmin, bmax] - -class CellArrange1(DungeonCell): - def __init__(self): - DungeonCell.__init__(self) - self.mesh = loader.loadModel("/models/arrangements/arrange1.glb") - - self.connections = [ - Vec3(0, 5, 0), - Vec3(0, -5, 0), - Vec3(5, 0, 0), - Vec3(-5, 0, 0) - ] - self.getBounds() - -class Game(ShowBase): - def __init__(self): - ShowBase.__init__(self) - - vfs = VirtualFileSystem.getGlobalPtr() - vfs.mount('assets', '/', 0) - - tex_bricks = loader.loadTexture('/textures/generic_bricks.png') - tex_floor = loader.loadTexture('/textures/generic_tiles.png') - - - self.room = CellArrange1() - self.room.mesh.reparentTo(render) - self.room.mesh.find('**/A1.Walls').setTexture(tex_bricks, 1) - self.room.mesh.find('**/A1.Floor').setTexture(tex_floor, 1) - print(self.room.bounds) - - winprops = WindowProperties() - winprops.setSize(1600, 900) - self.win.requestProperties(winprops) - -game = Game() -game.run() \ No newline at end of file diff --git a/source/filesystem.py b/source/filesystem.py new file mode 100644 index 0000000..a6dd50d --- /dev/null +++ b/source/filesystem.py @@ -0,0 +1,100 @@ + +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 + + + + + + + + + + + + + + + + + + + + + diff --git a/source/game.py b/source/game.py new file mode 100644 index 0000000..c82550d --- /dev/null +++ b/source/game.py @@ -0,0 +1,30 @@ + +from .filesystem import Filesystem +from direct.showbase.ShowBase import ShowBase +from panda3d.core import WindowProperties + +class Game(ShowBase): + def __init__(self, packages): + ShowBase.__init__(self) + #self.disableMouse() + + self.fs = Filesystem() + for package in packages: + self.fs.include(package) + + mdl2 = self.fs.find_model('$/arrangements/arrange1.glb') + mdl2.reparentTo(render) + mdl2.setTexture(self.fs.find_texture('$/sfsd.png'), 1) + + mdl_missing = self.fs.find_model('$/kakahead') + 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() \ No newline at end of file diff --git a/source/map/csg.py b/source/map/csg.py deleted file mode 100644 index 1b323fd..0000000 --- a/source/map/csg.py +++ /dev/null @@ -1,11 +0,0 @@ - - -from panda3d.core import Vec3 - - - - - -def convert_to_csg(mapfile): - - return \ No newline at end of file diff --git a/source/map/file.py b/source/map/file.py deleted file mode 100644 index 721f940..0000000 --- a/source/map/file.py +++ /dev/null @@ -1,124 +0,0 @@ - -from re import match as regexp -from enum import Enum -from panda3d.core import Vec3 - - -class MapFace: - def __init__(self): - self.v1 = Vec3() - self.v2 = Vec3() - self.v3 = Vec3() - self.tex = '' - self.offset = Vec3() - self.scale = Vec3() - self.angle = 0.0 - self.normal = Vec3() - -class MapBrush: - def __init__(self): - self.faces = [] - -class MapEntity: - def __init__(self): - self.classname = '' - self.attributes = {} - self.brushes = [] - -class MapFile: - def __init__(self, filepath, entities): - self.filepath = filepath - self.entities = entities - def entity_count(self): - return len(self.entities) - def brush_count(self): - total = 0 - for ent in self.entities: - total += len(ent.brushes) - return total - def face_count(self): - total = 0 - for ent in self.entities: - for brush in ent.brushes: - total += len(brush.faces) - return total - -class MapStack(Enum): - TOP = 0 - ENTITY = 1 - BRUSH = 2 - - - -def parse_map_file(filepath): - entities = [] - with open(filepath, 'r') as mapfile: - current_stack = MapStack.TOP - current_entity = None - current_brush = None - - for mapline in mapfile: - if mapline[:2] == '//': - continue - - if current_stack == MapStack.TOP and mapline[:1] == '{': - current_stack = MapStack.ENTITY - current_entity = MapEntity() - entities.append(current_entity) - - elif current_stack == MapStack.ENTITY and mapline[:1] == '}': - current_stack = MapStack.TOP - current_entity = None - - elif current_stack == MapStack.ENTITY and mapline[:1] == '{': - current_stack = MapStack.BRUSH - current_brush = MapBrush() - current_entity.brushes.append(current_brush) - - elif current_stack == MapStack.BRUSH and mapline[:1] == '}': - current_stack = MapStack.ENTITY - current_brush = None - - elif current_stack == MapStack.ENTITY and mapline[:1] == '"': - result = regexp('^"(.+)" "(.+)"$', mapline) - current_entity.attributes[result.group(1)] = result.group(2) - - elif current_stack == MapStack.BRUSH and mapline[:1] == '(': - result = regexp("^(\\(.+\\)) (.+)", mapline) - coordinates = result.group(1) - texture = result.group(2).split(' ') - - as_num = lambda v: float(v) - verts = regexp("^\\( (.+?) \\) \\( (.+?) \\) \\( (.+?) \\)$", coordinates) - verts1 = map(as_num, verts.group(1).split(' ')) - verts2 = map(as_num, verts.group(2).split(' ')) - verts3 = map(as_num, verts.group(3).split(' ')) - - current_face = MapFace() - current_face.v1 = Vec3(tuple(verts1)) - current_face.v2 = Vec3(tuple(verts2)) - current_face.v3 = Vec3(tuple(verts3)) - current_face.tex = texture[0] - current_face.offset = Vec3(float(texture[1]), float(texture[2]), 0) - current_face.angle = float(texture[3]) - current_face.scale = Vec3(float(texture[4]), float(texture[5]), 0) - current_brush.faces.append(current_face) - - edge_a = current_face.v2 - current_face.v1 - edge_b = current_face.v3 - current_face.v1 - current_face.normal = edge_b.cross(edge_a).normalized() - return MapFile(filepath, entities) - -''' -mapfile = parse_map_file("C:\\Users\\Bryan\\Documents\\MBH\\assets\\meshes\\maps\\test.map") -print(mapfile.entity_count()) -print(mapfile.brush_count()) -print(mapfile.face_count()) -''' - - - - - - -