Committing Logic patch and Checks

pull/83/head
Torrin Leonard 2022-04-09 13:34:43 -04:00
rodzic bc5568b564
commit c8e8d62837
5 zmienionych plików z 176 dodań i 305 usunięć

Wyświetl plik

@ -157,9 +157,8 @@ def update_combinations(dummy1, dummy2):
global recommended_limit
global offset
combinations = (get_combinations.get_combinations_from_scene())
combinations = (get_combinations.get_combinations())
recommended_limit = int(round(combinations/2))
redraw_panel()
@ -176,7 +175,7 @@ class createData(bpy.types.Operator):
def execute(self, context):
nftName = bpy.context.scene.my_tool.nftName
maxNFTs = bpy.context.scene.my_tool.collectionSize
collectionSize = bpy.context.scene.my_tool.collectionSize
nftsPerBatch = bpy.context.scene.my_tool.nftsPerBatch
save_path = bpy.path.abspath(bpy.context.scene.my_tool.save_path)
logicFile = bpy.path.abspath(bpy.context.scene.my_tool.logicFile)
@ -186,8 +185,8 @@ class createData(bpy.types.Operator):
Blend_My_NFTs_Output, batch_json_save_path, nftBatch_save_path = make_directories(save_path)
DNA_Generator.send_To_Record_JSON(maxNFTs, nftsPerBatch, save_path, enableRarity, enableLogic, logicFile, Blend_My_NFTs_Output)
Batch_Sorter.makeBatches(nftName, maxNFTs, nftsPerBatch, save_path, batch_json_save_path)
DNA_Generator.send_To_Record_JSON(collectionSize, nftsPerBatch, save_path, enableRarity, enableLogic, logicFile, Blend_My_NFTs_Output)
Batch_Sorter.makeBatches(nftName, collectionSize, nftsPerBatch, save_path, batch_json_save_path)
self.report({'INFO'}, f"NFT Data created!")
@ -203,7 +202,7 @@ class exportNFTs(bpy.types.Operator):
nftName = bpy.context.scene.my_tool.nftName
save_path = bpy.path.abspath(bpy.context.scene.my_tool.save_path)
batchToGenerate = bpy.context.scene.my_tool.batchToGenerate
maxNFTs = bpy.context.scene.my_tool.collectionSize
collectionSize = bpy.context.scene.my_tool.collectionSize
Blend_My_NFTs_Output, batch_json_save_path, nftBatch_save_path = make_directories(save_path)
@ -222,7 +221,7 @@ class exportNFTs(bpy.types.Operator):
failed_dna = None
failed_dna_index = None
Exporter.render_and_save_NFTs(nftName, maxNFTs, batchToGenerate, batch_json_save_path, nftBatch_save_path, enableImages,
Exporter.render_and_save_NFTs(nftName, collectionSize, batchToGenerate, batch_json_save_path, nftBatch_save_path, enableImages,
imageFileFormat, enableAnimations, animationFileFormat, enableModelsBlender,
modelFileFormat, fail_state, failed_batch, failed_dna, failed_dna_index
)
@ -241,7 +240,7 @@ class resume_failed_batch(bpy.types.Operator):
nftName = bpy.context.scene.my_tool.nftName
save_path = bpy.path.abspath(bpy.context.scene.my_tool.save_path)
batchToGenerate = bpy.context.scene.my_tool.batchToGenerate
maxNFTs = bpy.context.scene.my_tool.collectionSize
collectionSize = bpy.context.scene.my_tool.collectionSize
Blend_My_NFTs_Output, batch_json_save_path, nftBatch_save_path = make_directories(save_path)
fail_state, failed_batch, failed_dna, failed_dna_index = Checks.check_FailedBatches(batch_json_save_path)
@ -257,7 +256,7 @@ class resume_failed_batch(bpy.types.Operator):
enableModelsBlender = batch["Generation Save"][-1]["Render_Settings"]["enableModelsBlender"]
modelFileFormat = batch["Generation Save"][-1]["Render_Settings"]["modelFileFormat"]
Exporter.render_and_save_NFTs(nftName, maxNFTs, failed_batch, batch_json_save_path, nftBatch_save_path, enableImages,
Exporter.render_and_save_NFTs(nftName, collectionSize, failed_batch, batch_json_save_path, nftBatch_save_path, enableImages,
imageFileFormat, enableAnimations, animationFileFormat, enableModelsBlender,
modelFileFormat, fail_state, failed_batch, failed_dna, failed_dna_index
)
@ -380,8 +379,12 @@ class BMNFTS_PT_GenerateNFTs(bpy.types.Panel):
row.prop(mytool, "batchToGenerate")
save_path = bpy.path.abspath(bpy.context.scene.my_tool.save_path)
Blend_My_NFTs_Output, batch_json_save_path, nftBatch_save_path = make_directories(save_path)
Blend_My_NFTs_Output = os.path.join(save_path, "Blend_My_NFTs Output", "NFT_Data")
batch_json_save_path = os.path.join(Blend_My_NFTs_Output, "Batch_Data")
nftBatch_save_path = os.path.join(save_path, "Blend_My_NFTs Output", "Generated NFT Batches")
fail_state, failed_batch, failed_dna, failed_dna_index = Checks.check_FailedBatches(batch_json_save_path)
if fail_state:
row = layout.row()
self.layout.operator("exporter.nfts", icon='RENDER_RESULT', text="Generate NFTs")

Wyświetl plik

@ -11,6 +11,7 @@ import os
import json
from collections import Counter, defaultdict
from . import DNA_Generator, get_combinations
class bcolors:
"""
@ -22,6 +23,7 @@ class bcolors:
ERROR = '\033[91m' # RED
RESET = '\033[0m' # RESET COLOR
# Checks:
def check_Scene():
"""
@ -29,11 +31,36 @@ def check_Scene():
violations.
"""
script_ignore_exists = None # True if Script_Ignore collection exists in Blender scene
attribute_naming_conventions = None # True if all attributes in Blender scene follow BMNFTs naming conventions
variant_naming_conventions = None # True if all variants in Blender scene follow BMNFTs naming conventions
object_placing_conventions = None # True if all objects are within either Script_Ignore or a variant collection
hierarchy = DNA_Generator.get_hierarchy()
# script_ignore_exists:
try:
scriptIgnoreCollection = bpy.data.collections["Script_Ignore"]
except KeyError:
raise TypeError(
f"\n{bcolors.ERROR}Blend_My_NFTs Error:\n"
f"collection to your Blender scene and ensure the name is exactly 'Script_Ignore'. For more information, "
f"see:"
f"\nhttps://github.com/torrinworx/Blend_My_NFTs#blender-file-organization-and-structure\n{bcolors.RESET}"
)
else:
script_ignore_exists = True
collections = bpy.context.scene.collection
print(collections)
# attribute_naming_conventions
def check_Rarity(hierarchy, DNAList, save_path):
"""Checks rarity percentage of each Variant, then sends it to RarityData.json in NFT_Data folder."""
numNFTsGenerated = len(DNAList)
attributeNames = []
numDict = defaultdict(list)
hierarchy.keys()
@ -74,9 +101,11 @@ def check_Rarity(hierarchy, DNAList, save_path):
completeData[i] = x
print(completeData)
print(bcolors.OK + "Rarity Checker is active. These are the percentages for each variant per attribute you set in your .blend file:" + bcolors.RESET)
print(
f"\n{bcolors.OK}\n"
f"Rarity Checker is active. These are the percentages for each variant per attribute you set in your .blend file:"
f"\n{bcolors.RESET}"
)
for i in completeData:
print(i + ":")
@ -105,42 +134,27 @@ def check_Duplicates(DNAList):
print(f"NFTRecord.json contains {duplicates} duplicate NFT DNA.")
def check_FailedBatches(batch_json_save_path):
batch_folders = os.listdir(batch_json_save_path)
fail_state = False
failed_batch = None
failed_dna = None
failed_dna_index = None
for i in batch_folders:
batch = json.load(open(os.path.join(batch_json_save_path, i)))
NFTs_in_Batch = batch["NFTs_in_Batch"]
if "Generation Save" in batch:
dna_generated = batch["Generation Save"][-1]["DNA Generated"]
if dna_generated < NFTs_in_Batch:
fail_state = True
failed_batch = int(i.removeprefix("Batch").removesuffix(".json"))
failed_dna = dna_generated
if os.path.isdir(batch_json_save_path):
batch_folders = os.listdir(batch_json_save_path)
for i in batch_folders:
batch = json.load(open(os.path.join(batch_json_save_path, i)))
NFTs_in_Batch = batch["NFTs_in_Batch"]
if "Generation Save" in batch:
dna_generated = batch["Generation Save"][-1]["DNA Generated"]
if dna_generated < NFTs_in_Batch:
fail_state = True
failed_batch = int(i.removeprefix("Batch").removesuffix(".json"))
failed_dna = dna_generated
return fail_state, failed_batch, failed_dna, failed_dna_index
# Raise Errors:
def raise_Error_ScriptIgnore():
"""Checks if Script_Ignore collection exists, if not raises error."""
try:
scriptIgnore = bpy.data.collections["Script_Ignore"]
return scriptIgnore
except KeyError:
raise KeyError(
f"\n{bcolors.ERROR}Blend_My_NFTs Error:\n"
f"Script_Ignore collection not found in Blender scene. Please add the Script_Ignore "
f"collection to Blender scene or ensure the spelling is exactly 'Script_Ignore'. For more information, "
f"see:\n{bcolors.RESET}"
f"https://github.com/torrinworx/Blend_My_NFTs#blender-file-organization-and-structure\n{bcolors.RESET}"
)
def raise_Error_numBatches(maxNFTs, nftsPerBatch):
"""Checks if number of Batches is less than maxNFTs, if not raises error."""
@ -148,15 +162,18 @@ def raise_Error_numBatches(maxNFTs, nftsPerBatch):
numBatches = maxNFTs / nftsPerBatch
return numBatches
except ZeroDivisionError:
print(f"{bcolors.ERROR} ERROR:\nnftsPerBatch in config.py needs to be a positive integer. {bcolors.RESET}")
raise ZeroDivisionError(
f"\n{bcolors.ERROR}Blend_My_NFTs Error:\n"
f"The number of combinations is less than the number of \n{bcolors.RESET}"
f"The number of NFTs per Batch must be greater than ZERO."
f"Please review your Blender scene and ensure it follows "
f"the naming conventions and scene structure. For more information, "
f"see:\n{bcolors.RESET}"
f"https://github.com/torrinworx/Blend_My_NFTs#blender-file-organization-and-structure\n{bcolors.RESET}"
)
def raise_Error_ZeroCombinations(combinations):
def raise_Error_ZeroCombinations():
"""Checks if combinations is greater than 0, if so, raises error."""
if combinations == 0:
if get_combinations.get_combinations() == 0:
raise ValueError(
f"\n{bcolors.ERROR}Blend_My_NFTs Error:\n"
f"The number of all possible combinations is ZERO. Please review your Blender scene and ensure it follows "
@ -177,13 +194,29 @@ def raise_Error_numBatchesGreaterThan(numBatches):
# Raise Warnings:
def raise_Warning_maxNFTs(nftsPerBatch, maxNFTs):
def raise_Warning_maxNFTs(nftsPerBatch, collectionSize):
"""
Prints warning if nftsPerBatch is greater than collectionSize.
"""
"""
if nftsPerBatch > maxNFTs:
raise (
if nftsPerBatch > collectionSize:
raise ValueError(
f"\n{bcolors.WARNING}Blend_My_NFTs Warning:\n"
f"The number of NFTs Per Batch you set is smaller than the NFT Collection Size you set.\n{bcolors.RESET}"
)
def raise_Warning_collectionSize(DNAList, collectionSize):
"""
Prints warning if BMNFTs cannot generate requested number of NFTs from a given collectionSize.
"""
if len(DNAList) < collectionSize:
print(f"\n{bcolors.WARNING} \nWARNING: \n"
f"Blend_My_NFTs cannot generate {collectionSize} NFTs."
f" Only {len(DNAList)} NFT DNA were generated."
f"\nThis might be for a number of reasons:"
f"\n a) Rarity is preventing combinations from being generated (See https://github.com/torrinworx/Blend_My_NFTs#notes-on-rarity-and-weighted-variants).\n"
f"\n b) Logic is preventing combinations from being generated (See https://github.com/torrinworx/Blend_My_NFTs#logic).\n"
f"\n c) The number of possible combinations of your NFT collection is too low. Add more Variants or Attributes to increase the recommended collection size.\n"
f"\n{bcolors.RESET}")

Wyświetl plik

@ -23,15 +23,14 @@ class bcolors:
RESET = '\033[0m' # RESET COLOR
def returnData(maxNFTs, nftsPerBatch):
def get_hierarchy():
"""
Generates important variables, dictionaries, and lists needed to be stored to catalog the NFTs.
:return: listAllCollections, attributeCollections, attributeCollections1, hierarchy, variantMetaData, possibleCombinations
Returns the hierarchy of a given Blender scene.
"""
coll = bpy.context.scene.collection
scriptIgnore = Checks.raise_Error_ScriptIgnore()
scriptIgnoreCollection = bpy.data.collections["Script_Ignore"]
listAllCollInScene = []
listAllCollections = []
@ -47,7 +46,7 @@ def returnData(maxNFTs, nftsPerBatch):
for i in listAllCollInScene:
listAllCollections.append(i.name)
listAllCollections.remove(scriptIgnore.name)
listAllCollections.remove(scriptIgnoreCollection.name)
if "Scene Collection" in listAllCollections:
listAllCollections.remove("Scene Collection")
@ -55,20 +54,19 @@ def returnData(maxNFTs, nftsPerBatch):
if "Master Collection" in listAllCollections:
listAllCollections.remove("Master Collection")
def allScriptIgnore(scriptIgnore):
"""
Removes all collections, sub collections in Script_Ignore collection from listAllCollections.
"""
for coll in list(scriptIgnore.children):
def allScriptIgnore(scriptIgnoreCollection):
# Removes all collections, sub collections in Script_Ignore collection from listAllCollections.
for coll in list(scriptIgnoreCollection.children):
listAllCollections.remove(coll.name)
listColl = list(coll.children)
if len(listColl) > 0:
allScriptIgnore(coll)
allScriptIgnore(scriptIgnore)
allScriptIgnore(scriptIgnoreCollection)
listAllCollections.sort()
exclude = ["_", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"]
exclude = ["_"] # Excluding characters that identify a Variant
attributeCollections = copy.deepcopy(listAllCollections)
def filter_num():
@ -91,8 +89,6 @@ def returnData(maxNFTs, nftsPerBatch):
Creates a dictionary of each attribute
"""
allAttDataList = {}
count = 0
previousAttribute = ""
for i in attributeVariants:
def getName(i):
@ -123,67 +119,28 @@ def returnData(maxNFTs, nftsPerBatch):
variantMetaData = attributeData(attributeVariants)
def getHierarchy():
"""
Constructs the hierarchy dictionary from attributeCollections1 and variantMetaData.
"""
hierarchy = {}
for i in attributeCollections1:
colParLong = list(bpy.data.collections[str(i)].children)
colParShort = {}
for x in colParLong:
colParShort[x.name] = None
hierarchy[i] = colParShort
hierarchy = {}
for i in attributeCollections1:
colParLong = list(bpy.data.collections[str(i)].children)
colParShort = {}
for x in colParLong:
colParShort[x.name] = None
hierarchy[i] = colParShort
for a in hierarchy:
for b in hierarchy[a]:
for x in variantMetaData:
if str(x) == str(b):
(hierarchy[a])[b] = variantMetaData[x]
for a in hierarchy:
for b in hierarchy[a]:
for x in variantMetaData:
if str(x) == str(b):
(hierarchy[a])[b] = variantMetaData[x]
return hierarchy
return hierarchy
hierarchy = getHierarchy()
def numOfCombinations(hierarchy):
"""
Returns "combinations" the number of all possible NFT combinations.
"""
hierarchyByNum = []
for i in hierarchy:
# Ignore Collections with nothing in them
if len(hierarchy[i]) != 0:
hierarchyByNum.append(len(hierarchy[i]))
else:
print(f"The following collection has been identified as empty: {i}")
combinations = 1
for i in hierarchyByNum:
combinations = combinations*i
# Checks:
numBatches = Checks.raise_Error_numBatches(maxNFTs, nftsPerBatch)
Checks.raise_Error_ZeroCombinations(combinations)
Checks.raise_Error_numBatchesGreaterThan(numBatches)
Checks.raise_Error_numBatchesGreaterThan(numBatches)
return combinations
possibleCombinations = numOfCombinations(hierarchy)
return listAllCollections, attributeCollections, attributeCollections1, hierarchy, possibleCombinations
def generateNFT_DNA(maxNFTs, nftsPerBatch, logicFile, enableRarity, enableLogic):
def generateNFT_DNA(collectionSize, logicFile, enableRarity, enableLogic):
"""
Returns batchDataDictionary containing the number of NFT combinations, hierarchy, and the DNAList.
"""
listAllCollections, attributeCollections, attributeCollections1, hierarchy, possibleCombinations = returnData(maxNFTs, nftsPerBatch)
hierarchy = get_hierarchy()
# DNA random, Rarity and Logic methods:
DataDictionary = {}
@ -232,10 +189,10 @@ def generateNFT_DNA(maxNFTs, nftsPerBatch, logicFile, enableRarity, enableLogic)
"""Creates DNAList. Loops through createDNARandom() and applies Rarity, and Logic while checking if all DNA are unique"""
DNASetReturn = set()
for i in range(maxNFTs):
for i in range(collectionSize):
dnaPushToList = partial(singleCompleteDNA)
DNASetReturn |= {''.join([dnaPushToList()]) for _ in range(maxNFTs - len(DNASetReturn))}
DNASetReturn |= {''.join([dnaPushToList()]) for _ in range(collectionSize - len(DNASetReturn))}
DNAListReturn = list(DNASetReturn)
@ -244,21 +201,17 @@ def generateNFT_DNA(maxNFTs, nftsPerBatch, logicFile, enableRarity, enableLogic)
DNAList = create_DNAList()
# Messages:
if len(DNAList) < maxNFTs:
print(f"{bcolors.ERROR} \nWARNING: \n"
f"You are seeing this warning because the program cannot generate {maxNFTs} NFTs with rarity enabled. "
f"Only {len(DNAList)} NFT DNA were generated."
f"Either A) Lower the number of NFTs you wish to create, or B) Increase the maximum number of possible NFTs by"
f" creating more variants and attributes in your .blend file.{bcolors.RESET}")
Checks.raise_Warning_collectionSize(DNAList, collectionSize)
# Data stored in batchDataDictionary:
DataDictionary["numNFTsGenerated"] = len(DNAList)
DataDictionary["hierarchy"] = hierarchy
DataDictionary["DNAList"] = DNAList
return DataDictionary, possibleCombinations
return DataDictionary
def send_To_Record_JSON(maxNFTs, nftsPerBatch, save_path, enableRarity, enableLogic, logicFile, Blend_My_NFTs_Output):
def send_To_Record_JSON(collectionSize, nftsPerBatch, save_path, enableRarity, enableLogic, logicFile, Blend_My_NFTs_Output):
"""
Creates NFTRecord.json file and sends "batchDataDictionary" to it. NFTRecord.json is a permanent record of all DNA
you've generated with all attribute variants. If you add new variants or attributes to your .blend file, other scripts
@ -266,10 +219,13 @@ def send_To_Record_JSON(maxNFTs, nftsPerBatch, save_path, enableRarity, enableLo
repeate DNA.
"""
# Checking Scene is compatible with BMNFTs:
Checks.check_Scene()
# Messages:
print(
f"\n========================================\n"
f"Creating NFT Data. Generating {maxNFTs} NFT DNA.\n"
f"Creating NFT Data. Generating {collectionSize} NFT DNA.\n"
)
if not enableRarity and not enableLogic:
@ -282,17 +238,21 @@ def send_To_Record_JSON(maxNFTs, nftsPerBatch, save_path, enableRarity, enableLo
print(f"{bcolors.OK}Logic is ON. Rules listed in {logicFile} will be taken into account.\n{bcolors.RESET}")
time_start = time.time()
def create_nft_data():
try:
DataDictionary, possibleCombinations = generateNFT_DNA(maxNFTs, nftsPerBatch, logicFile, enableRarity, enableLogic)
DataDictionary = generateNFT_DNA(collectionSize, logicFile, enableRarity, enableLogic)
NFTRecord_save_path = os.path.join(Blend_My_NFTs_Output, "NFTRecord.json")
# Checks:
Checks.raise_Warning_maxNFTs(nftsPerBatch, maxNFTs)
Checks.check_Rarity(DataDictionary["hierarchy"], DataDictionary["DNAList"], os.path.join(save_path, "Blend_My_NFTs Output/NFT_Data"))
Checks.raise_Warning_maxNFTs(nftsPerBatch, collectionSize)
Checks.check_Duplicates(DataDictionary["DNAList"])
Checks.raise_Error_ZeroCombinations()
if enableRarity:
Checks.check_Rarity(DataDictionary["hierarchy"], DataDictionary["DNAList"], os.path.join(save_path, "Blend_My_NFTs Output/NFT_Data"))
except FileNotFoundError:
raise FileNotFoundError(
f"\n{bcolors.ERROR}Blend_My_NFTs Error:\n"
@ -301,8 +261,6 @@ def send_To_Record_JSON(maxNFTs, nftsPerBatch, save_path, enableRarity, enableLo
f"see:\n{bcolors.RESET}"
f"https://github.com/torrinworx/Blend_My_NFTs#blender-file-organization-and-structure\n"
)
else:
print("Something unexpected happened. Please check Blender System Console Traceback error for more information.")
finally:
loading.stop()
@ -324,8 +282,6 @@ def send_To_Record_JSON(maxNFTs, nftsPerBatch, save_path, enableRarity, enableLo
f"https://github.com/torrinworx/Blend_My_NFTs#blender-file-organization-and-structure\n"
)
# Loading Animation:
loading = Loader(f'Creating NFT DNA...', '').start()
create_nft_data()

Wyświetl plik

@ -99,10 +99,21 @@ def reconstructDNA(deconstructedDNA):
reconstructed_DNA += num
return (''.join(reconstructed_DNA.split('-', 1)))
def strip_empty_variant(num_list):
for i in num_list:
var_list = num_list[i]
var_list.remove("0")
num_list[i] = var_list
return num_list
# Rule Checks:
def never_with_Rule_Check(hierarchy, deconstructed_DNA, num_List1, num_List2):
"""Returns True if singleDNA violates Never with Rule stated in Logic.json."""
violates_rule = None
num_List1 = strip_empty_variant(num_List1)
num_List2 = strip_empty_variant(num_List2)
for a in num_List1:
for b in num_List2:
if str(deconstructed_DNA[getAttIndex(hierarchy, a)]) in num_List1[a] and \
@ -116,6 +127,7 @@ def never_with_Rule_Check(hierarchy, deconstructed_DNA, num_List1, num_List2):
def only_with_Rule_Check(hierarchy, deconstructed_DNA, num_List1, num_List2):
"""Returns True if singleDNA violates Only with Rule stated in Logic.json."""
violates_rule = None
for a in num_List1:
for b in num_List2:
if str(deconstructed_DNA[getAttIndex(hierarchy, a)]) in num_List1[a] and \
@ -130,6 +142,7 @@ def only_with_Rule_Check(hierarchy, deconstructed_DNA, num_List1, num_List2):
def always_with_Rule_Check(hierarchy, deconstructed_DNA, num_List1, num_List2):
"""Returns True if singleDNA violates Always with Rule stated in Logic.json."""
violates_rule = None
for a in num_List2:
if str(deconstructed_DNA[getAttIndex(hierarchy, a)]) not in num_List2[a]:
violates_rule = True
@ -147,7 +160,6 @@ def logicafyDNAsingle(hierarchy, singleDNA, logicFile):
didReconstruct = True
originalDNA = str(singleDNA)
resultDNA = str(singleDNA)
while didReconstruct:
didReconstruct = False
@ -168,6 +180,12 @@ def logicafyDNAsingle(hierarchy, singleDNA, logicFile):
if not rand_bool:
deconstructed_DNA = rar_selectVar(hierarchy, items_List1, deconstructed_DNA)
newDNA = reconstructDNA(deconstructed_DNA)
if newDNA != originalDNA:
originalDNA = str(newDNA)
didReconstruct = True
break
if logicFile[rule]["Rule-Type"] == "Only with":
if only_with_Rule_Check(hierarchy, deconstructed_DNA, num_List1, num_List2):
for b in num_List1:
@ -177,15 +195,20 @@ def logicafyDNAsingle(hierarchy, singleDNA, logicFile):
if "0" not in num_List1[b]: # Not complete attribute, select from other variants with rarity:
deconstructed_DNA = rar_selectVar(hierarchy, items_List1, deconstructed_DNA)
newDNA = reconstructDNA(deconstructed_DNA)
if newDNA != originalDNA:
originalDNA = str(newDNA)
didReconstruct = True
break
if logicFile[rule]["Rule-Type"] == "Always with":
if always_with_Rule_Check(hierarchy, deconstructed_DNA, num_List1, num_List2):
deconstructed_DNA = rar_selectVar(hierarchy, items_List1, deconstructed_DNA)
newDNA = reconstructDNA(deconstructed_DNA)
if newDNA != originalDNA:
originalDNA = str(newDNA)
didReconstruct = True
resultDNA = str(newDNA)
break
newDNA = reconstructDNA(deconstructed_DNA)
if newDNA != originalDNA:
originalDNA = str(newDNA)
didReconstruct = True
break
return resultDNA
return str(reconstructDNA(deconstructed_DNA))

Wyświetl plik

@ -1,6 +1,6 @@
import bpy
import re
import copy
from . import DNA_Generator
class bcolors:
"""
@ -11,169 +11,25 @@ class bcolors:
ERROR = '\033[91m' # RED
RESET = '\033[0m' # RESET COLOR
def stripColorFromName(name):
return "_".join(name.split("_")[:-1])
def get_combinations_from_scene():
def get_combinations():
"""
Generates important variables, dictionaries, and lists needed to be stored to catalog the NFTs.
:return: listAllCollections, attributeCollections, attributeCollections1, hierarchy, variantMetaData, possibleCombinations
Returns "combinations", the number of all possible NFT DNA for a given Blender scene formatted to BMNFTs conventions
combinations.
"""
coll = bpy.context.scene.collection
hierarchy = DNA_Generator.get_hierarchy()
hierarchyByNum = []
try:
scriptIgnore = bpy.data.collections["Script_Ignore"]
except:
print(f"{bcolors.ERROR} ERROR:\nScript_Ignore collection is not in .blend file scene. Please add the Script_Ignore collection to your "
f".blend file scene. For more information, read the README.md file.\n {bcolors.RESET}")
for i in hierarchy:
# Ignore Collections with nothing in them
if len(hierarchy[i]) != 0:
hierarchyByNum.append(len(hierarchy[i]))
else:
print(f"The following collection has been identified as empty: {i}")
listAllCollInScene = []
listAllCollections = []
combinations = 1
for i in hierarchyByNum:
combinations = combinations*i
def traverse_tree(t):
yield t
for child in t.children:
yield from traverse_tree(child)
for c in traverse_tree(coll):
listAllCollInScene.append(c)
for i in listAllCollInScene:
listAllCollections.append(i.name)
listAllCollections.remove(scriptIgnore.name)
if "Scene Collection" in listAllCollections:
listAllCollections.remove("Scene Collection")
if "Master Collection" in listAllCollections:
listAllCollections.remove("Master Collection")
def allScriptIgnore(collection):
'''
Removes all collections, sub collections in Script_Ignore collection from listAllCollections.
'''
for coll in list(collection.children):
listAllCollections.remove(coll.name)
listColl = list(coll.children)
if len(listColl) > 0:
allScriptIgnore(coll)
allScriptIgnore(scriptIgnore)
listAllCollections.sort()
exclude = ["_", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"]
attributeCollections = copy.deepcopy(listAllCollections)
def filter_num():
"""
This function removes items from 'attributeCollections' if they include values from the 'exclude' variable.
It removes child collections from the parent collections in from the "listAllCollections" list.
"""
for x in attributeCollections:
if any(a in x for a in exclude):
attributeCollections.remove(x)
for i in range(len(listAllCollections)):
filter_num()
attributeVariants = [x for x in listAllCollections if x not in attributeCollections]
attributeCollections1 = copy.deepcopy(attributeCollections)
def attributeData(attributeVariants):
"""
Creates a dictionary of each attribute
"""
allAttDataList = {}
count = 0
previousAttribute = ""
for i in attributeVariants:
def getName(i):
"""
Returns the name of "i" attribute variant
"""
name = i.split("_")[0]
return name
def getOrder_rarity(i):
"""
Returns the "order", "rarity" and "color" (if enabled) of i attribute variant in a list
"""
x = re.sub(r'[a-zA-Z]', "", i)
a = x.split("_")
del a[0]
return list(a)
name = getName(i)
orderRarity = getOrder_rarity(i)
if len(orderRarity) == 0:
print(f"{bcolors.ERROR} \nERROR: {bcolors.RESET}")
print(f"The collection {i} doesn't follow the naming conventions of attributes. Please move this \n"
"colleciton to Script_Ignore or review proper collection format in README.md")
return
elif len(orderRarity) > 0:
number = orderRarity[0]
rarity = orderRarity[1]
eachObject = {"name": name, "number": number, "rarity": rarity}
allAttDataList[i] = eachObject
return allAttDataList
variantMetaData = attributeData(attributeVariants)
def getHierarchy():
"""
Constructs the hierarchy dictionary from attributeCollections1 and variantMetaData.
"""
hierarchy = {}
for i in attributeCollections1:
colParLong = list(bpy.data.collections[str(i)].children)
colParShort = {}
for x in colParLong:
colParShort[x.name] = None
hierarchy[i] = colParShort
for a in hierarchy:
for b in hierarchy[a]:
for x in variantMetaData:
if str(x) == str(b):
(hierarchy[a])[b] = variantMetaData[x]
return hierarchy
hierarchy = getHierarchy()
def numOfCombinations(hierarchy):
"""
Returns "combinations" the number of all possible NFT combinations.
"""
hierarchyByNum = []
for i in hierarchy:
# Ignore Collections with nothing in them
if len(hierarchy[i]) != 0:
hierarchyByNum.append(len(hierarchy[i]))
else:
print(f"The following collection has been identified as empty: {i}")
combinations = 1
for i in hierarchyByNum:
combinations = combinations*i
if combinations == 0:
print(bcolors.ERROR + "\nERROR:" + bcolors.RESET)
print("The number of all possible combinations is equal to 0. Please review your collection hierarchy"
"and ensure it is formatted correctly. Please review README.md for more information. \nHere is the "
"hierarchy of all collections the DNA_Generator gathered from your .blend file, excluding those in "
f"Script_Ignore: {hierarchy}")
return combinations
possibleCombinations = numOfCombinations(hierarchy)
return possibleCombinations
return combinations