From 3cb2a69c81932e5b882b69c4c4bfbdd153a2dfee Mon Sep 17 00:00:00 2001 From: Torrin Leonard <82110564+torrinworx@users.noreply.github.com> Date: Mon, 6 Jun 2022 17:04:25 -0400 Subject: [PATCH] Changes to Materials and Logic - Added AutoSave before generation functionality to Other panel - Removed strip_empty_exclude function - Modified Exporter to work with new Material Randomizer layout - Added Enable Materials option in logicafyDNAsingle function in preparation for Material Randomizer Logic - Materials are no longer formatted like Variants, the Material List is now a dictionary where the keys are the names of the Materials and the values are the Rarity percentages. Each Variant in the Materials.json file can have a different list with different rarity values that are selected for only that variant. Material file format: ``` { "Variant Name": { "Material List": { "Material Name 1": 90, "Material Name 2": 5, "Material Name 3": 1, "Material Name 4": 4 }, "Variant Objects": [] } } ``` --- __init__.py | 14 ++++++++++ main/DNA_Generator.py | 46 +++++++-------------------------- main/Exporter.py | 10 ++++--- main/Logic.py | 7 +++-- main/Material_Generator.py | 53 ++++++++++++++++++++++---------------- 5 files changed, 63 insertions(+), 67 deletions(-) diff --git a/__init__.py b/__init__.py index 3390b9f..77d252b 100644 --- a/__init__.py +++ b/__init__.py @@ -376,6 +376,8 @@ class BMNFTS_PGT_Input_Properties(bpy.types.PropertyGroup): ) # Other Panel: + enableAutoSave: bpy.props.BoolProperty(name="Auto Save Before Generation") + # API Panel properties: apiKey: bpy.props.StringProperty(name="API Key", subtype='PASSWORD') @@ -478,6 +480,11 @@ class exportNFTs(bpy.types.Operator): name="Reverse Order") def execute(self, context): + + enableAutoSave = bpy.context.scene.input_tool.enableAutoSave + if enableAutoSave: + bpy.ops.wm.save_mainfile() + class input: nftName = bpy.context.scene.input_tool.nftName save_path = bpy.path.abspath(bpy.context.scene.input_tool.save_path) @@ -923,10 +930,17 @@ def draw(self, context): input_tool_scene = scene.input_tool """ + Other: + A place to store miscellaneous settings, features, and external links that the user may find useful but doesn't + want to get in the way of their work flow. Export Settings: This panel gives the user the option to export all settings from the Blend_My_NFTs addon into a config file. Settings will be read from the config file when running heedlessly. """ + + row = layout.row() + row.prop(input_tool_scene, "enableAutoSave") + layout.label(text=f"Running Blend_My_NFTs Headless:") save_path = bpy.path.abspath(bpy.context.scene.input_tool.save_path) diff --git a/main/DNA_Generator.py b/main/DNA_Generator.py index bcb6f70..838a39f 100644 --- a/main/DNA_Generator.py +++ b/main/DNA_Generator.py @@ -123,47 +123,18 @@ def attributeData(attributeVariants): return hierarchy -def strip_empty_exclude(hierarchy): - """ - Strips Empty Exclude variants from the hierarchy. - """ - excluded_var_dict = {} - - for a in hierarchy: - empty_variant = "" - empty_var_count = 0 - variant_list = list(hierarchy[a].keys()) - # empty_var_count and raise() prevents this for from causing breaking stuff: - - for b in variant_list: - if b.split("_")[1] == "0": - empty_variant = b - empty_var_count += 1 - if empty_var_count > 1: - raise Exception( - f"\n{bcolors.ERROR}Blend_My_NFTs Error:\n" - f"The Attribute collection '{a}' has more than one Empty variant.\n" - f"Attributes can only have a maximum of 1 Empty variant, please review the documentation here:\n{bcolors.RESET}" - f"https://github.com/torrinworx/Blend_My_NFTs#blender-file-organization-and-structure\n" - ) - - if len(empty_variant.split("_")) == 4 and empty_variant.split("_")[3] == "Exclude": - excluded_var_dict[a] = empty_variant - del hierarchy[a][empty_variant] - - return hierarchy, excluded_var_dict def generateNFT_DNA(collectionSize, enableRarity, enableLogic, logicFile, enableMaterials, materialsFile): """ Returns batchDataDictionary containing the number of NFT combinations, hierarchy, and the DNAList. """ - hierarchy, excluded_var_dict = strip_empty_exclude(get_hierarchy()) + hierarchy = get_hierarchy() # DNA random, Rarity and Logic methods: DataDictionary = {} - def createDNArandom(): + def createDNArandom(hierarchy): """Creates a single DNA randomly without Rarity or Logic.""" dnaStr = "" dnaStrList = [] @@ -195,20 +166,22 @@ def singleCompleteDNA(): singleDNA = "" # Comments for debugging random, rarity, logic, and materials. if not enableRarity: - singleDNA = createDNArandom() + singleDNA = createDNArandom(hierarchy) # print("============") # print(f"Original DNA: {singleDNA}") if enableRarity: singleDNA = Rarity.createDNArarity(hierarchy) # print(f"Rarity DNA: {singleDNA}") + if enableMaterials: + singleDNA = Material_Generator.apply_materials(hierarchy, singleDNA, materialsFile, enableRarity) + # print(f"Materials DNA: {singleDNA}") + if enableLogic: - singleDNA = Logic.logicafyDNAsingle(hierarchy, singleDNA, logicFile, enableRarity, excluded_var_dict) + singleDNA = Logic.logicafyDNAsingle(hierarchy, singleDNA, logicFile, enableRarity, enableMaterials) # print(f"Logic DNA: {singleDNA}") - if enableMaterials: - singleDNA = Material_Generator.apply_materials(hierarchy, singleDNA, materialsFile) - # print(f"Materials DNA: {singleDNA}") + # print("============\n") return singleDNA @@ -246,7 +219,6 @@ def create_DNAList(): # Data stored in batchDataDictionary: DataDictionary["numNFTsGenerated"] = len(DNAList) - DataDictionary["excludedVariants"] = excluded_var_dict DataDictionary["hierarchy"] = hierarchy DataDictionary["DNAList"] = DNAList diff --git a/main/Exporter.py b/main/Exporter.py index d1bb513..f77bb52 100644 --- a/main/Exporter.py +++ b/main/Exporter.py @@ -177,12 +177,14 @@ def match_materialDNA_to_Material(single_dna, material_dna, materialsFile): if hierarchy[attribute][var]['number'] == variant: variant = var - if material != '0': + if material != '0': # If material is not empty for variant_m in materialsFile: if variant == variant_m: - for mat in materialsFile[variant_m]["Material List"]: - if mat.split('_')[1] == material: - material = mat + # Getting Materials name from Materials index in the Materials List + materials_list = list(materialsFile[variant_m]["Material List"].keys()) + + material = materials_list[int(material) - 1] # Subtract 1 because '0' means empty mat + break full_dna_dict[variant] = material diff --git a/main/Logic.py b/main/Logic.py index 230c80d..eef2c0a 100644 --- a/main/Logic.py +++ b/main/Logic.py @@ -15,7 +15,7 @@ def reconstructDNA(deconstructedDNA): return ''.join(reconstructed_DNA.split('-', 1)) -def apply_rules_to_dna(hierarchy, deconstructed_DNA, if_dict, then_dict, enableRarity, excluded_var_dict): +def apply_rules_to_dna(hierarchy, deconstructed_DNA, if_dict, then_dict, enableRarity): # Check if Variants in if_dict are in deconstructed_DNA, if so return if_list_selected = True: if_list_selected = False @@ -221,7 +221,7 @@ def get_var_info(variant): return dict(items_returned) -def logicafyDNAsingle(hierarchy, singleDNA, logicFile, enableRarity, excluded_var_dict): +def logicafyDNAsingle(hierarchy, singleDNA, logicFile, enableRarity, enableMaterials): deconstructed_DNA = singleDNA.split("-") didReconstruct = True @@ -236,7 +236,6 @@ def logicafyDNAsingle(hierarchy, singleDNA, logicFile, enableRarity, excluded_va # Items from 'THEN' key for a given rule then_dict = create_dicts(hierarchy, logicFile[rule]["THEN"]) - # save_result(then_dict) violates_rule, if_bool, then_bool, full_att_bool = get_rule_break_type(hierarchy, deconstructed_DNA, if_dict, then_dict) if deconstructed_DNA[3] != "1": @@ -249,7 +248,7 @@ def logicafyDNAsingle(hierarchy, singleDNA, logicFile, enableRarity, excluded_va print(f"======={deconstructed_DNA} VIOLATES RULE======") deconstructed_DNA = apply_rules_to_dna( - hierarchy, deconstructed_DNA, if_dict, then_dict, enableRarity, excluded_var_dict + hierarchy, deconstructed_DNA, if_dict, then_dict, enableRarity ) newDNA = reconstructDNA(deconstructed_DNA) diff --git a/main/Material_Generator.py b/main/Material_Generator.py index cb02756..f921a07 100644 --- a/main/Material_Generator.py +++ b/main/Material_Generator.py @@ -9,34 +9,42 @@ import random -def select_material(materialList): +def select_material(materialList, enableRarity): """Selects a material from a passed material list. """ - - number_List_Of_i = [] + material_List_Of_i = [] # List of Material names instead of order numbers rarity_List_Of_i = [] - ifZeroBool = None - for material in materialList: + # Material Order Number comes from index in the Material List in materials.json for a given Variant. + # material_order_num = list(materialList.keys()).index(material) - material_order_num = material.split("_")[1] - number_List_Of_i.append(material_order_num) + material_List_Of_i.append(material) - material_rarity_percent = material.split("_")[1] + material_rarity_percent = materialList[material] rarity_List_Of_i.append(float(material_rarity_percent)) - for x in rarity_List_Of_i: - if x == 0: - ifZeroBool = True - break - elif x != 0: - ifZeroBool = False + print(f"MATERIAL_LIST_OF_I:{material_List_Of_i}") + print(f"RARITY_LIST_OF_I:{rarity_List_Of_i}") + + if enableRarity: + ifZeroBool = None + + for x in rarity_List_Of_i: + if x == 0: + ifZeroBool = True + break + elif x != 0: + ifZeroBool = False + + if ifZeroBool: + selected_material = random.choices(material_List_Of_i, k=1) + elif not ifZeroBool: + + selected_material = random.choices(material_List_Of_i, weights=rarity_List_Of_i, k=1) - if ifZeroBool: - selected_material = random.choices(number_List_Of_i, k=1) - elif not ifZeroBool: - selected_material = random.choices(number_List_Of_i, weights=rarity_List_Of_i, k=1) + else: + selected_material = random.choices(material_List_Of_i, k=1) - return selected_material[0] + return selected_material[0], materialList def get_variant_att_index(variant, hierarchy): variant_attribute = None @@ -69,7 +77,7 @@ def match_DNA_to_Variant(hierarchy, singleDNA): dnaDictionary.update({x: k}) return dnaDictionary -def apply_materials(hierarchy, singleDNA, materialsFile): +def apply_materials(hierarchy, singleDNA, materialsFile, enableRarity): """ DNA with applied material example: "1-1:1-1" : @@ -85,8 +93,9 @@ def apply_materials(hierarchy, singleDNA, materialsFile): complete = False for b in materialsFile: if singleDNADict[a] == b: - mat = select_material(materialsFile[b]['Material List']) - deconstructed_MaterialDNA[a] = mat + material_name, materialList, = select_material(materialsFile[b]['Material List'], enableRarity) + material_order_num = list(materialList.keys()).index(material_name) # Gets the Order Number of the Material + deconstructed_MaterialDNA[a] = str(material_order_num + 1) complete = True if not complete: deconstructed_MaterialDNA[a] = "0"