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": []
    }
}
```
pull/135/head
Torrin Leonard 2022-06-06 17:04:25 -04:00
rodzic 17cbf3a32f
commit 3cb2a69c81
5 zmienionych plików z 63 dodań i 67 usunięć

Wyświetl plik

@ -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 @@ class BMNFTS_PT_Other(bpy.types.Panel):
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)

Wyświetl plik

@ -123,47 +123,18 @@ def get_hierarchy():
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 generateNFT_DNA(collectionSize, enableRarity, enableLogic, logicFile, enable
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 generateNFT_DNA(collectionSize, enableRarity, enableLogic, logicFile, enable
# Data stored in batchDataDictionary:
DataDictionary["numNFTsGenerated"] = len(DNAList)
DataDictionary["excludedVariants"] = excluded_var_dict
DataDictionary["hierarchy"] = hierarchy
DataDictionary["DNAList"] = DNAList

Wyświetl plik

@ -177,12 +177,14 @@ def render_and_save_NFTs(input):
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

Wyświetl plik

@ -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 create_dicts(hierarchy, rule_list_items):
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)

Wyświetl plik

@ -9,34 +9,42 @@ import json
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 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)
if enableRarity:
ifZeroBool = None
return selected_material[0]
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)
else:
selected_material = random.choices(material_List_Of_i, k=1)
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" <Normal DNA>:<Selected Material for each Variant>
@ -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"