Added Resume Failed Batch feature

Don't get me started.
pull/78/head
Torrin Leonard 2022-03-25 23:47:54 -04:00
rodzic f90cb38e2b
commit d5d4c37456
4 zmienionych plików z 169 dodań i 41 usunięć

Wyświetl plik

@ -14,11 +14,9 @@ import bpy
from bpy.app.handlers import persistent
import os
import json
import importlib
# Import files from main directory:
importList = ['DNA_Generator', 'Batch_Sorter', 'Exporter', 'Batch_Refactorer', 'get_combinations', 'UIList']
if bpy in locals():
importlib.reload(DNA_Generator)
@ -26,13 +24,16 @@ if bpy in locals():
importlib.reload(Exporter)
importlib.reload(Refactorer)
importlib.reload(get_combinations)
importlib.reload(Checks)
else:
from .main import \
DNA_Generator, \
Batch_Sorter, \
Exporter, \
Refactorer, \
get_combinations
get_combinations, \
Checks
# User input Property Group:
class BMNFTS_PGT_MyProperties(bpy.types.PropertyGroup):
@ -164,6 +165,7 @@ def update_combinations(dummy1, dummy2):
bpy.app.handlers.depsgraph_update_post.append(update_combinations)
# Main Operators:
class createData(bpy.types.Operator):
bl_idname = 'create.data'
@ -214,16 +216,56 @@ class exportNFTs(bpy.types.Operator):
enableModelsBlender = bpy.context.scene.my_tool.modelBool
modelFileFormat = bpy.context.scene.my_tool.modelEnum
# fail state variables, set to no fail due to resume_failed_batch() Operator in BMNFTS_PT_GenerateNFTs Panel
fail_state = False
failed_batch = None
failed_dna = None
failed_dna_index = None
Exporter.render_and_save_NFTs(nftName, maxNFTs, batchToGenerate, batch_json_save_path, nftBatch_save_path, enableImages,
imageFileFormat, enableAnimations, animationFileFormat, enableModelsBlender,
modelFileFormat
modelFileFormat, fail_state, failed_batch, failed_dna, failed_dna_index
)
self.report({'INFO'}, f"All NFTs generated for batch {batchToGenerate}!")
return {"FINISHED"}
class resume_failed_batch(bpy.types.Operator):
bl_idname = 'exporter.resume_nfts'
bl_label = 'Resume Failed Batch'
bl_description = 'Failed Batch detected. Generate NFTs where the previous batch failed?'
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
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
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)
file_name = os.path.join(batch_json_save_path, "Batch{}.json".format(batchToGenerate))
batch = json.load(open(file_name))
nftBatch_save_path = batch["Generation Save"][-1]["Render_Settings"]["nftBatch_save_path"]
enableImages = batch["Generation Save"][-1]["Render_Settings"]["enableImages"]
imageFileFormat = batch["Generation Save"][-1]["Render_Settings"]["imageFileFormat"]
enableAnimations = batch["Generation Save"][-1]["Render_Settings"]["enableAnimations"]
animationFileFormat = batch["Generation Save"][-1]["Render_Settings"]["animationFileFormat"]
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,
imageFileFormat, enableAnimations, animationFileFormat, enableModelsBlender,
modelFileFormat, fail_state, failed_batch, failed_dna, failed_dna_index
)
self.report({'INFO'}, f"Resuming Failed Batch Generation!")
return {"FINISHED"}
class refactor_Batches(bpy.types.Operator):
"""Refactor your collection? This action cannot be undone."""
bl_idname = 'refactor.batches'
@ -337,9 +379,20 @@ class BMNFTS_PT_GenerateNFTs(bpy.types.Panel):
row = layout.row()
row.prop(mytool, "batchToGenerate")
row = layout.row()
self.layout.operator("exporter.nfts", icon='RENDER_RESULT', text="Generate NFTs")
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)
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")
row = layout.row()
row.alert = True
row.operator("exporter.resume_nfts", icon='ERROR', text="Resume Failed Batch")
if not fail_state:
row = layout.row()
self.layout.operator("exporter.nfts", icon='RENDER_RESULT', text="Generate NFTs")
# Refactor Batches & create MetaData Panel:
class BMNFTS_PT_Refactor(bpy.types.Panel):
bl_label = "Refactor Batches & create MetaData"
@ -426,21 +479,6 @@ class BMNFTS_PT_Documentation(bpy.types.Panel):
# scene = context.scene
# mytool = scene.my_tool
#
# # API Panel:
# class BMNFTS_PT_API_Panel(bpy.types.Panel):
# bl_label = "API"
# bl_idname = "BMNFTS_PT_API_Panel"
# bl_space_type = 'VIEW_3D'
# bl_region_type = 'UI'
# bl_category = 'Blend_My_NFTs'
#
# def draw(self, context):
# layout = self.layout
# scene = context.scene
# mytool = scene.my_tool
#
# row = layout.row()
# row.prop(mytool, "apiKey")
def redraw_panel():
try:
@ -460,10 +498,10 @@ classes = (
# Other panels:
# BMNFTS_PT_MATERIALS_Panel,
# BMNFTS_PT_API_Panel,
createData,
exportNFTs,
resume_failed_batch,
refactor_Batches,
)

