diff --git a/.gitignore b/.gitignore index b6e4761..a6cd46a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +# Visual Studio Code +.vscode/ + # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] diff --git a/README.md b/README.md index 11dad4f..ad70aff 100644 --- a/README.md +++ b/README.md @@ -11,10 +11,14 @@ It is recommended to toggle Blender's System Console to watch the addon's progre ### Download the latest version of the Addon from **[here](https://github.com/SWTOR-Slicers/SWTOR-Area-Assembler/releases)**. ### Full usage guide **[here](https://github.com/SWTOR-Slicers/WikiPedia/wiki/Assembling-SWTOR-Game-Areas-via-the-SWTOR-Area-Assembler-Addon-for-Blender)**. +___ ---- -## Changelog: +CHANGELOG: +**V.1.3.1: Addon-crashing bug corrected:** +Extensions in .json entries' filepaths weren't thorough enough. Now they are. +* There's still an issue with some collision objects being parents of others. Somehow they are being filtered out even when not meant to. Investigating… +___ **v.1.3.0: Support for placeables:** Importing of placeables, both static (.plc directly mentioning .gr2 and .mag) and dynamic (.plc mentioning .dyn that in turn contain .gr2 and .mag). That means that objects such as GTN booths, holoprojectors, spaceship cockpit's seats, etc. that weren't appearing in the imported scenes show up now. @@ -51,5 +55,5 @@ In order to deal with two kinds of enormous area imports that leave Blender in a Resulting Collections are excluded (checkbox in Outliner, 'e' shortcut') to keep Blender fully responsive and be able to manage them without lag. Excluded Collections won't list their objects in the Outliner: that's normal. **Recommended when importing a massive number of areas, such as whole worlds.** - -(Excluding Collections resets the hide/show state of the Collections' contents. The **Hide Objects After Importing** option won't have an effect if the **Exclude Collections After Importing** option is on) + + (Excluding Collections resets the hide/show state of the Collections' contents. The **Hide Objects After Importing** option won't have an effect if the **Exclude Collections After Importing** option is on) \ No newline at end of file diff --git a/swtor_area_assembler.zip b/swtor_area_assembler.zip index 411d1d4..da7b2ae 100644 Binary files a/swtor_area_assembler.zip and b/swtor_area_assembler.zip differ diff --git a/swtor_area_assembler/__init__.py b/swtor_area_assembler/__init__.py index 470a1f1..2ee4c16 100644 --- a/swtor_area_assembler/__init__.py +++ b/swtor_area_assembler/__init__.py @@ -8,7 +8,7 @@ bl_info = { "name": "SWTOR Area Assembler", "author": "ZeroGravitas & Crunch", - "version": (1, 3, 0), + "version": (1, 3, 1), "blender": (3, 1, 0), "category": "SWTOR", "location": "File > Import > SWTOR (Area .json)", diff --git a/swtor_area_assembler/area_import.py b/swtor_area_assembler/area_import.py index 3ae989c..83cbc24 100644 --- a/swtor_area_assembler/area_import.py +++ b/swtor_area_assembler/area_import.py @@ -318,7 +318,7 @@ def execute(self, context): swtor_id = element["id"] swtor_parent_id = element["parent"] - if swtor_filepath.endswith("spn_p"): + if swtor_filepath.endswith(".spn_p"): # .SPN_P OBJECT REFERENCE (non-NPC .SPN) if swtor_filepath in spn_table: @@ -514,11 +514,11 @@ def execute(self, context): # Set some variables that will be used per element constantly. swtor_filepath = element["assetName"] - if not (swtor_filepath.endswith("gr2") or - swtor_filepath.endswith("lit") or - swtor_filepath.endswith("hms") or - swtor_filepath.endswith("mag") or - swtor_filepath.endswith("spn_p") or + if not (swtor_filepath.endswith(".gr2") or + swtor_filepath.endswith(".lit") or + swtor_filepath.endswith(".hms") or + swtor_filepath.endswith(".mag") or + swtor_filepath.endswith(".spn_p") or ("dbo" in swtor_filepath and self.SAAboolSkipDBOObjects == False) ): continue @@ -541,7 +541,7 @@ def execute(self, context): - if swtor_filepath.endswith("lit"): + if swtor_filepath.endswith(".lit"): # LIGHT OBJECT. ---------------------------------- @@ -562,7 +562,7 @@ def execute(self, context): continue - elif swtor_filepath.endswith("hms"): + elif swtor_filepath.endswith(".hms"): # TERRAIN OBJECT. --------------------------------- @@ -636,7 +636,7 @@ def execute(self, context): print(f'{LINEBACK}{amount_processed * 100 / amount_to_process:6.2f} % AREA: {json_name:<{max_json_name_length}} ID: {swtor_id} NAME: {swtor_name:{max_swtor_name_length}}', end="") - if swtor_filepath.endswith("mag"): + if swtor_filepath.endswith(".mag"): # .MAG OBJECT REFERENCE try: with open( str( Path(swtor_resources_folderpath) / Path(swtor_filepath) ), "r") as read_mag_file: @@ -693,7 +693,7 @@ def execute(self, context): link_objects_to_collection(imported_objects, location_objects_collection, move = True) else: - print("NOT PRESENT AMONG ASSETS. DISCARDED") + print("FILE NOT FOUND. DISCARDED") continue else: @@ -882,7 +882,7 @@ def execute(self, context): # would lead to extra nested rotations after the general # parenting stage that we don't know how to correct. - if not swtor_name.endswith("hms"): + if not swtor_name.endswith(".hms"): position = [element["position"][0], element["position"][1], element["position"][2]] @@ -902,7 +902,7 @@ def execute(self, context): blender_object.scale = scale # Resize lights to something more reasonable - if swtor_name.endswith("lit"): + if swtor_name.endswith(".lit"): scale = scale / 10 # Fill custom properties to the object to facilitate @@ -1159,7 +1159,7 @@ def unregister(): # ------------------------------------------------------------------------------- -# START UTLITY FUNCTIONS -------------------------------------------------------- +# UTLITY FUNCTIONS -------------------------------------------------------------- # ------------------------------------------------------------------------------- @@ -1170,7 +1170,7 @@ def unregister(): @contextlib.contextmanager def suppress_stdout(suppress=True): - # Output to console supressor for hiding .gr2 addon + # Console output supressor for hiding the .gr2 addon's output. # Use suppress=False to allow for specific outputs # in the middle of a suppressed block of code. # Usage is: @@ -1189,6 +1189,62 @@ def suppress_stdout(suppress=True): yield +# Cre + +def encase_objects_with_empty(objects, empty_name = "Empty", collection_name = ""): + # Create a new Empty object + empty = bpy.data.objects.new(empty_name, None) + if collection_name == "": + bpy.context.collection.objects.link(empty) + else: + if collection_name not in bpy.data.collections: + bpy.data.collections.new(collection_name) + bpy.data.collections[collection_name].objects.link(empty) + + # Set the Empty object's display type to 'CUBE' + empty.empty_display_type = 'CUBE' + + # Set the Empty object's origin to the center of its base + empty.matrix_world = calculate_base_center_matrix(objects) + + # Parent objects to the Empty object + for obj in objects: + obj.parent = empty + + return empty + +def calculate_base_center_matrix(objects): + # Find the minimum and maximum coordinates of all objects' bounding boxes + min_x, min_y, min_z = float('inf'), float('inf'), float('inf') + max_x, max_y, max_z = float('-inf'), float('-inf'), float('-inf') + + for obj in objects: + bbox = obj.bound_box + for vertex in bbox: + min_x = min(min_x, vertex[0]) + min_y = min(min_y, vertex[1]) + min_z = min(min_z, vertex[2]) + max_x = max(max_x, vertex[0]) + max_y = max(max_y, vertex[1]) + max_z = max(max_z, vertex[2]) + + # Calculate the center of the base + base_center = ( + (min_x + max_x) / 2, + (min_y + max_y) / 2, + min_z + ) + + # Calculate the translation vector to move the origin + translation_vector = -base_center + + # Create a translation matrix + translation_matrix = Matrix.Translation(translation_vector) + + return translation_matrix + + + # UNUSED: THE OPS ISN'T WORKING def hide_outliner_one_level():