Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@
/build
/run
/.unused
*.pyc
addon/umap.py
BlenderUmap.log
35 changes: 35 additions & 0 deletions addon/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

bl_info = {
"name" : "BlenderUmap",
"author" : "Amrsatrio, MountainFlash (MinshuG)",
"description" : "",
"blender" : (2, 80, 0),
"version" : (0, 0, 1),
"location" : "View3D > Properties > Umap",
"warning" : "",
"doc_url": "https://github.com/Amrsatrio/BlenderUmap/blob/master/README.md",
"category" : "Add Mesh"
}


from . import auto_load

auto_load.init()

def register():
auto_load.register()

def unregister():
auto_load.unregister()
138 changes: 138 additions & 0 deletions addon/auto_load.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import os
import bpy
import sys
import typing
import inspect
import pkgutil
import importlib
from pathlib import Path

__all__ = (
"init",
"register",
"unregister",
)

modules = None
ordered_classes = None

def init():
global modules
global ordered_classes

modules = get_all_submodules(Path(__file__).parent)
ordered_classes = get_ordered_classes_to_register(modules)

def register():
for cls in ordered_classes:
bpy.utils.register_class(cls)

for module in modules:
if module.__name__ == __name__:
continue
if hasattr(module, "register"):
module.register()

def unregister():
for cls in reversed(ordered_classes):
bpy.utils.unregister_class(cls)

for module in modules:
if module.__name__ == __name__:
continue
if hasattr(module, "unregister"):
module.unregister()


# Import modules
#################################################

def get_all_submodules(directory):
return list(iter_submodules(directory, directory.name))

def iter_submodules(path, package_name):
for name in sorted(iter_submodule_names(path)):
yield importlib.import_module("." + name, package_name)

def iter_submodule_names(path, root=""):
for _, module_name, is_package in pkgutil.iter_modules([str(path)]):
if is_package:
sub_path = path / module_name
sub_root = root + module_name + "."
yield from iter_submodule_names(sub_path, sub_root)
else:
yield root + module_name


# Find classes to register
#################################################

def get_ordered_classes_to_register(modules):
return toposort(get_register_deps_dict(modules))

def get_register_deps_dict(modules):
deps_dict = {}
classes_to_register = set(iter_classes_to_register(modules))
for cls in classes_to_register:
deps_dict[cls] = set(iter_own_register_deps(cls, classes_to_register))
return deps_dict

def iter_own_register_deps(cls, own_classes):
yield from (dep for dep in iter_register_deps(cls) if dep in own_classes)

def iter_register_deps(cls):
for value in typing.get_type_hints(cls, {}, {}).values():
dependency = get_dependency_from_annotation(value)
if dependency is not None:
yield dependency

def get_dependency_from_annotation(value):
if isinstance(value, tuple) and len(value) == 2:
if value[0] in (bpy.props.PointerProperty, bpy.props.CollectionProperty):
return value[1]["type"]
return None

def iter_classes_to_register(modules):
base_types = get_register_base_types()
for cls in get_classes_in_modules(modules):
if any(base in base_types for base in cls.__bases__):
if not getattr(cls, "is_registered", False):
yield cls

def get_classes_in_modules(modules):
classes = set()
for module in modules:
for cls in iter_classes_in_module(module):
classes.add(cls)
return classes

def iter_classes_in_module(module):
for value in module.__dict__.values():
if inspect.isclass(value):
yield value

def get_register_base_types():
return set(getattr(bpy.types, name) for name in [
"Panel", "Operator", "PropertyGroup",
"AddonPreferences", "Header", "Menu",
"Node", "NodeSocket", "NodeTree",
"UIList", "RenderEngine"
])


# Find order to register to solve dependencies
#################################################

def toposort(deps_dict):
sorted_list = []
sorted_values = set()
while len(deps_dict) > 0:
unsorted = []
for value, deps in deps_dict.items():
if len(deps) == 0:
sorted_list.append(value)
sorted_values.add(value)
else:
unsorted.append(value)
deps_dict = {value : deps_dict[value] - sorted_values for value in unsorted}
return sorted_list
120 changes: 120 additions & 0 deletions addon/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import bpy
from typing import List, Any, TypeVar
import os
import json

T = TypeVar("T")

def from_list(x: Any) -> List[T]:
l = []
l.append({
"Guid": "00000000000000000000000000000000",
"Key": bpy.context.scene.aeskey
})
for a in x:
if a.pakname == "" and a.daeskey == "":
continue
if a.guid == "" and a.pakname == "":
continue
if a.daeskey == "":
continue

d = {}
if a.guid != "":
d["Guid"] = a.guid
if a.pakname != "":
d["FileName"] = a.pakname
d["Key"] = a.daeskey
l.append(d)
return l

class Config:
Documentation: str = "https://github.com/Amrsatrio/BlenderUmap/blob/master/README.md"
PaksDirectory: str
ExportPath: str
UEVersion: str
EncryptionKeys: List[Any]
bDumpAssets: bool
ObjectCacheSize: int
bReadMaterials: bool
bExportToDDSWhenPossible: bool
bExportBuildingFoundations: bool
bUseUModel: bool
UModelAdditionalArgs: str
ExportPackage: str

def __init__(self) -> None:
sc = bpy.context.scene
self.PaksDirectory = sc.Game_Path[:-1]
self.ExportPath = sc.exportPath
self.UEVersion = sc.ue4_versions
self.EncryptionKeys = sc.dpklist
self.bDumpAssets = sc.bdumpassets
self.ObjectCacheSize = sc.ObjectCacheSize
self.bReadMaterials = sc.readmats
self.bExportToDDSWhenPossible = sc.bExportToDDSWhenPossible
self.bExportBuildingFoundations = sc.bExportBuildingFoundations
self.bUseUModel = sc.bUseUModel
self.UModelAdditionalArgs = sc.additionalargs
self.ExportPackage = sc.package

def to_dict(self) -> dict:
result: dict = {}
result["_Documentation"] = self.Documentation
result["PaksDirectory"] = self.PaksDirectory
result["ExportPath"] = self.ExportPath
result["UEVersion"] = self.UEVersion
result["bDumpAssets"] = self.bDumpAssets
result["ObjectCacheSize"] = self.ObjectCacheSize
result["bReadMaterials"] = self.bReadMaterials
result["bExportToDDSWhenPossible"] = self.bExportToDDSWhenPossible
result["bExportBuildingFoundations"] = self.bExportBuildingFoundations
result["bUseUModel"] = self.bUseUModel
result["UModelAdditionalArgs"] = self.UModelAdditionalArgs
result["ExportPackage"] = self.ExportPackage
result["EncryptionKeys"] = from_list(self.EncryptionKeys)
return result

def load(self, out = {}):
if not os.path.exists(os.path.join(self.ExportPath,"config.json")):
return
with open(os.path.join(self.ExportPath,"config.json"),"r") as f:
data = json.load(f)
out = data

sc = bpy.context.scene

sc.Game_Path = data["PaksDirectory"] + "/"
sc.exportPath = data["ExportPath"]
sc.ue4_versions = data["UEVersion"]
sc.bdumpassets = data["bDumpAssets"]
sc.ObjectCacheSize = data["ObjectCacheSize"]
sc.readmats = data["bReadMaterials"]
sc.bExportToDDSWhenPossible = data["bExportToDDSWhenPossible"]
sc.bExportBuildingFoundations = data["bExportBuildingFoundations"]
sc.bUseUModel = data["bUseUModel"]
sc.additionalargs = data["UModelAdditionalArgs"]
sc.package = data["ExportPackage"]

for a in range(len(sc.dpklist)):
sc.dpklist.remove(a)

sc.list_index = 0
i = 0
for x in data["EncryptionKeys"]:
if guid := x.get("Guid"):
if guid == "00000000000000000000000000000000":
sc.aeskey = x["Key"]
continue

sc.list_index = i
sc.dpklist.add()
dpk = sc.dpklist[i]
dpk.guid = x.get("Guid") or ""
dpk.pakname = x.get("FileName") or ""
dpk.daeskey = x["Key"]
i += 1

def dump(self,path):
with open(os.path.join(path,"config.json"),"w") as f:
json.dump(self.to_dict(),f,indent=4)
Loading