Wyświetl plik

@ -42,7 +42,9 @@ def makeBatches(nftName, maxNFTs, nftsPerBatch, save_path, batch_json_save_path)
j = 0
while (j < nftsPerBatch) and (DNAList):
oneDNA = random.choice(DNAList)
BatchDNAList.append(oneDNA)
BatchDNAList.append({
oneDNA: {"Complete": False}
})
DNAList.remove(oneDNA)
j += 1
@ -57,7 +59,7 @@ def makeBatches(nftName, maxNFTs, nftsPerBatch, save_path, batch_json_save_path)
i += 1
if len(DNAList) > 0:
if len(DNAList) > 0: # Add to Checks.py
print(f"One batch could not be filled completely and will contain {len(DNAList)} NFTs.")
incompleteBatch = {"NFTs_in_Batch": int(len(DNAList)), "hierarchy": hierarchy, "BatchDNAList": DNAList}

Wyświetl plik

@ -6,7 +6,6 @@
# This file is provided for transparency. The accuracy of the rarity values you set in your .blend file as outlined in
# the README.md file are dependent on the maxNFTs, and the maximum number of combinations of your NFT collection.
import bpy
import os
import json
@ -105,6 +104,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
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."""

Wyświetl plik

@ -6,19 +6,74 @@ import bpy
import os
import time
import json
import datetime
from .loading_animation import Loader
class bcolors:
'''
The colour of console messages.
'''
OK = '\033[92m' # GREEN
WARNING = '\033[93m' # YELLOW
ERROR = '\033[91m' # RED
RESET = '\033[0m' # RESET COLOR
"""
The colour of console messages.
"""
OK = '\033[92m' # GREEN
WARNING = '\033[93m' # YELLOW
ERROR = '\033[91m' # RED
RESET = '\033[0m' # RESET COLOR
# Save info
def save_batch(batch, file_name):
saved_batch = json.dumps(batch, indent=1, ensure_ascii=True)
with open(os.path.join(file_name), 'w') as outfile:
outfile.write(saved_batch + '\n')
def save_generation_state(batchToGenerate, batch_json_save_path, nftBatch_save_path, enableImages, imageFileFormat, enableAnimations,
animationFileFormat, enableModelsBlender, modelFileFormat):
"""Saves date and time of generation start, and generation types; Images, Animations, 3D Models, and the file types for each."""
file_name = os.path.join(batch_json_save_path, "Batch{}.json".format(batchToGenerate))
batch = json.load(open(file_name))
CURRENT_TIME = datetime.datetime.now().strftime("%H:%M:%S")
CURRENT_DATE = datetime.datetime.now().strftime("%d/%m/%Y")
LOCAL_TIMEZONE = str(datetime.datetime.now(datetime.timezone.utc))
if "Generation Save" in batch:
batch_save_number = int(batch[f"Generation Save"].index(batch[f"Generation Save"][-1]))
else:
batch_save_number = 0
batch["Generation Save"] = list()
batch["Generation Save"].append({
"Batch Save Number": batch_save_number + 1,
"DNA Generated": None,
"Generation Start Date and Time": [CURRENT_TIME, CURRENT_DATE, LOCAL_TIMEZONE],
"Render_Settings": {
"nftBatch_save_path": nftBatch_save_path,
"enableImages": enableImages,
"imageFileFormat": imageFileFormat,
"enableAnimations": enableAnimations,
"animationFileFormat": animationFileFormat,
"enableModelsBlender": enableModelsBlender,
"modelFileFormat": modelFileFormat,
},
})
save_batch(batch, file_name)
def save_completed(single_dna, a, x, batch_json_save_path, batchToGenerate):
"""Saves progress of rendering to batch.json file."""
file_name = os.path.join(batch_json_save_path, "Batch{}.json".format(batchToGenerate))
batch = json.load(open(file_name))
index = batch["BatchDNAList"].index(a)
batch["BatchDNAList"][index][single_dna]["Complete"] = True
batch["Generation Save"][-1]["DNA Generated"] = x
save_batch(batch, file_name)
# Exporter functions:
def getBatchData(batchToGenerate, batch_json_save_path):
"""
Retrieves a given batches data determined by renderBatch in config.py
@ -26,7 +81,7 @@ def getBatchData(batchToGenerate, batch_json_save_path):
file_name = os.path.join(batch_json_save_path, "Batch{}.json".format(batchToGenerate))
batch = json.load(open(file_name))
NFTs_in_Batch = batch["NFTs_in_Batch"]
hierarchy = batch["hierarchy"]
BatchDNAList = batch["BatchDNAList"]
@ -35,7 +90,7 @@ def getBatchData(batchToGenerate, batch_json_save_path):
def render_and_save_NFTs(nftName, maxNFTs, batchToGenerate, batch_json_save_path, nftBatch_save_path, enableImages,
imageFileFormat, enableAnimations, animationFileFormat, enableModelsBlender,
modelFileFormat
modelFileFormat, fail_state, failed_batch, failed_dna, failed_dna_index
):
"""
Renders the NFT DNA in a Batch#.json, where # is renderBatch in config.py. Turns off the viewport camera and
@ -46,20 +101,31 @@ def render_and_save_NFTs(nftName, maxNFTs, batchToGenerate, batch_json_save_path
time_start_1 = time.time()
x = 1
if fail_state:
for a in range(failed_dna):
del BatchDNAList[0]
x = failed_dna + 1
else:
save_generation_state(batchToGenerate, batch_json_save_path, nftBatch_save_path, enableImages, imageFileFormat,
enableAnimations,
animationFileFormat, enableModelsBlender, modelFileFormat)
x = 1
for a in BatchDNAList:
single_dna = list(a.keys())[0]
for i in hierarchy:
for j in hierarchy[i]:
bpy.data.collections[j].hide_render = True
bpy.data.collections[j].hide_viewport = True
def match_DNA_to_Variant(a):
def match_DNA_to_Variant(single_dna):
"""
Matches each DNA number separated by "-" to its attribute, then its variant.
"""
listAttributes = list(hierarchy.keys())
listDnaDecunstructed = a.split('-')
listDnaDecunstructed = single_dna.split('-')
dnaDictionary = {}
for i, j in zip(listAttributes, listDnaDecunstructed):
@ -72,11 +138,11 @@ def render_and_save_NFTs(nftName, maxNFTs, batchToGenerate, batch_json_save_path
dnaDictionary.update({x: k})
return dnaDictionary
dnaDictionary = match_DNA_to_Variant(a)
dnaDictionary = match_DNA_to_Variant(single_dna)
name = nftName + "_" + str(x)
print(f"\n{bcolors.OK}|---Generating NFT {x}/{NFTs_in_Batch} ---|{bcolors.RESET}")
print(f"DNA attribute list:\n{dnaDictionary}\nDNA Code:{a}")
print(f"DNA attribute list:\n{dnaDictionary}\nDNA Code:{single_dna}")
for c in dnaDictionary:
collection = dnaDictionary[c]
@ -99,7 +165,6 @@ def render_and_save_NFTs(nftName, maxNFTs, batchToGenerate, batch_json_save_path
metaDataFolder = os.path.join(batchFolder, "BMNFT_metaData")
# Generation/Rendering:
if enableImages:
print(f"{bcolors.OK}---Image---{bcolors.RESET}")
@ -235,6 +300,9 @@ def render_and_save_NFTs(nftName, maxNFTs, batchToGenerate, batch_json_save_path
outfile.write(jsonMetaData + '\n')
print(f"Completed {name} render in {time.time() - time_start_2}s")
save_completed(single_dna, a, x, batch_json_save_path, batchToGenerate)
x += 1
for i in hierarchy: