kopia lustrzana https://github.com/torrinworx/Blend_My_NFTs
Pep8 formatting and renaming key variables
rodzic
7c389e15df
commit
57ec4b1ac1
|
@ -11,6 +11,7 @@ from bpy.types import (Operator,
|
||||||
PropertyGroup,
|
PropertyGroup,
|
||||||
UIList)
|
UIList)
|
||||||
|
|
||||||
|
|
||||||
# ======== Operators ======== #
|
# ======== Operators ======== #
|
||||||
class CUSTOM_OT_custom_metadata_fields_actions(Operator):
|
class CUSTOM_OT_custom_metadata_fields_actions(Operator):
|
||||||
"""Move items up and down, add and remove"""
|
"""Move items up and down, add and remove"""
|
||||||
|
@ -103,6 +104,7 @@ class CUSTOM_UL_custom_metadata_fields_items(UIList):
|
||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
# ======== Property Collection ======== #
|
# ======== Property Collection ======== #
|
||||||
class CUSTOM_custom_metadata_fields_objectCollection(PropertyGroup):
|
class CUSTOM_custom_metadata_fields_objectCollection(PropertyGroup):
|
||||||
# name: StringProperty() -> Instantiated by default
|
# name: StringProperty() -> Instantiated by default
|
||||||
|
|
|
@ -11,6 +11,7 @@ from bpy.types import (Operator,
|
||||||
PropertyGroup,
|
PropertyGroup,
|
||||||
UIList)
|
UIList)
|
||||||
|
|
||||||
|
|
||||||
# ======== Operators ======== #
|
# ======== Operators ======== #
|
||||||
class CUSTOM_OT_logic_actions(Operator):
|
class CUSTOM_OT_logic_actions(Operator):
|
||||||
"""Move items up and down, add and remove"""
|
"""Move items up and down, add and remove"""
|
||||||
|
|
492
__init__.py
492
__init__.py
|
@ -1,18 +1,19 @@
|
||||||
bl_info = {
|
bl_info = {
|
||||||
"name": "Blend_My_NFTs",
|
"name": "Blend_My_NFTs",
|
||||||
"author": "Torrin Leonard, This Cozy Studio Inc",
|
"author": "Torrin Leonard, This Cozy Studio Inc.",
|
||||||
"version": (4, 5, 0),
|
"version": (4, 5, 1),
|
||||||
"blender": (3, 2, 2),
|
"blender": (3, 2, 2),
|
||||||
"location": "View3D",
|
"location": "View3D",
|
||||||
"description": "A free and opensource Blender add-on that enables you to create thousands of unique images, animations, and 3D models.",
|
"description": "A free and opensource Blender add-on that enables you to create thousands of unique images, "
|
||||||
|
"animations, and 3D models.",
|
||||||
"support": "COMMUNITY",
|
"support": "COMMUNITY",
|
||||||
"doc_url": "https://github.com/torrinworx/Blend_My_NFTs",
|
"doc_url": "https://github.com/torrinworx/Blend_My_NFTs",
|
||||||
"tracker_url": "https://github.com/torrinworx/Blend_My_NFTs/issues/new",
|
"tracker_url": "https://github.com/torrinworx/Blend_My_NFTs/issues/new",
|
||||||
"category": "Development",
|
"category": "Development",
|
||||||
}
|
}
|
||||||
|
|
||||||
BMNFTS_VERSION = "v4.5.0"
|
BMNFTS_VERSION = "v4.5.1"
|
||||||
LAST_UPDATED = "12:34AM, Aug 11th, 2022"
|
LAST_UPDATED = "01:02PM, Aug 24th, 2022"
|
||||||
|
|
||||||
# ======== Import handling ======== #
|
# ======== Import handling ======== #
|
||||||
|
|
||||||
|
@ -111,64 +112,64 @@ bpy.app.handlers.depsgraph_update_post.append(Refresh_UI)
|
||||||
# ======== Defining BMNFTs Data ======== #
|
# ======== Defining BMNFTs Data ======== #
|
||||||
@dataclass
|
@dataclass
|
||||||
class BMNFTData:
|
class BMNFTData:
|
||||||
nftName: str
|
nft_name: str
|
||||||
save_path: str
|
save_path: str
|
||||||
nftsPerBatch: int
|
nfts_per_batch: int
|
||||||
batchToGenerate: int
|
batch_to_generate: int
|
||||||
collectionSize: int
|
collection_size: int
|
||||||
|
|
||||||
Blend_My_NFTs_Output: str
|
blend_my_nfts_output: str
|
||||||
batch_json_save_path: str
|
batch_json_save_path: str
|
||||||
nftBatch_save_path: str
|
nft_batch_save_path: str
|
||||||
|
|
||||||
enableImages: bool
|
enable_images: bool
|
||||||
imageFileFormat: str
|
image_file_format: str
|
||||||
|
|
||||||
enableAnimations: bool
|
enable_animations: bool
|
||||||
animationFileFormat: str
|
animation_file_format: str
|
||||||
|
|
||||||
enableModelsBlender: bool
|
enable_models: bool
|
||||||
modelFileFormat: str
|
model_file_format: str
|
||||||
|
|
||||||
enableCustomFields: bool
|
enable_custom_fields: bool
|
||||||
|
|
||||||
cardanoMetaDataBool: bool
|
cardano_metadata_bool: bool
|
||||||
solanaMetaDataBool: bool
|
solana_metadata_bool: bool
|
||||||
erc721MetaData: bool
|
erc721_metadata: bool
|
||||||
|
|
||||||
cardano_description: str
|
cardano_description: str
|
||||||
solana_description: str
|
solana_description: str
|
||||||
erc721_description: str
|
erc721_description: str
|
||||||
|
|
||||||
enableMaterials: bool
|
enable_materials: bool
|
||||||
materialsFile: str
|
materials_file: str
|
||||||
|
|
||||||
enableLogic: bool
|
enable_logic: bool
|
||||||
enable_Logic_Json: bool
|
enable_logic_json: bool
|
||||||
logicFile: str
|
logic_file: str
|
||||||
|
|
||||||
enableRarity: bool
|
enable_rarity: bool
|
||||||
|
|
||||||
enableAutoShutdown: bool
|
enable_auto_shutdown: bool
|
||||||
|
|
||||||
specify_timeBool: bool
|
specify_time_bool: bool
|
||||||
hours: int
|
hours: int
|
||||||
minutes: int
|
minutes: int
|
||||||
|
|
||||||
emailNotificationBool: bool
|
email_notification_bool: bool
|
||||||
sender_from: str
|
sender_from: str
|
||||||
email_password: str
|
email_password: str
|
||||||
receiver_to: str
|
receiver_to: str
|
||||||
enable_debug: bool
|
enable_debug: bool
|
||||||
|
|
||||||
custom_Fields: dict = None
|
custom_fields: dict = None
|
||||||
fail_state: Any = False
|
fail_state: Any = False
|
||||||
failed_batch: Any = None
|
failed_batch: Any = None
|
||||||
failed_dna: Any = None
|
failed_dna: Any = None
|
||||||
failed_dna_index: Any = None
|
failed_dna_index: Any = None
|
||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
self.custom_Fields = {}
|
self.custom_fields = {}
|
||||||
|
|
||||||
|
|
||||||
def getBMNFTData():
|
def getBMNFTData():
|
||||||
|
@ -176,51 +177,51 @@ def getBMNFTData():
|
||||||
_Blend_My_NFTs_Output, _batch_json_save_path, _nftBatch_save_path = make_directories(_save_path)
|
_Blend_My_NFTs_Output, _batch_json_save_path, _nftBatch_save_path = make_directories(_save_path)
|
||||||
|
|
||||||
data = BMNFTData(
|
data = BMNFTData(
|
||||||
nftName=bpy.context.scene.input_tool.nftName,
|
nft_name=bpy.context.scene.input_tool.nft_name,
|
||||||
save_path=_save_path,
|
save_path=_save_path,
|
||||||
nftsPerBatch=bpy.context.scene.input_tool.nftsPerBatch,
|
nfts_per_batch=bpy.context.scene.input_tool.nfts_per_batch,
|
||||||
batchToGenerate=bpy.context.scene.input_tool.batchToGenerate,
|
batch_to_generate=bpy.context.scene.input_tool.batch_to_generate,
|
||||||
collectionSize=bpy.context.scene.input_tool.collectionSize,
|
collection_size=bpy.context.scene.input_tool.collection_size,
|
||||||
|
|
||||||
enableRarity=bpy.context.scene.input_tool.enableRarity,
|
enable_rarity=bpy.context.scene.input_tool.enable_rarity,
|
||||||
|
|
||||||
Blend_My_NFTs_Output=_Blend_My_NFTs_Output,
|
blend_my_nfts_output=_Blend_My_NFTs_Output,
|
||||||
batch_json_save_path=_batch_json_save_path,
|
batch_json_save_path=_batch_json_save_path,
|
||||||
nftBatch_save_path=_nftBatch_save_path,
|
nft_batch_save_path=_nftBatch_save_path,
|
||||||
|
|
||||||
enableLogic=bpy.context.scene.input_tool.enableLogic,
|
enable_logic=bpy.context.scene.input_tool.enable_logic,
|
||||||
enable_Logic_Json=bpy.context.scene.input_tool.enable_Logic_Json,
|
enable_logic_json=bpy.context.scene.input_tool.enable_logic_json,
|
||||||
logicFile=bpy.context.scene.input_tool.logicFile,
|
logic_file=bpy.context.scene.input_tool.logic_file,
|
||||||
|
|
||||||
enableImages=bpy.context.scene.input_tool.imageBool,
|
enable_images=bpy.context.scene.input_tool.image_bool,
|
||||||
imageFileFormat=bpy.context.scene.input_tool.imageEnum,
|
image_file_format=bpy.context.scene.input_tool.image_enum,
|
||||||
|
|
||||||
enableAnimations=bpy.context.scene.input_tool.animationBool,
|
enable_animations=bpy.context.scene.input_tool.animation_bool,
|
||||||
animationFileFormat=bpy.context.scene.input_tool.animationEnum,
|
animation_file_format=bpy.context.scene.input_tool.animation_enum,
|
||||||
|
|
||||||
enableModelsBlender=bpy.context.scene.input_tool.modelBool,
|
enable_models=bpy.context.scene.input_tool.model_bool,
|
||||||
modelFileFormat=bpy.context.scene.input_tool.modelEnum,
|
model_file_format=bpy.context.scene.input_tool.model_enum,
|
||||||
|
|
||||||
enableCustomFields=bpy.context.scene.input_tool.enableCustomFields,
|
enable_custom_fields=bpy.context.scene.input_tool.enable_custom_fields,
|
||||||
|
|
||||||
cardanoMetaDataBool=bpy.context.scene.input_tool.cardanoMetaDataBool,
|
cardano_metadata_bool=bpy.context.scene.input_tool.cardano_metadata_bool,
|
||||||
solanaMetaDataBool=bpy.context.scene.input_tool.solanaMetaDataBool,
|
solana_metadata_bool=bpy.context.scene.input_tool.solana_metadata_bool,
|
||||||
erc721MetaData=bpy.context.scene.input_tool.erc721MetaData,
|
erc721_metadata=bpy.context.scene.input_tool.erc721_metadata,
|
||||||
|
|
||||||
cardano_description=bpy.context.scene.input_tool.cardano_description,
|
cardano_description=bpy.context.scene.input_tool.cardano_description,
|
||||||
solana_description=bpy.context.scene.input_tool.solana_description,
|
solana_description=bpy.context.scene.input_tool.solana_description,
|
||||||
erc721_description=bpy.context.scene.input_tool.erc721_description,
|
erc721_description=bpy.context.scene.input_tool.erc721_description,
|
||||||
|
|
||||||
enableMaterials=bpy.context.scene.input_tool.enableMaterials,
|
enable_materials=bpy.context.scene.input_tool.enable_materials,
|
||||||
materialsFile=bpy.path.abspath(bpy.context.scene.input_tool.materialsFile),
|
materials_file=bpy.path.abspath(bpy.context.scene.input_tool.materials_file),
|
||||||
|
|
||||||
enableAutoShutdown=bpy.context.scene.input_tool.enableAutoShutdown,
|
enable_auto_shutdown=bpy.context.scene.input_tool.enable_auto_shutdown,
|
||||||
|
|
||||||
specify_timeBool=bpy.context.scene.input_tool.specify_timeBool,
|
specify_time_bool=bpy.context.scene.input_tool.specify_time_bool,
|
||||||
hours=bpy.context.scene.input_tool.hours,
|
hours=bpy.context.scene.input_tool.hours,
|
||||||
minutes=bpy.context.scene.input_tool.minutes,
|
minutes=bpy.context.scene.input_tool.minutes,
|
||||||
|
|
||||||
emailNotificationBool=bpy.context.scene.input_tool.emailNotificationBool,
|
email_notification_bool=bpy.context.scene.input_tool.email_notification_bool,
|
||||||
sender_from=bpy.context.scene.input_tool.sender_from,
|
sender_from=bpy.context.scene.input_tool.sender_from,
|
||||||
email_password=bpy.context.scene.input_tool.email_password,
|
email_password=bpy.context.scene.input_tool.email_password,
|
||||||
receiver_to=bpy.context.scene.input_tool.receiver_to,
|
receiver_to=bpy.context.scene.input_tool.receiver_to,
|
||||||
|
@ -263,35 +264,35 @@ def runAsHeadless():
|
||||||
|
|
||||||
print('Using {} devices for rendering!'.format(cprefs.get_num_gpu_devices()))
|
print('Using {} devices for rendering!'.format(cprefs.get_num_gpu_devices()))
|
||||||
|
|
||||||
def dumpSettings(settings):
|
# def dumpSettings(settings):
|
||||||
output = (
|
# output = (
|
||||||
f"nftName={settings.nftName}\n"
|
# f"nft_name={settings.nft_name}\n"
|
||||||
f"collectionSize={str(settings.collectionSize)}\n"
|
# f"collection_size={str(settings.collection_size)}\n"
|
||||||
f"nftsPerBatch={str(settings.nftsPerBatch)}\n"
|
# f"nfts_per_batch={str(settings.nfts_per_batch)}\n"
|
||||||
f"save_path={settings.save_path}\n"
|
# f"save_path={settings.save_path}\n"
|
||||||
f"enableRarity={(settings.enableRarity)}\n"
|
# f"enable_rarity={(settings.enable_rarity)}\n"
|
||||||
f"enableLogic={str(settings.enableLogic)}\n"
|
# f"enable_logic={str(settings.enable_logic)}\n"
|
||||||
f"imageBool={str(settings.imageBool)}\n"
|
# f"image_bool={str(settings.image_bool)}\n"
|
||||||
f"imageEnum={settings.imageEnum}\n"
|
# f"image_enum={settings.image_enum}\n"
|
||||||
f"animationBool={str(settings.animationBool)}\n"
|
# f"animation_bool={str(settings.animation_bool)}\n"
|
||||||
f"animationEnum={settings.animationEnum}\n"
|
# f"animation_enum={settings.animation_enum}\n"
|
||||||
f"modelBool={str(settings.modelBool)}\n"
|
# f"model_bool={str(settings.model_bool)}\n"
|
||||||
f"modelEnum={settings.modelEnum}\n"
|
# f"model_enum={settings.model_enum}\n"
|
||||||
f"batch_to_generate={str(settings.batchToGenerate)}\n"
|
# f"batch_to_generate={str(settings.batch_to_generate)}\n"
|
||||||
f"cardanoMetaDataBool={str(settings.cardanoMetaDataBool)}\n"
|
# f"cardano_metadata_bool={str(settings.cardano_metadata_bool)}\n"
|
||||||
f"cardano_description={settings.cardano_description}\n"
|
# f"cardano_description={settings.cardano_description}\n"
|
||||||
f"erc721MetaData={str(settings.erc721MetaData)}\n"
|
# f"erc721_metadata={str(settings.erc721_metadata)}\n"
|
||||||
f"erc721_description={settings.erc721_description}\n"
|
# f"erc721_description={settings.erc721_description}\n"
|
||||||
f"solanaMetaDataBool={str(settings.solanaMetaDataBool)}\n"
|
# f"solana_metadata_bool={str(settings.solana_metadata_bool)}\n"
|
||||||
f"solana_description={settings.solana_description}\n"
|
# f"solana_description={settings.solana_description}\n"
|
||||||
f"enableCustomFields={str(settings.enableCustomFields)}\n"
|
# f"enable_custom_fields={str(settings.enable_custom_fields)}\n"
|
||||||
f"customfieldsFile={settings.customfieldsFile}\n"
|
# f"custom_fields_file={settings.custom_fields_file}\n"
|
||||||
f"enableMaterials={str(settings.customfieldsFile)}\n"
|
# f"enable_materials={str(settings.custom_fields_file)}\n"
|
||||||
f"materialsFile={settings.materialsFile}\n"
|
# f"materials_file={settings.materials_file}\n"
|
||||||
)
|
# )
|
||||||
print(output)
|
# print(output)
|
||||||
|
|
||||||
args, parser = headless_util.getPythonArgs()
|
args, parser = headless_util.get_python_args()
|
||||||
|
|
||||||
settings = bpy.context.scene.input_tool
|
settings = bpy.context.scene.input_tool
|
||||||
|
|
||||||
|
@ -304,37 +305,37 @@ def runAsHeadless():
|
||||||
|
|
||||||
# print(pairs)
|
# print(pairs)
|
||||||
|
|
||||||
settings.nftName = pairs[0][1]
|
settings.nft_name = pairs[0][1]
|
||||||
settings.collectionSize = int(pairs[1][1])
|
settings.collection_size = int(pairs[1][1])
|
||||||
settings.nftsPerBatch = int(pairs[2][1])
|
settings.nfts_per_batch = int(pairs[2][1])
|
||||||
settings.save_path = pairs[3][1]
|
settings.save_path = pairs[3][1]
|
||||||
settings.enableRarity = pairs[4][1] == 'True'
|
settings.enable_rarity = pairs[4][1]=='True'
|
||||||
settings.enableLogic = pairs[5][1] == 'True'
|
settings.enable_logic = pairs[5][1]=='True'
|
||||||
settings.enableLogicJson = pairs[6][1] == 'True'
|
settings.enableLogicJson = pairs[6][1] == 'True'
|
||||||
settings.logicFile = pairs[7][1]
|
settings.logic_file = pairs[7][1]
|
||||||
settings.imageBool = pairs[8][1] == 'True'
|
settings.image_bool = pairs[8][1]=='True'
|
||||||
settings.imageEnum = pairs[9][1]
|
settings.image_enum = pairs[9][1]
|
||||||
settings.animationBool = pairs[10][1] == 'True'
|
settings.animation_bool = pairs[10][1]=='True'
|
||||||
settings.animationEnum = pairs[11][1]
|
settings.animation_enum = pairs[11][1]
|
||||||
settings.modelBool = pairs[12][1] == 'True'
|
settings.model_bool = pairs[12][1]=='True'
|
||||||
settings.modelEnum = pairs[13][1]
|
settings.model_enum = pairs[13][1]
|
||||||
settings.batchToGenerate = int(pairs[14][1])
|
settings.batch_to_generate = int(pairs[14][1])
|
||||||
settings.cardanoMetaDataBool = pairs[15][1] == 'True'
|
settings.cardano_metadata_bool = pairs[15][1]=='True'
|
||||||
settings.cardano_description = pairs[16][1]
|
settings.cardano_description = pairs[16][1]
|
||||||
settings.erc721MetaData = pairs[17][1] == 'True'
|
settings.erc721_metadata = pairs[17][1]=='True'
|
||||||
settings.erc721_description = pairs[18][1]
|
settings.erc721_description = pairs[18][1]
|
||||||
settings.solanaMetaDataBool = pairs[19][1] == 'True'
|
settings.solana_metadata_bool = pairs[19][1]=='True'
|
||||||
settings.solanaDescription = pairs[20][1]
|
settings.solanaDescription = pairs[20][1]
|
||||||
settings.enableCustomFields = pairs[21][1] == 'True'
|
settings.enable_custom_fields = pairs[21][1]=='True'
|
||||||
settings.customfieldsFile = pairs[22][1]
|
settings.custom_fields_file = pairs[22][1]
|
||||||
settings.enableMaterials = pairs[23][1] == 'True'
|
settings.enable_materials = pairs[23][1]=='True'
|
||||||
settings.materialsFile = pairs[24][1]
|
settings.materials_file = pairs[24][1]
|
||||||
|
|
||||||
if args.save_path:
|
if args.save_path:
|
||||||
settings.save_path = args.save_path
|
settings.save_path = args.save_path
|
||||||
|
|
||||||
if args.batch_number:
|
if args.batch_number:
|
||||||
settings.batchToGenerate = args.batch_number
|
settings.batch_to_generate = args.batch_number
|
||||||
|
|
||||||
input = getBMNFTData()
|
input = getBMNFTData()
|
||||||
|
|
||||||
|
@ -342,27 +343,27 @@ def runAsHeadless():
|
||||||
input.batch_json_save_path = args.batch_data_path
|
input.batch_json_save_path = args.batch_data_path
|
||||||
|
|
||||||
if args.operation == 'create-dna':
|
if args.operation == 'create-dna':
|
||||||
intermediate.send_To_Record_JSON(input)
|
intermediate.send_to_record(input)
|
||||||
|
|
||||||
elif args.operation == 'generate-nfts':
|
elif args.operation == 'generate-nfts':
|
||||||
intermediate.render_and_save_NFTs(input)
|
intermediate.render_and_save_nfts(input)
|
||||||
|
|
||||||
elif args.operation == 'refactor-batches':
|
elif args.operation == 'refactor-batches':
|
||||||
refactorer.reformatNFTCollection(input)
|
refactorer.reformat_nft_collection(input)
|
||||||
|
|
||||||
|
|
||||||
# ======== User input Property Group ======== #
|
# ======== User input Property Group ======== #
|
||||||
class BMNFTS_PGT_Input_Properties(bpy.types.PropertyGroup):
|
class BMNFTS_PGT_Input_Properties(bpy.types.PropertyGroup):
|
||||||
# Create NFT Data Panel:
|
# Create NFT Data Panel:
|
||||||
|
|
||||||
nftName: bpy.props.StringProperty(name="NFT Name")
|
nft_name: bpy.props.StringProperty(name="NFT Name")
|
||||||
|
|
||||||
collectionSize: bpy.props.IntProperty(
|
collection_size: bpy.props.IntProperty(
|
||||||
name="NFT Collection Size",
|
name="NFT Collection Size",
|
||||||
default=1,
|
default=1,
|
||||||
min=1
|
min=1
|
||||||
) # max=(combinations - offset)
|
) # max=(combinations - offset)
|
||||||
nftsPerBatch: bpy.props.IntProperty(
|
nfts_per_batch: bpy.props.IntProperty(
|
||||||
name="NFTs Per Batch",
|
name="NFTs Per Batch",
|
||||||
default=1,
|
default=1,
|
||||||
min=1
|
min=1
|
||||||
|
@ -376,17 +377,17 @@ class BMNFTS_PGT_Input_Properties(bpy.types.PropertyGroup):
|
||||||
subtype="DIR_PATH"
|
subtype="DIR_PATH"
|
||||||
)
|
)
|
||||||
|
|
||||||
enableRarity: bpy.props.BoolProperty(
|
enable_rarity: bpy.props.BoolProperty(
|
||||||
name="Enable Rarity"
|
name="Enable Rarity"
|
||||||
)
|
)
|
||||||
|
|
||||||
enableLogic: bpy.props.BoolProperty(
|
enable_logic: bpy.props.BoolProperty(
|
||||||
name="Enable Logic"
|
name="Enable Logic"
|
||||||
)
|
)
|
||||||
enable_Logic_Json: bpy.props.BoolProperty(
|
enable_logic_json: bpy.props.BoolProperty(
|
||||||
name="Use Logic.json instead"
|
name="Use Logic.json instead"
|
||||||
)
|
)
|
||||||
logicFile: bpy.props.StringProperty(
|
logic_file: bpy.props.StringProperty(
|
||||||
name="Logic File Path",
|
name="Logic File Path",
|
||||||
description="Path where Logic.json is located.",
|
description="Path where Logic.json is located.",
|
||||||
default="",
|
default="",
|
||||||
|
@ -394,10 +395,10 @@ class BMNFTS_PGT_Input_Properties(bpy.types.PropertyGroup):
|
||||||
subtype="FILE_PATH"
|
subtype="FILE_PATH"
|
||||||
)
|
)
|
||||||
|
|
||||||
enableMaterials: bpy.props.BoolProperty(
|
enable_materials: bpy.props.BoolProperty(
|
||||||
name="Enable Materials"
|
name="Enable Materials"
|
||||||
)
|
)
|
||||||
materialsFile: bpy.props.StringProperty(
|
materials_file: bpy.props.StringProperty(
|
||||||
name="Materials File",
|
name="Materials File",
|
||||||
description="Path where Materials.json is located.",
|
description="Path where Materials.json is located.",
|
||||||
default="",
|
default="",
|
||||||
|
@ -406,10 +407,10 @@ class BMNFTS_PGT_Input_Properties(bpy.types.PropertyGroup):
|
||||||
)
|
)
|
||||||
|
|
||||||
# Generate NFTs Panel:
|
# Generate NFTs Panel:
|
||||||
imageBool: bpy.props.BoolProperty(
|
image_bool: bpy.props.BoolProperty(
|
||||||
name="Image"
|
name="Image"
|
||||||
)
|
)
|
||||||
imageEnum: bpy.props.EnumProperty(
|
image_enum: bpy.props.EnumProperty(
|
||||||
name="Image File Format",
|
name="Image File Format",
|
||||||
description="Select Image file format",
|
description="Select Image file format",
|
||||||
items=[
|
items=[
|
||||||
|
@ -418,10 +419,10 @@ class BMNFTS_PGT_Input_Properties(bpy.types.PropertyGroup):
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
animationBool: bpy.props.BoolProperty(
|
animation_bool: bpy.props.BoolProperty(
|
||||||
name="Animation"
|
name="Animation"
|
||||||
)
|
)
|
||||||
animationEnum: bpy.props.EnumProperty(
|
animation_enum: bpy.props.EnumProperty(
|
||||||
name="Animation File Format",
|
name="Animation File Format",
|
||||||
description="Select Animation file format",
|
description="Select Animation file format",
|
||||||
items=[
|
items=[
|
||||||
|
@ -434,10 +435,10 @@ class BMNFTS_PGT_Input_Properties(bpy.types.PropertyGroup):
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
modelBool: bpy.props.BoolProperty(
|
model_bool: bpy.props.BoolProperty(
|
||||||
name="3D Model"
|
name="3D Model"
|
||||||
)
|
)
|
||||||
modelEnum: bpy.props.EnumProperty(
|
model_enum: bpy.props.EnumProperty(
|
||||||
name="3D Model File Format",
|
name="3D Model File Format",
|
||||||
description="Select 3D Model file format",
|
description="Select 3D Model file format",
|
||||||
items=[
|
items=[
|
||||||
|
@ -454,38 +455,38 @@ class BMNFTS_PGT_Input_Properties(bpy.types.PropertyGroup):
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
batchToGenerate: bpy.props.IntProperty(
|
batch_to_generate: bpy.props.IntProperty(
|
||||||
name="Batch To Generate",
|
name="Batch To Generate",
|
||||||
default=1,
|
default=1,
|
||||||
min=1
|
min=1
|
||||||
)
|
)
|
||||||
|
|
||||||
# Refactor Batches & Create Metadata Panel:
|
# Refactor Batches & Create Metadata Panel:
|
||||||
cardanoMetaDataBool: bpy.props.BoolProperty(
|
cardano_metadata_bool: bpy.props.BoolProperty(
|
||||||
name="Cardano Cip"
|
name="Cardano Cip"
|
||||||
)
|
)
|
||||||
cardano_description: bpy.props.StringProperty(
|
cardano_description: bpy.props.StringProperty(
|
||||||
name="Cardano description"
|
name="Cardano description"
|
||||||
)
|
)
|
||||||
|
|
||||||
solanaMetaDataBool: bpy.props.BoolProperty(
|
solana_metadata_bool: bpy.props.BoolProperty(
|
||||||
name="Solana Metaplex"
|
name="Solana Metaplex"
|
||||||
)
|
)
|
||||||
solana_description: bpy.props.StringProperty(
|
solana_description: bpy.props.StringProperty(
|
||||||
name="Solana description"
|
name="Solana description"
|
||||||
)
|
)
|
||||||
|
|
||||||
erc721MetaData: bpy.props.BoolProperty(
|
erc721_metadata: bpy.props.BoolProperty(
|
||||||
name="ERC721"
|
name="ERC721"
|
||||||
)
|
)
|
||||||
erc721_description: bpy.props.StringProperty(
|
erc721_description: bpy.props.StringProperty(
|
||||||
name="ERC721 description"
|
name="ERC721 description"
|
||||||
)
|
)
|
||||||
|
|
||||||
enableCustomFields: bpy.props.BoolProperty(
|
enable_custom_fields: bpy.props.BoolProperty(
|
||||||
name="Enable Custom Metadata Fields"
|
name="Enable Custom Metadata Fields"
|
||||||
)
|
)
|
||||||
customfieldsFile: bpy.props.StringProperty(
|
custom_fields_file: bpy.props.StringProperty(
|
||||||
name="Custom Fields File",
|
name="Custom Fields File",
|
||||||
description="Path where Custom_Fields.json is located.",
|
description="Path where Custom_Fields.json is located.",
|
||||||
default="",
|
default="",
|
||||||
|
@ -496,17 +497,17 @@ class BMNFTS_PGT_Input_Properties(bpy.types.PropertyGroup):
|
||||||
# TODO: Add 'Other' panel inputs to Headless functionality.
|
# TODO: Add 'Other' panel inputs to Headless functionality.
|
||||||
|
|
||||||
# Other Panel:
|
# Other Panel:
|
||||||
enableAutoSave: bpy.props.BoolProperty(
|
enable_auto_save: bpy.props.BoolProperty(
|
||||||
name="Auto Save Before Generation",
|
name="Auto Save Before Generation",
|
||||||
description="Automatically saves your Blender file when 'Generate NFTs & Create Metadata' button is clicked"
|
description="Automatically saves your Blender file when 'Generate NFTs & Create Metadata' button is clicked"
|
||||||
)
|
)
|
||||||
|
|
||||||
enableAutoShutdown: bpy.props.BoolProperty(
|
enable_auto_shutdown: bpy.props.BoolProperty(
|
||||||
name="Auto Shutdown",
|
name="Auto Shutdown",
|
||||||
description="Automatically shuts down your computer after a Batch is finished Generating"
|
description="Automatically shuts down your computer after a Batch is finished Generating"
|
||||||
)
|
)
|
||||||
|
|
||||||
specify_timeBool: bpy.props.BoolProperty(
|
specify_time_bool: bpy.props.BoolProperty(
|
||||||
name="Shutdown in a Given Amount of Time",
|
name="Shutdown in a Given Amount of Time",
|
||||||
description="Wait a given amount of time after a Batch is generated before Automatic Shutdown"
|
description="Wait a given amount of time after a Batch is generated before Automatic Shutdown"
|
||||||
)
|
)
|
||||||
|
@ -517,7 +518,7 @@ class BMNFTS_PGT_Input_Properties(bpy.types.PropertyGroup):
|
||||||
default=0, min=0
|
default=0, min=0
|
||||||
)
|
)
|
||||||
|
|
||||||
emailNotificationBool: bpy.props.BoolProperty(
|
email_notification_bool: bpy.props.BoolProperty(
|
||||||
name="Email Notifications",
|
name="Email Notifications",
|
||||||
description="Receive Email Notifications from Blender once a batch is finished generating"
|
description="Receive Email Notifications from Blender once a batch is finished generating"
|
||||||
)
|
)
|
||||||
|
@ -541,17 +542,18 @@ class BMNFTS_PGT_Input_Properties(bpy.types.PropertyGroup):
|
||||||
)
|
)
|
||||||
|
|
||||||
# API Panel properties:
|
# API Panel properties:
|
||||||
apiKey: bpy.props.StringProperty(
|
api_key: bpy.props.StringProperty(
|
||||||
name="API Key",
|
name="API Key",
|
||||||
subtype='PASSWORD'
|
subtype='PASSWORD'
|
||||||
) # Test code for future features
|
) # Test code for future features
|
||||||
|
|
||||||
|
|
||||||
# ======== Main Operators ======== #
|
# ======== Main Operators ======== #
|
||||||
class createData(bpy.types.Operator):
|
class Createdata(bpy.types.Operator):
|
||||||
bl_idname = 'create.data'
|
bl_idname = 'create.data'
|
||||||
bl_label = 'Create Data'
|
bl_label = 'Create Data'
|
||||||
bl_description = 'Creates NFT Data. Run after any changes were made to scene. All previous data will be overwritten and cannot be recovered.'
|
bl_description = 'Creates NFT Data. Run after any changes were made to scene. All previous data will be ' \
|
||||||
|
'overwritten and cannot be recovered.'
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
reverse_order: BoolProperty(
|
reverse_order: BoolProperty(
|
||||||
|
@ -562,12 +564,12 @@ class createData(bpy.types.Operator):
|
||||||
# Handling Custom Fields UIList input:
|
# Handling Custom Fields UIList input:
|
||||||
input = getBMNFTData()
|
input = getBMNFTData()
|
||||||
|
|
||||||
if input.enableLogic:
|
if input.enable_logic:
|
||||||
if input.enable_Logic_Json and not input.logicFile:
|
if input.enable_logic_json and not input.logic_file:
|
||||||
self.report({'ERROR'},
|
self.report({'ERROR'},
|
||||||
f"No Logic.json file path set. Please set the file path to your Logic.json file.")
|
f"No Logic.json file path set. Please set the file path to your Logic.json file.")
|
||||||
|
|
||||||
intermediate.send_To_Record_JSON(input)
|
intermediate.send_to_record(input)
|
||||||
|
|
||||||
self.report({'INFO'}, f"NFT Data created!")
|
self.report({'INFO'}, f"NFT Data created!")
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
@ -576,7 +578,7 @@ class createData(bpy.types.Operator):
|
||||||
return context.window_manager.invoke_confirm(self, event)
|
return context.window_manager.invoke_confirm(self, event)
|
||||||
|
|
||||||
|
|
||||||
class exportNFTs(bpy.types.Operator):
|
class ExportNFTs(bpy.types.Operator):
|
||||||
bl_idname = 'exporter.nfts'
|
bl_idname = 'exporter.nfts'
|
||||||
bl_label = 'Export NFTs'
|
bl_label = 'Export NFTs'
|
||||||
bl_description = 'Generate and export a given batch of NFTs.'
|
bl_description = 'Generate and export a given batch of NFTs.'
|
||||||
|
@ -590,14 +592,14 @@ class exportNFTs(bpy.types.Operator):
|
||||||
input = getBMNFTData()
|
input = getBMNFTData()
|
||||||
# Handling Custom Fields UIList input:
|
# Handling Custom Fields UIList input:
|
||||||
|
|
||||||
intermediate.render_and_save_NFTs(input)
|
intermediate.render_and_save_nfts(input)
|
||||||
|
|
||||||
self.report({'INFO'}, f"All NFTs generated for batch {input.batchToGenerate}!")
|
self.report({'INFO'}, f"All NFTs generated for batch {input.batch_to_generate}!")
|
||||||
|
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class resume_failed_batch(bpy.types.Operator):
|
class ResumeFailedBatch(bpy.types.Operator):
|
||||||
bl_idname = 'exporter.resume_nfts'
|
bl_idname = 'exporter.resume_nfts'
|
||||||
bl_label = 'Resume Failed Batch'
|
bl_label = 'Resume Failed Batch'
|
||||||
bl_description = 'Failed Batch detected. Generate NFTs where the previous batch failed?'
|
bl_description = 'Failed Batch detected. Generate NFTs where the previous batch failed?'
|
||||||
|
@ -607,7 +609,7 @@ class resume_failed_batch(bpy.types.Operator):
|
||||||
_save_path = bpy.path.abspath(bpy.context.scene.input_tool.save_path)
|
_save_path = bpy.path.abspath(bpy.context.scene.input_tool.save_path)
|
||||||
_Blend_My_NFTs_Output, _batch_json_save_path, _nftBatch_save_path = make_directories(_save_path)
|
_Blend_My_NFTs_Output, _batch_json_save_path, _nftBatch_save_path = make_directories(_save_path)
|
||||||
|
|
||||||
_batchToGenerate = bpy.context.scene.input_tool.batchToGenerate
|
_batchToGenerate = bpy.context.scene.input_tool.batch_to_generate
|
||||||
|
|
||||||
file_name = os.path.join(_batch_json_save_path, "Batch{}.json".format(_batchToGenerate))
|
file_name = os.path.join(_batch_json_save_path, "Batch{}.json".format(_batchToGenerate))
|
||||||
batchData = json.load(open(file_name))
|
batchData = json.load(open(file_name))
|
||||||
|
@ -617,51 +619,51 @@ class resume_failed_batch(bpy.types.Operator):
|
||||||
render_settings = batchData["Generation Save"][-1]["Render_Settings"]
|
render_settings = batchData["Generation Save"][-1]["Render_Settings"]
|
||||||
|
|
||||||
input = BMNFTData(
|
input = BMNFTData(
|
||||||
nftName=render_settings["nftName"],
|
nft_name=render_settings["nft_name"],
|
||||||
save_path=_save_path,
|
save_path=_save_path,
|
||||||
nftsPerBatch=render_settings["nftsPerBatch"],
|
nfts_per_batch=render_settings["nfts_per_batch"],
|
||||||
batchToGenerate=render_settings["batch_to_generate"],
|
batch_to_generate=render_settings["batch_to_generate"],
|
||||||
collectionSize=render_settings["collectionSize"],
|
collection_size=render_settings["collection_size"],
|
||||||
|
|
||||||
Blend_My_NFTs_Output=_Blend_My_NFTs_Output,
|
blend_my_nfts_output=_Blend_My_NFTs_Output,
|
||||||
batch_json_save_path=_batch_json_save_path,
|
batch_json_save_path=_batch_json_save_path,
|
||||||
nftBatch_save_path=render_settings["nftBatch_save_path"],
|
nft_batch_save_path=render_settings["nft_batch_save_path"],
|
||||||
|
|
||||||
enableImages=render_settings["enableImages"],
|
enable_images=render_settings["enable_images"],
|
||||||
imageFileFormat=render_settings["imageFileFormat"],
|
image_file_format=render_settings["image_file_format"],
|
||||||
|
|
||||||
enableAnimations=render_settings["enableAnimations"],
|
enable_animations=render_settings["enable_animations"],
|
||||||
animationFileFormat=render_settings["animationFileFormat"],
|
animation_file_format=render_settings["animation_file_format"],
|
||||||
|
|
||||||
enableModelsBlender=render_settings["enableModelsBlender"],
|
enable_models=render_settings["enable_models"],
|
||||||
modelFileFormat=render_settings["modelFileFormat"],
|
model_file_format=render_settings["model_file_format"],
|
||||||
|
|
||||||
enableCustomFields=render_settings["enableCustomFields"],
|
enable_custom_fields=render_settings["enable_custom_fields"],
|
||||||
|
|
||||||
cardanoMetaDataBool=render_settings["cardanoMetaDataBool"],
|
cardano_metadata_bool=render_settings["cardano_metadata_bool"],
|
||||||
solanaMetaDataBool=render_settings["solanaMetaDataBool"],
|
solana_metadata_bool=render_settings["solana_metadata_bool"],
|
||||||
erc721MetaData=render_settings["erc721MetaData"],
|
erc721_metadata=render_settings["erc721_metadata"],
|
||||||
|
|
||||||
cardano_description=render_settings["cardano_description"],
|
cardano_description=render_settings["cardano_description"],
|
||||||
solana_description=render_settings["solana_description"],
|
solana_description=render_settings["solana_description"],
|
||||||
erc721_description=render_settings["erc721_description"],
|
erc721_description=render_settings["erc721_description"],
|
||||||
|
|
||||||
enableMaterials=render_settings["enableMaterials"],
|
enable_materials=render_settings["enable_materials"],
|
||||||
materialsFile=render_settings["materialsFile"],
|
materials_file=render_settings["materials_file"],
|
||||||
|
|
||||||
enableLogic=render_settings["enableLogic"],
|
enable_logic=render_settings["enable_logic"],
|
||||||
enable_Logic_Json=render_settings["enable_Logic_Json"],
|
enable_logic_json=render_settings["enable_logic_json"],
|
||||||
logicFile=render_settings["logicFile"],
|
logic_file=render_settings["logic_file"],
|
||||||
|
|
||||||
enableRarity=render_settings["enableRarity"],
|
enable_rarity=render_settings["enable_rarity"],
|
||||||
|
|
||||||
enableAutoShutdown=render_settings["enableAutoShutdown"],
|
enable_auto_shutdown=render_settings["enable_auto_shutdown"],
|
||||||
|
|
||||||
specify_timeBool=render_settings["specify_timeBool"],
|
specify_time_bool=render_settings["specify_time_bool"],
|
||||||
hours=render_settings["hours"],
|
hours=render_settings["hours"],
|
||||||
minutes=render_settings["minutes"],
|
minutes=render_settings["minutes"],
|
||||||
|
|
||||||
emailNotificationBool=render_settings["emailNotificationBool"],
|
email_notification_bool=render_settings["email_notification_bool"],
|
||||||
sender_from=render_settings["sender_from"],
|
sender_from=render_settings["sender_from"],
|
||||||
email_password=render_settings["email_password"],
|
email_password=render_settings["email_password"],
|
||||||
receiver_to=render_settings["receiver_to"],
|
receiver_to=render_settings["receiver_to"],
|
||||||
|
@ -672,7 +674,7 @@ class resume_failed_batch(bpy.types.Operator):
|
||||||
failed_dna=_failed_dna,
|
failed_dna=_failed_dna,
|
||||||
failed_dna_index=_failed_dna_index,
|
failed_dna_index=_failed_dna_index,
|
||||||
|
|
||||||
custom_Fields=render_settings["custom_Fields"],
|
custom_fields=render_settings["custom_fields"],
|
||||||
)
|
)
|
||||||
|
|
||||||
exporter.render_and_save_nfts(input)
|
exporter.render_and_save_nfts(input)
|
||||||
|
@ -682,7 +684,7 @@ class resume_failed_batch(bpy.types.Operator):
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class refactor_Batches(bpy.types.Operator):
|
class RefactorBatches(bpy.types.Operator):
|
||||||
"""Refactor your collection? This action cannot be undone."""
|
"""Refactor your collection? This action cannot be undone."""
|
||||||
bl_idname = 'refactor.batches'
|
bl_idname = 'refactor.batches'
|
||||||
bl_label = 'Refactor your Batches?'
|
bl_label = 'Refactor your Batches?'
|
||||||
|
@ -695,14 +697,14 @@ class refactor_Batches(bpy.types.Operator):
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
# Passing info to main functions for refactoring:
|
# Passing info to main functions for refactoring:
|
||||||
refactorer.reformatNFTCollection(getBMNFTData())
|
refactorer.reformat_nft_collection(getBMNFTData())
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
return context.window_manager.invoke_confirm(self, event)
|
return context.window_manager.invoke_confirm(self, event)
|
||||||
|
|
||||||
|
|
||||||
class export_settings(bpy.types.Operator):
|
class ExportSettings(bpy.types.Operator):
|
||||||
"""Export your settings into a configuration file."""
|
"""Export your settings into a configuration file."""
|
||||||
bl_idname = 'export.settings'
|
bl_idname = 'export.settings'
|
||||||
bl_label = 'Export Settings'
|
bl_label = 'Export Settings'
|
||||||
|
@ -721,51 +723,51 @@ class export_settings(bpy.types.Operator):
|
||||||
"#when running Blend_My_NFTs in a headless environment.\n"
|
"#when running Blend_My_NFTs in a headless environment.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"#The name of your nft project\n"
|
"#The name of your nft project\n"
|
||||||
f"nftName={settings.nftName}\n"
|
f"nft_name={settings.nft_name}\n"
|
||||||
"\n"
|
"\n"
|
||||||
"#NFT Collection Size\n"
|
"#NFT Collection Size\n"
|
||||||
f"collectionSize={settings.collectionSize}\n"
|
f"collection_size={settings.collection_size}\n"
|
||||||
"\n"
|
"\n"
|
||||||
"#The number of NFTs to generate per batch\n"
|
"#The number of NFTs to generate per batch\n"
|
||||||
f"nftsPerBatch={str(settings.nftsPerBatch)}\n"
|
f"nfts_per_batch={str(settings.nfts_per_batch)}\n"
|
||||||
"\n"
|
"\n"
|
||||||
"#Save path for your NFT files\n"
|
"#Save path for your NFT files\n"
|
||||||
f"save_path={settings.save_path}\n"
|
f"save_path={settings.save_path}\n"
|
||||||
"\n"
|
"\n"
|
||||||
"#Enable Rarity\n"
|
"#Enable Rarity\n"
|
||||||
f"enableRarity={(settings.enableRarity)}\n"
|
f"enable_rarity={settings.enable_rarity}\n"
|
||||||
"\n"
|
"\n"
|
||||||
"#Enable Logic\n"
|
"#Enable Logic\n"
|
||||||
f"enableLogic={str(settings.enableLogic)}\n"
|
f"enable_logic={str(settings.enable_logic)}\n"
|
||||||
f"enableLogicJson={str(settings.enable_Logic_Json)}\n"
|
f"enableLogicJson={str(settings.enable_logic_json)}\n"
|
||||||
f"logicFilePath={settings.logicFile}\n"
|
f"logicFilePath={settings.logic_file}\n"
|
||||||
"\n"
|
"\n"
|
||||||
"#NFT Media output type(s):\n"
|
"#NFT Media output type(s):\n"
|
||||||
f"imageBool={str(settings.imageBool)}\n"
|
f"image_bool={str(settings.image_bool)}\n"
|
||||||
f"imageEnum={settings.imageEnum}\n"
|
f"image_enum={settings.image_enum}\n"
|
||||||
f"animationBool={str(settings.animationBool)}\n"
|
f"animation_bool={str(settings.animation_bool)}\n"
|
||||||
f"animationEnum={settings.animationEnum}\n"
|
f"animation_enum={settings.animation_enum}\n"
|
||||||
f"modelBool={str(settings.modelBool)}\n"
|
f"model_bool={str(settings.model_bool)}\n"
|
||||||
f"modelEnum={settings.modelEnum}\n"
|
f"model_enum={settings.model_enum}\n"
|
||||||
"\n"
|
"\n"
|
||||||
"#Batch to generate\n"
|
"#Batch to generate\n"
|
||||||
f"batch_to_generate={str(settings.batchToGenerate)}\n"
|
f"batch_to_generate={str(settings.batch_to_generate)}\n"
|
||||||
"\n"
|
"\n"
|
||||||
"#Metadata Format\n"
|
"#Metadata Format\n"
|
||||||
f"cardanoMetaDataBool={str(settings.cardanoMetaDataBool)}\n"
|
f"cardano_metadata_bool={str(settings.cardano_metadata_bool)}\n"
|
||||||
f"cardano_description={settings.cardano_description}\n"
|
f"cardano_description={settings.cardano_description}\n"
|
||||||
f"erc721MetaData={str(settings.erc721MetaData)}\n"
|
f"erc721_metadata={str(settings.erc721_metadata)}\n"
|
||||||
f"erc721_description={settings.erc721_description}\n"
|
f"erc721_description={settings.erc721_description}\n"
|
||||||
f"solanaMetaDataBool={str(settings.solanaMetaDataBool)}\n"
|
f"solana_metadata_bool={str(settings.solana_metadata_bool)}\n"
|
||||||
f"solana_description={settings.solana_description}\n"
|
f"solana_description={settings.solana_description}\n"
|
||||||
"\n"
|
"\n"
|
||||||
"#Enable Custom Fields\n"
|
"#Enable Custom Fields\n"
|
||||||
f"enableCustomFields={str(settings.enableCustomFields)}\n"
|
f"enable_custom_fields={str(settings.enable_custom_fields)}\n"
|
||||||
f"customfieldsFile={settings.customfieldsFile}\n"
|
f"custom_fields_file={settings.custom_fields_file}\n"
|
||||||
"\n"
|
"\n"
|
||||||
"#Enable Materials\n"
|
"#Enable Materials\n"
|
||||||
f"enableMaterials={str(settings.enableMaterials)}\n"
|
f"enable_materials={str(settings.enable_materials)}\n"
|
||||||
f"materialsFile={settings.materialsFile}\n"
|
f"materials_file={settings.materials_file}\n"
|
||||||
)
|
)
|
||||||
|
|
||||||
print(output, file=config)
|
print(output, file=config)
|
||||||
|
@ -789,29 +791,29 @@ class BMNFTS_PT_CreateData(bpy.types.Panel):
|
||||||
input_tool_scene = scene.input_tool
|
input_tool_scene = scene.input_tool
|
||||||
|
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop(input_tool_scene, "nftName")
|
row.prop(input_tool_scene, "nft_name")
|
||||||
|
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
layout.label(text=f"Maximum Number Of NFTs: {combinations}")
|
layout.label(text=f"Maximum Number Of NFTs: {combinations}")
|
||||||
layout.label(text=f"Recommended limit: {recommended_limit}")
|
layout.label(text=f"Recommended limit: {recommended_limit}")
|
||||||
|
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop(input_tool_scene, "collectionSize")
|
row.prop(input_tool_scene, "collection_size")
|
||||||
|
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop(input_tool_scene, "nftsPerBatch")
|
row.prop(input_tool_scene, "nfts_per_batch")
|
||||||
|
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop(input_tool_scene, "save_path")
|
row.prop(input_tool_scene, "save_path")
|
||||||
|
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop(input_tool_scene, "enableRarity")
|
row.prop(input_tool_scene, "enable_rarity")
|
||||||
|
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop(input_tool_scene, "enableLogic")
|
row.prop(input_tool_scene, "enable_logic")
|
||||||
|
|
||||||
# Logic_UIList implementation:
|
# Logic_UIList implementation:
|
||||||
if bpy.context.scene.input_tool.enableLogic:
|
if bpy.context.scene.input_tool.enable_logic:
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
scn = bpy.context.scene
|
scn = bpy.context.scene
|
||||||
|
|
||||||
|
@ -835,18 +837,18 @@ class BMNFTS_PT_CreateData(bpy.types.Panel):
|
||||||
row.label(text=f"*Field Names must be unique.")
|
row.label(text=f"*Field Names must be unique.")
|
||||||
|
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop(input_tool_scene, "enable_Logic_Json")
|
row.prop(input_tool_scene, "enable_logic_json")
|
||||||
|
|
||||||
if bpy.context.scene.input_tool.enable_Logic_Json:
|
if bpy.context.scene.input_tool.enable_logic_json:
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop(input_tool_scene, "logicFile")
|
row.prop(input_tool_scene, "logic_file")
|
||||||
|
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop(input_tool_scene, "enableMaterials")
|
row.prop(input_tool_scene, "enable_materials")
|
||||||
|
|
||||||
if bpy.context.scene.input_tool.enableMaterials:
|
if bpy.context.scene.input_tool.enable_materials:
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop(input_tool_scene, "materialsFile")
|
row.prop(input_tool_scene, "materials_file")
|
||||||
|
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
self.layout.operator("create.data", icon='DISCLOSURE_TRI_RIGHT', text="Create Data")
|
self.layout.operator("create.data", icon='DISCLOSURE_TRI_RIGHT', text="Create Data")
|
||||||
|
@ -870,26 +872,26 @@ class BMNFTS_PT_GenerateNFTs(bpy.types.Panel):
|
||||||
layout.label(text="NFT Media files:")
|
layout.label(text="NFT Media files:")
|
||||||
|
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop(input_tool_scene, "imageBool")
|
row.prop(input_tool_scene, "image_bool")
|
||||||
if bpy.context.scene.input_tool.imageBool:
|
if bpy.context.scene.input_tool.image_bool:
|
||||||
row.prop(input_tool_scene, "imageEnum")
|
row.prop(input_tool_scene, "image_enum")
|
||||||
|
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop(input_tool_scene, "animationBool")
|
row.prop(input_tool_scene, "animation_bool")
|
||||||
if bpy.context.scene.input_tool.animationBool:
|
if bpy.context.scene.input_tool.animation_bool:
|
||||||
row.prop(input_tool_scene, "animationEnum")
|
row.prop(input_tool_scene, "animation_enum")
|
||||||
|
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop(input_tool_scene, "modelBool")
|
row.prop(input_tool_scene, "model_bool")
|
||||||
if bpy.context.scene.input_tool.modelBool:
|
if bpy.context.scene.input_tool.model_bool:
|
||||||
row.prop(input_tool_scene, "modelEnum")
|
row.prop(input_tool_scene, "model_enum")
|
||||||
|
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
layout.label(text="Meta Data format:")
|
layout.label(text="Meta Data format:")
|
||||||
|
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop(input_tool_scene, "cardanoMetaDataBool")
|
row.prop(input_tool_scene, "cardano_metadata_bool")
|
||||||
if bpy.context.scene.input_tool.cardanoMetaDataBool:
|
if bpy.context.scene.input_tool.cardano_metadata_bool:
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop(input_tool_scene, "cardano_description")
|
row.prop(input_tool_scene, "cardano_description")
|
||||||
|
|
||||||
|
@ -898,8 +900,8 @@ class BMNFTS_PT_GenerateNFTs(bpy.types.Panel):
|
||||||
icon='URL').url = "https://cips.cardano.org/cips/cip25/"
|
icon='URL').url = "https://cips.cardano.org/cips/cip25/"
|
||||||
|
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop(input_tool_scene, "solanaMetaDataBool")
|
row.prop(input_tool_scene, "solana_metadata_bool")
|
||||||
if bpy.context.scene.input_tool.solanaMetaDataBool:
|
if bpy.context.scene.input_tool.solana_metadata_bool:
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop(input_tool_scene, "solana_description")
|
row.prop(input_tool_scene, "solana_description")
|
||||||
|
|
||||||
|
@ -908,8 +910,8 @@ class BMNFTS_PT_GenerateNFTs(bpy.types.Panel):
|
||||||
icon='URL').url = "https://docs.metaplex.com/token-metadata/specification"
|
icon='URL').url = "https://docs.metaplex.com/token-metadata/specification"
|
||||||
|
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop(input_tool_scene, "erc721MetaData")
|
row.prop(input_tool_scene, "erc721_metadata")
|
||||||
if bpy.context.scene.input_tool.erc721MetaData:
|
if bpy.context.scene.input_tool.erc721_metadata:
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop(input_tool_scene, "erc721_description")
|
row.prop(input_tool_scene, "erc721_description")
|
||||||
|
|
||||||
|
@ -918,10 +920,10 @@ class BMNFTS_PT_GenerateNFTs(bpy.types.Panel):
|
||||||
icon='URL').url = "https://docs.opensea.io/docs/metadata-standards"
|
icon='URL').url = "https://docs.opensea.io/docs/metadata-standards"
|
||||||
|
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop(input_tool_scene, "enableCustomFields")
|
row.prop(input_tool_scene, "enable_custom_fields")
|
||||||
|
|
||||||
# Custom Metadata Fields UIList:
|
# Custom Metadata Fields UIList:
|
||||||
if bpy.context.scene.input_tool.enableCustomFields:
|
if bpy.context.scene.input_tool.enable_custom_fields:
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
scn = bpy.context.scene
|
scn = bpy.context.scene
|
||||||
|
|
||||||
|
@ -1010,16 +1012,16 @@ class BMNFTS_PT_Other(bpy.types.Panel):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop(input_tool_scene, "enableAutoSave")
|
row.prop(input_tool_scene, "enable_auto_save")
|
||||||
|
|
||||||
# Auto Shutdown:
|
# Auto Shutdown:
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop(input_tool_scene, "enableAutoShutdown")
|
row.prop(input_tool_scene, "enable_auto_shutdown")
|
||||||
row.label(text="*Must Run Blender as Admin")
|
row.label(text="*Must Run Blender as Admin")
|
||||||
|
|
||||||
if bpy.context.scene.input_tool.enableAutoShutdown:
|
if bpy.context.scene.input_tool.enable_auto_shutdown:
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop(input_tool_scene, "specify_timeBool")
|
row.prop(input_tool_scene, "specify_time_bool")
|
||||||
|
|
||||||
time_row1 = layout.row()
|
time_row1 = layout.row()
|
||||||
time_row1.label(text=f"Hours")
|
time_row1.label(text=f"Hours")
|
||||||
|
@ -1029,7 +1031,7 @@ class BMNFTS_PT_Other(bpy.types.Panel):
|
||||||
time_row2.label(text=f"Minutes")
|
time_row2.label(text=f"Minutes")
|
||||||
time_row2.prop(input_tool_scene, "minutes", text="")
|
time_row2.prop(input_tool_scene, "minutes", text="")
|
||||||
|
|
||||||
if not bpy.context.scene.input_tool.specify_timeBool:
|
if not bpy.context.scene.input_tool.specify_time_bool:
|
||||||
time_row1.enabled = False
|
time_row1.enabled = False
|
||||||
time_row2.enabled = False
|
time_row2.enabled = False
|
||||||
else:
|
else:
|
||||||
|
@ -1038,10 +1040,10 @@ class BMNFTS_PT_Other(bpy.types.Panel):
|
||||||
layout.separator()
|
layout.separator()
|
||||||
|
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop(input_tool_scene, "emailNotificationBool")
|
row.prop(input_tool_scene, "email_notification_bool")
|
||||||
row.label(text="*Windows 10+ only")
|
row.label(text="*Windows 10+ only")
|
||||||
|
|
||||||
if bpy.context.scene.input_tool.emailNotificationBool:
|
if bpy.context.scene.input_tool.email_notification_bool:
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop(input_tool_scene, "sender_from")
|
row.prop(input_tool_scene, "sender_from")
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
|
@ -1089,22 +1091,22 @@ class BMNFTS_PT_Other(bpy.types.Panel):
|
||||||
|
|
||||||
# ======== Blender add-on register/unregister handling ======== #
|
# ======== Blender add-on register/unregister handling ======== #
|
||||||
classes = (
|
classes = (
|
||||||
# Property Group Classes:
|
# Property Group Classes:
|
||||||
BMNFTS_PGT_Input_Properties,
|
BMNFTS_PGT_Input_Properties,
|
||||||
|
|
||||||
# Operator Classes:
|
# Operator Classes:
|
||||||
createData,
|
Createdata,
|
||||||
exportNFTs,
|
ExportNFTs,
|
||||||
resume_failed_batch,
|
ResumeFailedBatch,
|
||||||
refactor_Batches,
|
RefactorBatches,
|
||||||
export_settings,
|
ExportSettings,
|
||||||
|
|
||||||
# Panel Classes:
|
# Panel Classes:
|
||||||
BMNFTS_PT_CreateData,
|
BMNFTS_PT_CreateData,
|
||||||
BMNFTS_PT_GenerateNFTs,
|
BMNFTS_PT_GenerateNFTs,
|
||||||
BMNFTS_PT_Refactor,
|
BMNFTS_PT_Refactor,
|
||||||
BMNFTS_PT_Other,
|
BMNFTS_PT_Other,
|
||||||
) + custom_metadata_ui_list.classes_Custom_Metadata_UIList + logic_ui_list.classes_Logic_UIList
|
) + custom_metadata_ui_list.classes_Custom_Metadata_UIList + logic_ui_list.classes_Logic_UIList
|
||||||
|
|
||||||
|
|
||||||
def register():
|
def register():
|
||||||
|
|
|
@ -110,7 +110,7 @@ def generate_nft_dna(
|
||||||
# print(f"Rarity DNA: {single_dna}")
|
# print(f"Rarity DNA: {single_dna}")
|
||||||
|
|
||||||
if enable_logic:
|
if enable_logic:
|
||||||
single_dna = logic.logicafyDNAsingle(hierarchy, single_dna, logic_file, enable_rarity, enable_materials)
|
single_dna = logic.logicafy_dna_single(hierarchy, single_dna, logic_file, enable_rarity, enable_materials)
|
||||||
# print(f"Logic DNA: {single_dna}")
|
# print(f"Logic DNA: {single_dna}")
|
||||||
|
|
||||||
if enable_materials:
|
if enable_materials:
|
||||||
|
@ -170,7 +170,7 @@ def make_batches(
|
||||||
batch_json_save_path
|
batch_json_save_path
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Sorts through all the batches and outputs a given number of batches depending on collectionSize and nftsPerBatch.
|
Sorts through all the batches and outputs a given number of batches depending on collection_size and nfts_per_batch.
|
||||||
These files are then saved as Batch#.json files to batch_json_save_path
|
These files are then saved as Batch#.json files to batch_json_save_path
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
152
main/exporter.py
152
main/exporter.py
|
@ -12,7 +12,7 @@ import datetime
|
||||||
import platform
|
import platform
|
||||||
|
|
||||||
from .helpers import TextColors, Loader
|
from .helpers import TextColors, Loader
|
||||||
from .metadata_templates import createCardanoMetadata, createSolanaMetaData, createErc721MetaData
|
from .metadata_templates import create_cardano_metadata, createSolanaMetaData, create_erc721_meta_data
|
||||||
|
|
||||||
|
|
||||||
# Save info
|
# Save info
|
||||||
|
@ -28,7 +28,7 @@ def save_generation_state(input):
|
||||||
Saves date and time of generation start, and generation types; Images, Animations, 3D Models, and the file types for
|
Saves date and time of generation start, and generation types; Images, Animations, 3D Models, and the file types for
|
||||||
each.
|
each.
|
||||||
"""
|
"""
|
||||||
file_name = os.path.join(input.batch_json_save_path, "Batch{}.json".format(input.batchToGenerate))
|
file_name = os.path.join(input.batch_json_save_path, "Batch{}.json".format(input.batch_to_generate))
|
||||||
batch = json.load(open(file_name))
|
batch = json.load(open(file_name))
|
||||||
|
|
||||||
current_time = datetime.datetime.now().strftime("%H:%M:%S")
|
current_time = datetime.datetime.now().strftime("%H:%M:%S")
|
||||||
|
@ -46,56 +46,56 @@ def save_generation_state(input):
|
||||||
"DNA Generated": None,
|
"DNA Generated": None,
|
||||||
"Generation Start Date and Time": [current_time, current_date, local_timezone],
|
"Generation Start Date and Time": [current_time, current_date, local_timezone],
|
||||||
"Render_Settings": {
|
"Render_Settings": {
|
||||||
"nftName": input.nftName,
|
"nft_name": input.nft_name,
|
||||||
"save_path": input.save_path,
|
"save_path": input.save_path,
|
||||||
"nftsPerBatch": input.nftsPerBatch,
|
"nfts_per_batch": input.nfts_per_batch,
|
||||||
"batch_to_generate": input.batchToGenerate,
|
"batch_to_generate": input.batch_to_generate,
|
||||||
"collectionSize": input.collectionSize,
|
"collection_size": input.collection_size,
|
||||||
|
|
||||||
"Blend_My_NFTs_Output": input.Blend_My_NFTs_Output,
|
"blend_my_nfts_output": input.blend_my_nfts_output,
|
||||||
"batch_json_save_path": input.batch_json_save_path,
|
"batch_json_save_path": input.batch_json_save_path,
|
||||||
"nftBatch_save_path": input.nftBatch_save_path,
|
"nft_batch_save_path": input.nft_batch_save_path,
|
||||||
|
|
||||||
"enableImages": input.enableImages,
|
"enable_images": input.enable_images,
|
||||||
"imageFileFormat": input.imageFileFormat,
|
"image_file_format": input.image_file_format,
|
||||||
|
|
||||||
"enableAnimations": input.enableAnimations,
|
"enable_animations": input.enable_animations,
|
||||||
"animationFileFormat": input.animationFileFormat,
|
"animation_file_format": input.animation_file_format,
|
||||||
|
|
||||||
"enableModelsBlender": input.enableModelsBlender,
|
"enable_models": input.enable_models,
|
||||||
"modelFileFormat": input.modelFileFormat,
|
"model_file_format": input.model_file_format,
|
||||||
|
|
||||||
"enableCustomFields": input.enableCustomFields,
|
"enable_custom_fields": input.enable_custom_fields,
|
||||||
|
|
||||||
"cardanoMetaDataBool": input.cardanoMetaDataBool,
|
"cardano_metadata_bool": input.cardano_metadata_bool,
|
||||||
"solanaMetaDataBool": input.solanaMetaDataBool,
|
"solana_metadata_bool": input.solana_metadata_bool,
|
||||||
"erc721MetaData": input.erc721MetaData,
|
"erc721_metadata": input.erc721_metadata,
|
||||||
|
|
||||||
"cardano_description": input.cardano_description,
|
"cardano_description": input.cardano_description,
|
||||||
"solana_description": input.solana_description,
|
"solana_description": input.solana_description,
|
||||||
"erc721_description": input.erc721_description,
|
"erc721_description": input.erc721_description,
|
||||||
|
|
||||||
"enableMaterials": input.enableMaterials,
|
"enable_materials": input.enable_materials,
|
||||||
"materialsFile": input.materialsFile,
|
"materials_file": input.materials_file,
|
||||||
|
|
||||||
"enableLogic": input.enableLogic,
|
"enable_logic": input.enable_logic,
|
||||||
"enable_Logic_Json": input.enable_Logic_Json,
|
"enable_logic_json": input.enable_logic_json,
|
||||||
"logicFile": input.logicFile,
|
"logic_file": input.logic_file,
|
||||||
|
|
||||||
"enableRarity": input.enableRarity,
|
"enable_rarity": input.enable_rarity,
|
||||||
|
|
||||||
"enableAutoShutdown": input.enableAutoShutdown,
|
"enable_auto_shutdown": input.enable_auto_shutdown,
|
||||||
|
|
||||||
"specify_timeBool": input.specify_timeBool,
|
"specify_time_bool": input.specify_time_bool,
|
||||||
"hours": input.hours,
|
"hours": input.hours,
|
||||||
"minutes": input.minutes,
|
"minutes": input.minutes,
|
||||||
|
|
||||||
"emailNotificationBool": input.emailNotificationBool,
|
"email_notification_bool": input.email_notification_bool,
|
||||||
"sender_from": input.sender_from,
|
"sender_from": input.sender_from,
|
||||||
"email_password": input.email_password,
|
"email_password": input.email_password,
|
||||||
"receiver_to": input.receiver_to,
|
"receiver_to": input.receiver_to,
|
||||||
|
|
||||||
"custom_Fields": input.custom_Fields,
|
"custom_fields": input.custom_fields,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -148,23 +148,23 @@ def render_and_save_nfts(input):
|
||||||
|
|
||||||
# If user is generating the normal way:
|
# If user is generating the normal way:
|
||||||
else:
|
else:
|
||||||
print(f"\nGenerating Batch #{input.batchToGenerate}\n")
|
print(f"\nGenerating Batch #{input.batch_to_generate}\n")
|
||||||
nfts_in_batch, hierarchy, batch_dna_list = get_batch_data(input.batchToGenerate, input.batch_json_save_path)
|
nfts_in_batch, hierarchy, batch_dna_list = get_batch_data(input.batch_to_generate, input.batch_json_save_path)
|
||||||
save_generation_state(input)
|
save_generation_state(input)
|
||||||
x = 1
|
x = 1
|
||||||
|
|
||||||
if input.enableMaterials:
|
if input.enable_materials:
|
||||||
materials_file = json.load(open(input.materialsFile))
|
materials_file = json.load(open(input.materials_file))
|
||||||
|
|
||||||
for a in batch_dna_list:
|
for a in batch_dna_list:
|
||||||
full_single_dna = list(a.keys())[0]
|
full_single_dna = list(a.keys())[0]
|
||||||
order_num = a[full_single_dna]['order_num']
|
order_num = a[full_single_dna]['order_num']
|
||||||
|
|
||||||
# Material handling:
|
# Material handling:
|
||||||
if input.enableMaterials:
|
if input.enable_materials:
|
||||||
single_dna, material_dna = full_single_dna.split(':')
|
single_dna, material_dna = full_single_dna.split(':')
|
||||||
|
|
||||||
if not input.enableMaterials:
|
if not input.enable_materials:
|
||||||
single_dna = full_single_dna
|
single_dna = full_single_dna
|
||||||
|
|
||||||
def match_dna_to_variant(single_dna):
|
def match_dna_to_variant(single_dna):
|
||||||
|
@ -221,7 +221,7 @@ def render_and_save_nfts(input):
|
||||||
|
|
||||||
metadata_material_dict = {}
|
metadata_material_dict = {}
|
||||||
|
|
||||||
if input.enableMaterials:
|
if input.enable_materials:
|
||||||
material_dna_dictionary = match_material_dna_to_material(single_dna, material_dna, materials_file)
|
material_dna_dictionary = match_material_dna_to_material(single_dna, material_dna, materials_file)
|
||||||
|
|
||||||
for var_mat in list(material_dna_dictionary.keys()):
|
for var_mat in list(material_dna_dictionary.keys()):
|
||||||
|
@ -263,7 +263,7 @@ def render_and_save_nfts(input):
|
||||||
)
|
)
|
||||||
|
|
||||||
dna_dictionary = match_dna_to_variant(single_dna)
|
dna_dictionary = match_dna_to_variant(single_dna)
|
||||||
name = input.nftName + "_" + str(order_num)
|
name = input.nft_name + "_" + str(order_num)
|
||||||
|
|
||||||
# Change Text Object in Scene to match DNA string:
|
# Change Text Object in Scene to match DNA string:
|
||||||
# Variables that can be used: full_single_dna, name, order_num
|
# Variables that can be used: full_single_dna, name, order_num
|
||||||
|
@ -273,7 +273,7 @@ def render_and_save_nfts(input):
|
||||||
print(f"\n{TextColors.OK}======== Generating NFT {x}/{nfts_in_batch}: {name} ========{TextColors.RESET}")
|
print(f"\n{TextColors.OK}======== Generating NFT {x}/{nfts_in_batch}: {name} ========{TextColors.RESET}")
|
||||||
print(f"\nVariants selected:")
|
print(f"\nVariants selected:")
|
||||||
print(f"{dna_dictionary}")
|
print(f"{dna_dictionary}")
|
||||||
if input.enableMaterials:
|
if input.enable_materials:
|
||||||
print(f"\nMaterials selected:")
|
print(f"\nMaterials selected:")
|
||||||
print(f"{material_dna_dictionary}")
|
print(f"{material_dna_dictionary}")
|
||||||
|
|
||||||
|
@ -288,7 +288,7 @@ def render_and_save_nfts(input):
|
||||||
time_start_2 = time.time()
|
time_start_2 = time.time()
|
||||||
|
|
||||||
# Main paths for batch sub-folders:
|
# Main paths for batch sub-folders:
|
||||||
batch_folder = os.path.join(input.nftBatch_save_path, "Batch" + str(input.batchToGenerate))
|
batch_folder = os.path.join(input.nft_batch_save_path, "Batch" + str(input.batch_to_generate))
|
||||||
|
|
||||||
image_folder = os.path.join(batch_folder, "Images")
|
image_folder = os.path.join(batch_folder, "Images")
|
||||||
animation_folder = os.path.join(batch_folder, "Animations")
|
animation_folder = os.path.join(batch_folder, "Animations")
|
||||||
|
@ -313,7 +313,7 @@ def render_and_save_nfts(input):
|
||||||
os.remove(file_path)
|
os.remove(file_path)
|
||||||
|
|
||||||
# Generation/Rendering:
|
# Generation/Rendering:
|
||||||
if input.enableImages:
|
if input.enable_images:
|
||||||
|
|
||||||
print(f"{TextColors.OK}-------- Image --------{TextColors.RESET}")
|
print(f"{TextColors.OK}-------- Image --------{TextColors.RESET}")
|
||||||
|
|
||||||
|
@ -326,7 +326,7 @@ def render_and_save_nfts(input):
|
||||||
os.makedirs(image_folder)
|
os.makedirs(image_folder)
|
||||||
|
|
||||||
bpy.context.scene.render.filepath = image_path
|
bpy.context.scene.render.filepath = image_path
|
||||||
bpy.context.scene.render.image_settings.file_format = input.imageFileFormat
|
bpy.context.scene.render.image_settings.file_format = input.image_file_format
|
||||||
bpy.ops.render.render(write_still=True)
|
bpy.ops.render.render(write_still=True)
|
||||||
|
|
||||||
# Loading Animation:
|
# Loading Animation:
|
||||||
|
@ -341,7 +341,7 @@ def render_and_save_nfts(input):
|
||||||
f"\n{TextColors.RESET}"
|
f"\n{TextColors.RESET}"
|
||||||
)
|
)
|
||||||
|
|
||||||
if input.enableAnimations:
|
if input.enable_animations:
|
||||||
print(f"{TextColors.OK}-------- Animation --------{TextColors.RESET}")
|
print(f"{TextColors.OK}-------- Animation --------{TextColors.RESET}")
|
||||||
|
|
||||||
animation_render_time_start = time.time()
|
animation_render_time_start = time.time()
|
||||||
|
@ -352,7 +352,7 @@ def render_and_save_nfts(input):
|
||||||
if not os.path.exists(animation_folder):
|
if not os.path.exists(animation_folder):
|
||||||
os.makedirs(animation_folder)
|
os.makedirs(animation_folder)
|
||||||
|
|
||||||
if input.animationFileFormat == "MP4":
|
if input.animation_file_format =="MP4":
|
||||||
bpy.context.scene.render.filepath = animation_path
|
bpy.context.scene.render.filepath = animation_path
|
||||||
bpy.context.scene.render.image_settings.file_format = "FFMPEG"
|
bpy.context.scene.render.image_settings.file_format = "FFMPEG"
|
||||||
|
|
||||||
|
@ -360,25 +360,25 @@ def render_and_save_nfts(input):
|
||||||
bpy.context.scene.render.ffmpeg.codec = 'H264'
|
bpy.context.scene.render.ffmpeg.codec = 'H264'
|
||||||
bpy.ops.render.render(animation=True)
|
bpy.ops.render.render(animation=True)
|
||||||
|
|
||||||
elif input.animationFileFormat == 'PNG':
|
elif input.animation_file_format =='PNG':
|
||||||
if not os.path.exists(animation_path):
|
if not os.path.exists(animation_path):
|
||||||
os.makedirs(animation_path)
|
os.makedirs(animation_path)
|
||||||
|
|
||||||
bpy.context.scene.render.filepath = os.path.join(animation_path, name)
|
bpy.context.scene.render.filepath = os.path.join(animation_path, name)
|
||||||
bpy.context.scene.render.image_settings.file_format = input.animationFileFormat
|
bpy.context.scene.render.image_settings.file_format = input.animation_file_format
|
||||||
bpy.ops.render.render(animation=True)
|
bpy.ops.render.render(animation=True)
|
||||||
|
|
||||||
elif input.animationFileFormat == 'TIFF':
|
elif input.animation_file_format =='TIFF':
|
||||||
if not os.path.exists(animation_path):
|
if not os.path.exists(animation_path):
|
||||||
os.makedirs(animation_path)
|
os.makedirs(animation_path)
|
||||||
|
|
||||||
bpy.context.scene.render.filepath = os.path.join(animation_path, name)
|
bpy.context.scene.render.filepath = os.path.join(animation_path, name)
|
||||||
bpy.context.scene.render.image_settings.file_format = input.animationFileFormat
|
bpy.context.scene.render.image_settings.file_format = input.animation_file_format
|
||||||
bpy.ops.render.render(animation=True)
|
bpy.ops.render.render(animation=True)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
bpy.context.scene.render.filepath = animation_path
|
bpy.context.scene.render.filepath = animation_path
|
||||||
bpy.context.scene.render.image_settings.file_format = input.animationFileFormat
|
bpy.context.scene.render.image_settings.file_format = input.animation_file_format
|
||||||
bpy.ops.render.render(animation=True)
|
bpy.ops.render.render(animation=True)
|
||||||
|
|
||||||
# Loading Animation:
|
# Loading Animation:
|
||||||
|
@ -393,7 +393,7 @@ def render_and_save_nfts(input):
|
||||||
f"\n{TextColors.RESET}"
|
f"\n{TextColors.RESET}"
|
||||||
)
|
)
|
||||||
|
|
||||||
if input.enableModelsBlender:
|
if input.enable_models:
|
||||||
print(f"{TextColors.OK}-------- 3D Model --------{TextColors.RESET}")
|
print(f"{TextColors.OK}-------- 3D Model --------{TextColors.RESET}")
|
||||||
|
|
||||||
model_generation_time_start = time.time()
|
model_generation_time_start = time.time()
|
||||||
|
@ -419,7 +419,7 @@ def render_and_save_nfts(input):
|
||||||
# if obj.name in remove_objects:
|
# if obj.name in remove_objects:
|
||||||
# obj.select_set(False)
|
# obj.select_set(False)
|
||||||
|
|
||||||
if input.modelFileFormat == 'GLB':
|
if input.model_file_format =='GLB':
|
||||||
check_failed_exists(f"{model_path}.glb")
|
check_failed_exists(f"{model_path}.glb")
|
||||||
bpy.ops.export_scene.gltf(
|
bpy.ops.export_scene.gltf(
|
||||||
filepath=f"{model_path}.glb",
|
filepath=f"{model_path}.glb",
|
||||||
|
@ -428,7 +428,7 @@ def render_and_save_nfts(input):
|
||||||
export_keep_originals=True,
|
export_keep_originals=True,
|
||||||
use_selection=True
|
use_selection=True
|
||||||
)
|
)
|
||||||
if input.modelFileFormat == 'GLTF_SEPARATE':
|
if input.model_file_format =='GLTF_SEPARATE':
|
||||||
check_failed_exists(f"{model_path}.gltf")
|
check_failed_exists(f"{model_path}.gltf")
|
||||||
check_failed_exists(f"{model_path}.bin")
|
check_failed_exists(f"{model_path}.bin")
|
||||||
bpy.ops.export_scene.gltf(
|
bpy.ops.export_scene.gltf(
|
||||||
|
@ -438,7 +438,7 @@ def render_and_save_nfts(input):
|
||||||
export_keep_originals=True,
|
export_keep_originals=True,
|
||||||
use_selection=True
|
use_selection=True
|
||||||
)
|
)
|
||||||
if input.modelFileFormat == 'GLTF_EMBEDDED':
|
if input.model_file_format =='GLTF_EMBEDDED':
|
||||||
check_failed_exists(f"{model_path}.gltf")
|
check_failed_exists(f"{model_path}.gltf")
|
||||||
bpy.ops.export_scene.gltf(
|
bpy.ops.export_scene.gltf(
|
||||||
filepath=f"{model_path}.gltf",
|
filepath=f"{model_path}.gltf",
|
||||||
|
@ -447,35 +447,35 @@ def render_and_save_nfts(input):
|
||||||
export_keep_originals=True,
|
export_keep_originals=True,
|
||||||
use_selection=True
|
use_selection=True
|
||||||
)
|
)
|
||||||
elif input.modelFileFormat == 'FBX':
|
elif input.model_file_format =='FBX':
|
||||||
check_failed_exists(f"{model_path}.fbx")
|
check_failed_exists(f"{model_path}.fbx")
|
||||||
bpy.ops.export_scene.fbx(
|
bpy.ops.export_scene.fbx(
|
||||||
filepath=f"{model_path}.fbx",
|
filepath=f"{model_path}.fbx",
|
||||||
check_existing=True,
|
check_existing=True,
|
||||||
use_selection=True
|
use_selection=True
|
||||||
)
|
)
|
||||||
elif input.modelFileFormat == 'OBJ':
|
elif input.model_file_format =='OBJ':
|
||||||
check_failed_exists(f"{model_path}.obj")
|
check_failed_exists(f"{model_path}.obj")
|
||||||
bpy.ops.export_scene.obj(
|
bpy.ops.export_scene.obj(
|
||||||
filepath=f"{model_path}.obj",
|
filepath=f"{model_path}.obj",
|
||||||
check_existing=True,
|
check_existing=True,
|
||||||
use_selection=True,
|
use_selection=True,
|
||||||
)
|
)
|
||||||
elif input.modelFileFormat == 'X3D':
|
elif input.model_file_format =='X3D':
|
||||||
check_failed_exists(f"{model_path}.x3d")
|
check_failed_exists(f"{model_path}.x3d")
|
||||||
bpy.ops.export_scene.x3d(
|
bpy.ops.export_scene.x3d(
|
||||||
filepath=f"{model_path}.x3d",
|
filepath=f"{model_path}.x3d",
|
||||||
check_existing=True,
|
check_existing=True,
|
||||||
use_selection=True
|
use_selection=True
|
||||||
)
|
)
|
||||||
elif input.modelFileFormat == 'STL':
|
elif input.model_file_format =='STL':
|
||||||
check_failed_exists(f"{model_path}.stl")
|
check_failed_exists(f"{model_path}.stl")
|
||||||
bpy.ops.export_mesh.stl(
|
bpy.ops.export_mesh.stl(
|
||||||
filepath=f"{model_path}.stl",
|
filepath=f"{model_path}.stl",
|
||||||
check_existing=True,
|
check_existing=True,
|
||||||
use_selection=True
|
use_selection=True
|
||||||
)
|
)
|
||||||
elif input.modelFileFormat == 'VOX':
|
elif input.model_file_format =='VOX':
|
||||||
check_failed_exists(f"{model_path}.vox")
|
check_failed_exists(f"{model_path}.vox")
|
||||||
bpy.ops.export_vox.some_data(filepath=f"{model_path}.vox")
|
bpy.ops.export_vox.some_data(filepath=f"{model_path}.vox")
|
||||||
|
|
||||||
|
@ -492,22 +492,22 @@ def render_and_save_nfts(input):
|
||||||
)
|
)
|
||||||
|
|
||||||
# Generating Metadata:
|
# Generating Metadata:
|
||||||
if input.cardanoMetaDataBool:
|
if input.cardano_metadata_bool:
|
||||||
if not os.path.exists(cardano_metadata_path):
|
if not os.path.exists(cardano_metadata_path):
|
||||||
os.makedirs(cardano_metadata_path)
|
os.makedirs(cardano_metadata_path)
|
||||||
createCardanoMetadata(
|
create_cardano_metadata(
|
||||||
name,
|
name,
|
||||||
order_num,
|
order_num,
|
||||||
full_single_dna,
|
full_single_dna,
|
||||||
dna_dictionary,
|
dna_dictionary,
|
||||||
metadata_material_dict,
|
metadata_material_dict,
|
||||||
input.custom_Fields,
|
input.custom_fields,
|
||||||
input.enableCustomFields,
|
input.enable_custom_fields,
|
||||||
input.cardano_description,
|
input.cardano_description,
|
||||||
cardano_metadata_path
|
cardano_metadata_path
|
||||||
)
|
)
|
||||||
|
|
||||||
if input.solanaMetaDataBool:
|
if input.solana_metadata_bool:
|
||||||
if not os.path.exists(solana_metadata_path):
|
if not os.path.exists(solana_metadata_path):
|
||||||
os.makedirs(solana_metadata_path)
|
os.makedirs(solana_metadata_path)
|
||||||
createSolanaMetaData(
|
createSolanaMetaData(
|
||||||
|
@ -516,23 +516,23 @@ def render_and_save_nfts(input):
|
||||||
full_single_dna,
|
full_single_dna,
|
||||||
dna_dictionary,
|
dna_dictionary,
|
||||||
metadata_material_dict,
|
metadata_material_dict,
|
||||||
input.custom_Fields,
|
input.custom_fields,
|
||||||
input.enableCustomFields,
|
input.enable_custom_fields,
|
||||||
input.solana_description,
|
input.solana_description,
|
||||||
solana_metadata_path
|
solana_metadata_path
|
||||||
)
|
)
|
||||||
|
|
||||||
if input.erc721MetaData:
|
if input.erc721_metadata:
|
||||||
if not os.path.exists(erc721_metadata_path):
|
if not os.path.exists(erc721_metadata_path):
|
||||||
os.makedirs(erc721_metadata_path)
|
os.makedirs(erc721_metadata_path)
|
||||||
createErc721MetaData(
|
create_erc721_meta_data(
|
||||||
name,
|
name,
|
||||||
order_num,
|
order_num,
|
||||||
full_single_dna,
|
full_single_dna,
|
||||||
dna_dictionary,
|
dna_dictionary,
|
||||||
metadata_material_dict,
|
metadata_material_dict,
|
||||||
input.custom_Fields,
|
input.custom_fields,
|
||||||
input.enableCustomFields,
|
input.enable_custom_fields,
|
||||||
input.erc721_description,
|
input.erc721_description,
|
||||||
erc721_metadata_path
|
erc721_metadata_path
|
||||||
)
|
)
|
||||||
|
@ -558,7 +558,7 @@ def render_and_save_nfts(input):
|
||||||
|
|
||||||
print(f"Completed {name} render in {time.time() - time_start_2}s")
|
print(f"Completed {name} render in {time.time() - time_start_2}s")
|
||||||
|
|
||||||
save_completed(full_single_dna, a, x, input.batch_json_save_path, input.batchToGenerate)
|
save_completed(full_single_dna, a, x, input.batch_json_save_path, input.batch_to_generate)
|
||||||
|
|
||||||
x += 1
|
x += 1
|
||||||
|
|
||||||
|
@ -569,17 +569,17 @@ def render_and_save_nfts(input):
|
||||||
|
|
||||||
batch_complete_time = time.time() - time_start_1
|
batch_complete_time = time.time() - time_start_1
|
||||||
|
|
||||||
print(f"\nAll NFTs successfully generated and sent to {input.nftBatch_save_path}"
|
print(f"\nAll NFTs successfully generated and sent to {input.nft_batch_save_path}"
|
||||||
f"\nCompleted all renders in Batch{input.batchToGenerate}.json in {batch_complete_time}s\n")
|
f"\nCompleted all renders in Batch{input.batch_to_generate}.json in {batch_complete_time}s\n")
|
||||||
|
|
||||||
batch_info = {"Batch Render Time": batch_complete_time, "Number of NFTs generated in Batch": x - 1,
|
batch_info = {"Batch Render Time": batch_complete_time, "Number of NFTs generated in Batch": x - 1,
|
||||||
"Average time per generation": batch_complete_time / x - 1}
|
"Average time per generation": batch_complete_time / x - 1}
|
||||||
|
|
||||||
batch_info_folder = os.path.join(input.nftBatch_save_path, "Batch" + str(input.batchToGenerate), "batch_info.json")
|
batch_info_folder = os.path.join(input.nft_batch_save_path, "Batch" + str(input.batch_to_generate), "batch_info.json")
|
||||||
save_batch(batch_info, batch_info_folder)
|
save_batch(batch_info, batch_info_folder)
|
||||||
|
|
||||||
# Send Email that Batch is complete:
|
# Send Email that Batch is complete:
|
||||||
if input.emailNotificationBool:
|
if input.email_notification_bool:
|
||||||
port = 465 # For SSL
|
port = 465 # For SSL
|
||||||
smtp_server = "smtp.gmail.com"
|
smtp_server = "smtp.gmail.com"
|
||||||
sender_email = input.sender_from # Enter your address
|
sender_email = input.sender_from # Enter your address
|
||||||
|
@ -592,9 +592,9 @@ def render_and_save_nfts(input):
|
||||||
batch_data = get_batch_data(input.failed_batch, input.batch_json_save_path)
|
batch_data = get_batch_data(input.failed_batch, input.batch_json_save_path)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
batch_data = get_batch_data(input.batchToGenerate, input.batch_json_save_path)
|
batch_data = get_batch_data(input.batch_to_generate, input.batch_json_save_path)
|
||||||
|
|
||||||
batch = input.batchToGenerate
|
batch = input.batch_to_generate
|
||||||
|
|
||||||
generation_time = str(datetime.timedelta(seconds=batch_complete_time))
|
generation_time = str(datetime.timedelta(seconds=batch_complete_time))
|
||||||
|
|
||||||
|
@ -627,11 +627,11 @@ def render_and_save_nfts(input):
|
||||||
if plateform == "Darwin":
|
if plateform == "Darwin":
|
||||||
os.system(f"shutdown /s /t {time}")
|
os.system(f"shutdown /s /t {time}")
|
||||||
|
|
||||||
if input.enableAutoShutdown and not input.specify_timeBool:
|
if input.enable_auto_shutdown and not input.specify_time_bool:
|
||||||
shutdown(0)
|
shutdown(0)
|
||||||
|
|
||||||
# If user selects automatic shutdown and specify time after Batch completion
|
# If user selects automatic shutdown and specify time after Batch completion
|
||||||
if input.enableAutoShutdown and input.specify_timeBool:
|
if input.enable_auto_shutdown and input.specify_time_bool:
|
||||||
hours = (int(input.hours) / 60) / 60
|
hours = (int(input.hours) / 60) / 60
|
||||||
minutes = int(input.minutes) / 60
|
minutes = int(input.minutes) / 60
|
||||||
total_sleep_time = hours + minutes
|
total_sleep_time = hours + minutes
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
import sys
|
import sys
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
def getPythonArgs():
|
|
||||||
|
def get_python_args():
|
||||||
|
|
||||||
argv = sys.argv
|
argv = sys.argv
|
||||||
|
|
||||||
|
@ -15,7 +16,7 @@ def getPythonArgs():
|
||||||
argv = argv[argv.index("--") + 1:] # get all args after "--"
|
argv = argv[argv.index("--") + 1:] # get all args after "--"
|
||||||
|
|
||||||
usage_text = (
|
usage_text = (
|
||||||
"Run Blend_My_NFTs headlessly from the command line\n"
|
"Run Blend_My_NFTs heedlessly from the command line\n"
|
||||||
"usage:\n"
|
"usage:\n"
|
||||||
"blender -background --python <Path to BMNFTs __init__.py> -- --config-file <path to config file>"
|
"blender -background --python <Path to BMNFTs __init__.py> -- --config-file <path to config file>"
|
||||||
)
|
)
|
||||||
|
@ -64,4 +65,4 @@ def getPythonArgs():
|
||||||
help="Overwrite the logic file path in the config file"
|
help="Overwrite the logic file path in the config file"
|
||||||
)
|
)
|
||||||
|
|
||||||
return (parser.parse_args(argv), parser)
|
return parser.parse_args(argv), parser
|
||||||
|
|
|
@ -408,7 +408,7 @@ def raise_error_num_batches_greater_then(num_batches):
|
||||||
# Raise Warnings:
|
# Raise Warnings:
|
||||||
def raise_warning_max_nfts(nfts_per_batch, collection_size):
|
def raise_warning_max_nfts(nfts_per_batch, collection_size):
|
||||||
"""
|
"""
|
||||||
Prints warning if nftsPerBatch is greater than collectionSize.
|
Prints warning if nfts_per_batch is greater than collection_size.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if nfts_per_batch > collection_size:
|
if nfts_per_batch > collection_size:
|
||||||
|
@ -421,7 +421,7 @@ def raise_warning_max_nfts(nfts_per_batch, collection_size):
|
||||||
|
|
||||||
def raise_warning_collection_size(dna_list, collection_size):
|
def raise_warning_collection_size(dna_list, collection_size):
|
||||||
"""
|
"""
|
||||||
Prints warning if BMNFTs cannot generate requested number of NFTs from a given collectionSize.
|
Prints warning if BMNFTs cannot generate requested number of NFTs from a given collection_size.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if len(dna_list) < collection_size:
|
if len(dna_list) < collection_size:
|
||||||
|
|
|
@ -1,21 +1,23 @@
|
||||||
import json
|
|
||||||
import bpy
|
import bpy
|
||||||
|
import json
|
||||||
|
|
||||||
from main import dna_generator, exporter
|
from main import dna_generator, exporter
|
||||||
|
|
||||||
|
# TODO: migrate this code to the exporter.py to simplify render process into one file.
|
||||||
|
|
||||||
def send_To_Record_JSON(input, reverse_order=False):
|
|
||||||
if input.enableLogic:
|
|
||||||
if input.enable_Logic_Json and input.logicFile:
|
|
||||||
input.logicFile = json.load(open(input.logicFile))
|
|
||||||
|
|
||||||
if input.enable_Logic_Json and not input.logicFile:
|
def send_to_record(input, reverse_order=False):
|
||||||
|
if input.enable_logic:
|
||||||
|
if input.enable_logic_json and input.logic_file:
|
||||||
|
input.logic_file = json.load(open(input.logic_file))
|
||||||
|
|
||||||
|
if input.enable_logic_json and not input.logic_file:
|
||||||
print({'ERROR'}, f"No Logic.json file path set. Please set the file path to your Logic.json file.")
|
print({'ERROR'}, f"No Logic.json file path set. Please set the file path to your Logic.json file.")
|
||||||
|
|
||||||
if not input.enable_Logic_Json:
|
if not input.enable_logic_json:
|
||||||
scn = bpy.context.scene
|
scn = bpy.context.scene
|
||||||
if reverse_order:
|
if reverse_order:
|
||||||
input.logicFile = {}
|
input.logic_file = {}
|
||||||
num = 1
|
num = 1
|
||||||
for i in range(scn.logic_fields_index, -1, -1):
|
for i in range(scn.logic_fields_index, -1, -1):
|
||||||
item = scn.logic_fields[i]
|
item = scn.logic_fields[i]
|
||||||
|
@ -23,20 +25,20 @@ def send_To_Record_JSON(input, reverse_order=False):
|
||||||
item_list1 = item.item_list1
|
item_list1 = item.item_list1
|
||||||
rule_type = item.rule_type
|
rule_type = item.rule_type
|
||||||
item_list2 = item.item_list2
|
item_list2 = item.item_list2
|
||||||
input.logicFile[f"Rule-{num}"] = {
|
input.logic_file[f"Rule-{num}"] = {
|
||||||
"IF": item_list1.split(','),
|
"IF": item_list1.split(','),
|
||||||
rule_type: item_list2.split(',')
|
rule_type: item_list2.split(',')
|
||||||
}
|
}
|
||||||
print(rule_type)
|
print(rule_type)
|
||||||
num += 1
|
num += 1
|
||||||
else:
|
else:
|
||||||
input.logicFile = {}
|
input.logic_file = {}
|
||||||
num = 1
|
num = 1
|
||||||
for item in scn.logic_fields:
|
for item in scn.logic_fields:
|
||||||
item_list1 = item.item_list1
|
item_list1 = item.item_list1
|
||||||
rule_type = item.rule_type
|
rule_type = item.rule_type
|
||||||
item_list2 = item.item_list2
|
item_list2 = item.item_list2
|
||||||
input.logicFile[f"Rule-{num}"] = {
|
input.logic_file[f"Rule-{num}"] = {
|
||||||
"IF": item_list1.split(','),
|
"IF": item_list1.split(','),
|
||||||
rule_type: item_list2.split(',')
|
rule_type: item_list2.split(',')
|
||||||
}
|
}
|
||||||
|
@ -44,37 +46,42 @@ def send_To_Record_JSON(input, reverse_order=False):
|
||||||
|
|
||||||
num += 1
|
num += 1
|
||||||
|
|
||||||
dna_generator.send_to_record(input.collectionSize,
|
dna_generator.send_to_record(
|
||||||
input.nftsPerBatch,
|
input.collection_size,
|
||||||
input.save_path,
|
input.nfts_per_batch,
|
||||||
input.enableRarity,
|
input.save_path,
|
||||||
input.enableLogic,
|
input.enable_rarity,
|
||||||
input.logicFile,
|
input.enable_logic,
|
||||||
input.enableMaterials,
|
input.logic_file,
|
||||||
input.materialsFile,
|
input.enable_materials,
|
||||||
input.Blend_My_NFTs_Output,
|
input.materials_file,
|
||||||
input.batch_json_save_path,
|
input.blend_my_nfts_output,
|
||||||
input.enable_debug,
|
input.batch_json_save_path,
|
||||||
)
|
input.enable_debug,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def render_and_save_NFTs(input, reverse_order=False):
|
def render_and_save_nfts(input, reverse_order=False):
|
||||||
if input.enableCustomFields:
|
if input.enable_custom_fields:
|
||||||
scn = bpy.context.scene
|
scn = bpy.context.scene
|
||||||
if reverse_order:
|
if reverse_order:
|
||||||
for i in range(scn.custom_metadata_fields_index, -1, -1):
|
for i in range(scn.custom_metadata_fields_index, -1, -1):
|
||||||
item = scn.custom_metadata_fields[i]
|
item = scn.custom_metadata_fields[i]
|
||||||
if item.field_name in list(input.custom_Fields.keys()):
|
if item.field_name in list(input.custom_fields.keys()):
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f"A duplicate of '{item.field_name}' was found. Please ensure all Custom Metadata field Names are unique.")
|
f"A duplicate of '{item.field_name}' was found. Please ensure all Custom Metadata field Names "
|
||||||
|
f"are unique."
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
input.custom_Fields[item.field_name] = item.field_value
|
input.custom_fields[item.field_name] = item.field_value
|
||||||
else:
|
else:
|
||||||
for item in scn.custom_metadata_fields:
|
for item in scn.custom_metadata_fields:
|
||||||
if item.field_name in list(input.custom_Fields.keys()):
|
if item.field_name in list(input.custom_fields.keys()):
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f"A duplicate of '{item.field_name}' was found. Please ensure all Custom Metadata field Names are unique.")
|
f"A duplicate of '{item.field_name}' was found. Please ensure all Custom Metadata field Names "
|
||||||
|
f"are unique."
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
input.custom_Fields[item.field_name] = item.field_value
|
input.custom_fields[item.field_name] = item.field_value
|
||||||
|
|
||||||
Exporter.render_and_save_nfts(input)
|
exporter.render_and_save_nfts(input)
|
||||||
|
|
155
main/logic.py
155
main/logic.py
|
@ -1,19 +1,19 @@
|
||||||
# Purpose:
|
# Purpose:
|
||||||
# The purpose of this file is to add logic and rules to the DNA that are sent to the NFTRecord.json file in dna_generator.py
|
# The purpose of this file is to add logic and rules to the DNA that are sent to the NFTRecord.json file in
|
||||||
|
# dna_generator.py
|
||||||
|
|
||||||
import bpy
|
|
||||||
import random
|
import random
|
||||||
import collections
|
import collections
|
||||||
|
|
||||||
from .helpers import TextColors, removeList, remove_file_by_extension, save_result
|
from .helpers import TextColors
|
||||||
|
|
||||||
|
|
||||||
def reconstructDNA(deconstructedDNA):
|
def reconstruct_dna(deconstructed_dna):
|
||||||
reconstructed_DNA = ""
|
reconstructed_dna = ""
|
||||||
for a in deconstructedDNA:
|
for a in deconstructed_dna:
|
||||||
num = "-" + str(a)
|
num = "-" + str(a)
|
||||||
reconstructed_DNA += num
|
reconstructed_dna += num
|
||||||
return ''.join(reconstructed_DNA.split('-', 1))
|
return ''.join(reconstructed_dna.split('-', 1))
|
||||||
|
|
||||||
|
|
||||||
def get_var_info(variant, hierarchy):
|
def get_var_info(variant, hierarchy):
|
||||||
|
@ -33,11 +33,11 @@ def get_var_info(variant, hierarchy):
|
||||||
return [name, order_number, rarity_number, attribute, attribute_index] # list of Var info sent back
|
return [name, order_number, rarity_number, attribute, attribute_index] # list of Var info sent back
|
||||||
|
|
||||||
|
|
||||||
def apply_rules_to_dna(hierarchy, deconstructed_DNA, if_dict, result_dict, result_dict_type, enableRarity):
|
def apply_rules_to_dna(hierarchy, deconstructed_dna, if_dict, result_dict, result_dict_type, enable_rarity):
|
||||||
# Check if Variants in if_dict are in deconstructed_DNA, if so return if_list_selected = True:
|
# Check if Variants in if_dict are in deconstructed_dna, if so return if_list_selected = True:
|
||||||
if_list_selected = False
|
if_list_selected = False
|
||||||
for a in deconstructed_DNA:
|
for a in deconstructed_dna:
|
||||||
attribute_index = deconstructed_DNA.index(a)
|
attribute_index = deconstructed_dna.index(a)
|
||||||
attribute = list(hierarchy.keys())[attribute_index]
|
attribute = list(hierarchy.keys())[attribute_index]
|
||||||
|
|
||||||
for b in hierarchy[attribute]:
|
for b in hierarchy[attribute]:
|
||||||
|
@ -49,23 +49,23 @@ def apply_rules_to_dna(hierarchy, deconstructed_DNA, if_dict, result_dict, resul
|
||||||
if_list_selected = True
|
if_list_selected = True
|
||||||
|
|
||||||
# Apply changes in accordance to Variants in 'result_dict' and 'if_list_selected' bool above:
|
# Apply changes in accordance to Variants in 'result_dict' and 'if_list_selected' bool above:
|
||||||
for a in deconstructed_DNA:
|
for a in deconstructed_dna:
|
||||||
attribute_index = deconstructed_DNA.index(a)
|
attribute_index = deconstructed_dna.index(a)
|
||||||
attribute = list(hierarchy.keys())[attribute_index]
|
attribute = list(hierarchy.keys())[attribute_index]
|
||||||
|
|
||||||
if attribute in result_dict: # Check if Attribute from DNA is in 'result_dict'
|
if attribute in result_dict: # Check if Attribute from DNA is in 'result_dict'
|
||||||
|
|
||||||
# If 'a' is a full Attribute and Variants in if_dict not selected, set 'a' to empty (0):
|
# If 'a' is a full Attribute and Variants in if_dict not selected, set 'a' to empty (0):
|
||||||
if list(result_dict[attribute].keys()) == list(hierarchy[attribute].keys()) and not if_list_selected:
|
if list(result_dict[attribute].keys()) == list(hierarchy[attribute].keys()) and not if_list_selected:
|
||||||
deconstructed_DNA[attribute_index] = "0"
|
deconstructed_dna[attribute_index] = "0"
|
||||||
|
|
||||||
# If 'a' is a full Attribute and result_dict_type = "NOT", set 'a' to empty (0):
|
# If 'a' is a full Attribute and result_dict_type = "NOT", set 'a' to empty (0):
|
||||||
if list(result_dict[attribute].keys()) == list(
|
if list(result_dict[attribute].keys()) == list(
|
||||||
hierarchy[attribute].keys()) and if_list_selected and result_dict_type == "NOT":
|
hierarchy[attribute].keys()) and if_list_selected and result_dict_type == "NOT":
|
||||||
deconstructed_DNA[attribute_index] = "0"
|
deconstructed_dna[attribute_index] = "0"
|
||||||
|
|
||||||
# If Variants in if_dict are selected, set each attribute in 'result_dict' to a random or rarity selected Variant from
|
# If Variants in if_dict are selected, set each attribute in 'result_dict' to a random or rarity selected Variant
|
||||||
# 'result_dict[attribute]' variant_list:
|
# from 'result_dict[attribute]' variant_list:
|
||||||
if if_list_selected:
|
if if_list_selected:
|
||||||
|
|
||||||
# Invert 'items_returned' if 'NOT' rule is selected:
|
# Invert 'items_returned' if 'NOT' rule is selected:
|
||||||
|
@ -91,60 +91,60 @@ def apply_rules_to_dna(hierarchy, deconstructed_DNA, if_dict, result_dict, resul
|
||||||
|
|
||||||
if attribute in result_dict: # Check if Attribute from DNA is in 'then_dict'
|
if attribute in result_dict: # Check if Attribute from DNA is in 'then_dict'
|
||||||
|
|
||||||
number_List_Of_i = []
|
number_list_of_i = []
|
||||||
rarity_List_Of_i = []
|
rarity_list_of_i = []
|
||||||
ifZeroBool = None
|
if_zero_bool = None
|
||||||
variantNum = None
|
variant_num = None
|
||||||
|
|
||||||
for b in variant_list:
|
for b in variant_list:
|
||||||
number = b.split("_")[1]
|
number = b.split("_")[1]
|
||||||
rarity = b.split("_")[2]
|
rarity = b.split("_")[2]
|
||||||
|
|
||||||
number_List_Of_i.append(int(number))
|
number_list_of_i.append(int(number))
|
||||||
rarity_List_Of_i.append(float(rarity))
|
rarity_list_of_i.append(float(rarity))
|
||||||
|
|
||||||
for b in rarity_List_Of_i:
|
for b in rarity_list_of_i:
|
||||||
if b == 0:
|
if b == 0:
|
||||||
ifZeroBool = True
|
if_zero_bool = True
|
||||||
elif b != 0:
|
elif b != 0:
|
||||||
ifZeroBool = False
|
if_zero_bool = False
|
||||||
|
|
||||||
if enableRarity:
|
if enable_rarity:
|
||||||
try:
|
try:
|
||||||
if ifZeroBool:
|
if if_zero_bool:
|
||||||
variantNum = random.choices(number_List_Of_i, k=1)
|
variant_num = random.choices(number_list_of_i, k=1)
|
||||||
elif not ifZeroBool:
|
elif not if_zero_bool:
|
||||||
variantNum = random.choices(number_List_Of_i, weights=rarity_List_Of_i, k=1)
|
variant_num = random.choices(number_list_of_i, weights=rarity_list_of_i, k=1)
|
||||||
except IndexError:
|
except IndexError:
|
||||||
raise IndexError(
|
raise IndexError(
|
||||||
f"\n{TextColors.ERROR}Blend_My_NFTs Error:\n"
|
f"\n{TextColors.ERROR}Blend_My_NFTs Error:\n"
|
||||||
f"An issue was found within the Attribute collection '{a}'. For more information on Blend_My_NFTs compatible scenes, "
|
f"An issue was found within the Attribute collection '{a}'. For more information on "
|
||||||
f"see:\n{TextColors.RESET}"
|
f"Blend_My_NFTs compatible scenes, see:\n{TextColors.RESET}"
|
||||||
f"https://github.com/torrinworx/Blend_My_NFTs#blender-file-organization-and-structure\n"
|
f"https://github.com/torrinworx/Blend_My_NFTs#blender-file-organization-and-structure\n"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
variantNum = random.choices(number_List_Of_i, k=1)
|
variant_num = random.choices(number_list_of_i, k=1)
|
||||||
except IndexError:
|
except IndexError:
|
||||||
raise IndexError(
|
raise IndexError(
|
||||||
f"\n{TextColors.ERROR}Blend_My_NFTs Error:\n"
|
f"\n{TextColors.ERROR}Blend_My_NFTs Error:\n"
|
||||||
f"An issue was found within the Attribute collection '{a}'. For more information on Blend_My_NFTs compatible scenes, "
|
f"An issue was found within the Attribute collection '{a}'. For more information on "
|
||||||
f"see:\n{TextColors.RESET}"
|
f"Blend_My_NFTs compatible scenes, see:\n{TextColors.RESET}"
|
||||||
f"https://github.com/torrinworx/Blend_My_NFTs#blender-file-organization-and-structure\n"
|
f"https://github.com/torrinworx/Blend_My_NFTs#blender-file-organization-and-structure\n"
|
||||||
)
|
)
|
||||||
deconstructed_DNA[int(attribute_index)] = str(variantNum[0])
|
deconstructed_dna[int(attribute_index)] = str(variant_num[0])
|
||||||
|
|
||||||
return deconstructed_DNA
|
return deconstructed_dna
|
||||||
|
|
||||||
|
|
||||||
def get_rule_break_type(hierarchy, deconstructed_DNA, if_dict, result_dict, result_dict_type):
|
def get_rule_break_type(hierarchy, deconstructed_dna, if_dict, result_dict, result_dict_type):
|
||||||
# Check if Variants in 'if_dict' found in deconstructed_DNA:
|
# Check if Variants in 'if_dict' found in deconstructed_dna:
|
||||||
if_bool = False # True if Variant in 'deconstructed_DNA' found in 'if_dict'
|
if_bool = False # True if Variant in 'deconstructed_dna' found in 'if_dict'
|
||||||
for a in if_dict: # Attribute in 'if_dict'
|
for a in if_dict: # Attribute in 'if_dict'
|
||||||
for b in if_dict[a]: # Variant in if_dict[Attribute]
|
for b in if_dict[a]: # Variant in if_dict[Attribute]
|
||||||
var_order_num = str(if_dict[a][b][1]) # Order number of 'b' (Variant)
|
var_order_num = str(if_dict[a][b][1]) # Order number of 'b' (Variant)
|
||||||
dna_order_num = str(
|
dna_order_num = str(
|
||||||
deconstructed_DNA[if_dict[a][b][4]]) # Order Number of 'b's attribute in deconstructed_DNA
|
deconstructed_dna[if_dict[a][b][4]]) # Order Number of 'b's attribute in deconstructed_dna
|
||||||
|
|
||||||
if var_order_num == dna_order_num: # If DNA selected Variants found inside IF list variants:
|
if var_order_num == dna_order_num: # If DNA selected Variants found inside IF list variants:
|
||||||
if_bool = True
|
if_bool = True
|
||||||
|
@ -153,14 +153,14 @@ def get_rule_break_type(hierarchy, deconstructed_DNA, if_dict, result_dict, resu
|
||||||
continue
|
continue
|
||||||
break
|
break
|
||||||
|
|
||||||
# Check if Variants in 'result_dict' found in deconstructed_DNA:
|
# Check if Variants in 'result_dict' found in deconstructed_dna:
|
||||||
full_att_bool = False
|
full_att_bool = False
|
||||||
result_bool = False # True if Variant in 'deconstructed_DNA' found in 'result_dict'
|
result_bool = False # True if Variant in 'deconstructed_dna' found in 'result_dict'
|
||||||
for a in result_dict: # Attribute in 'result_dict'
|
for a in result_dict: # Attribute in 'result_dict'
|
||||||
for b in result_dict[a]: # Variant in if_dict[Attribute]
|
for b in result_dict[a]: # Variant in if_dict[Attribute]
|
||||||
var_order_num = str(result_dict[a][b][1]) # Order number of 'b' (Variant)
|
var_order_num = str(result_dict[a][b][1]) # Order number of 'b' (Variant)
|
||||||
dna_order_num = str(
|
dna_order_num = str(
|
||||||
deconstructed_DNA[result_dict[a][b][4]]) # Order Number of 'b's attribute in deconstructed_DNA
|
deconstructed_dna[result_dict[a][b][4]]) # Order Number of 'b's attribute in deconstructed_dna
|
||||||
if var_order_num == dna_order_num: # If DNA selected Variants found inside THEN list variants:
|
if var_order_num == dna_order_num: # If DNA selected Variants found inside THEN list variants:
|
||||||
if list(result_dict[a].keys()) == list(hierarchy[a].keys()):
|
if list(result_dict[a].keys()) == list(hierarchy[a].keys()):
|
||||||
full_att_bool = True
|
full_att_bool = True
|
||||||
|
@ -173,20 +173,20 @@ def get_rule_break_type(hierarchy, deconstructed_DNA, if_dict, result_dict, resu
|
||||||
# Rule Bool return summary:
|
# Rule Bool return summary:
|
||||||
violates_rule = False
|
violates_rule = False
|
||||||
|
|
||||||
# If Variants in 'if_dict' found in deconstructed_DNA and Variants in 'result_dict' not found in deconstructed_DNA:
|
# If Variants in 'if_dict' found in deconstructed_dna and Variants in 'result_dict' not found in deconstructed_dna:
|
||||||
if if_bool and not result_bool:
|
if if_bool and not result_bool:
|
||||||
violates_rule = True
|
violates_rule = True
|
||||||
|
|
||||||
elif if_bool and result_bool and result_dict_type == "NOT":
|
elif if_bool and result_bool and result_dict_type == "NOT":
|
||||||
violates_rule = True
|
violates_rule = True
|
||||||
|
|
||||||
# If Variants in 'if_dict' not found in deconstructed_DNA, and 'result_dict' variants are found in deconstructed_DNA,
|
# If Variants in 'if_dict' not found in deconstructed_dna, and 'result_dict' variants are found in
|
||||||
# and they are a part of a full Attribute in 'then_dict'
|
# deconstructed_dna, and they are a part of a full Attribute in 'then_dict'
|
||||||
elif not if_bool and result_bool and full_att_bool:
|
elif not if_bool and result_bool and full_att_bool:
|
||||||
violates_rule = True
|
violates_rule = True
|
||||||
|
|
||||||
# If Variants in 'if_dict' not found in deconstructed_DNA, but Variants in 'then_dict' are found in deconstructed_DNA,
|
# If Variants in 'if_dict' not found in deconstructed_dna, but Variants in 'then_dict' are found in
|
||||||
# and don't make up a full Attribute:
|
# deconstructed_dna, and don't make up a full Attribute:
|
||||||
# elif not if_bool and result_bool and not full_att_bool:
|
# elif not if_bool and result_bool and not full_att_bool:
|
||||||
# violates_rule = False
|
# violates_rule = False
|
||||||
|
|
||||||
|
@ -252,41 +252,50 @@ def create_dicts(hierarchy, rule_list_items, result_dict_type):
|
||||||
return dict(items_returned)
|
return dict(items_returned)
|
||||||
|
|
||||||
|
|
||||||
def logicafyDNAsingle(hierarchy, singleDNA, logicFile, enableRarity, enableMaterials):
|
def logicafy_dna_single(hierarchy, single_dna, logic_file, enable_rarity):
|
||||||
deconstructed_DNA = singleDNA.split("-")
|
deconstructed_dna = single_dna.split("-")
|
||||||
didReconstruct = True
|
did_reconstruct = True
|
||||||
originalDNA = str(singleDNA)
|
original_dna = str(single_dna)
|
||||||
|
|
||||||
while didReconstruct:
|
while did_reconstruct:
|
||||||
didReconstruct = False
|
did_reconstruct = False
|
||||||
for rule in logicFile:
|
for rule in logic_file:
|
||||||
# Items from 'IF' key for a given rule
|
# Items from 'IF' key for a given rule
|
||||||
if_dict = create_dicts(hierarchy, logicFile[rule]["IF"], "IF")
|
if_dict = create_dicts(hierarchy, logic_file[rule]["IF"], "IF")
|
||||||
|
|
||||||
result_dict_type = ""
|
result_dict_type = ""
|
||||||
if "THEN" in logicFile[rule]:
|
if "THEN" in logic_file[rule]:
|
||||||
result_dict_type = "THEN"
|
result_dict_type = "THEN"
|
||||||
|
|
||||||
if "NOT" in logicFile[rule]:
|
if "NOT" in logic_file[rule]:
|
||||||
result_dict_type = "NOT"
|
result_dict_type = "NOT"
|
||||||
|
|
||||||
result_dict = create_dicts(hierarchy, logicFile[rule][result_dict_type], result_dict_type)
|
result_dict = create_dicts(hierarchy, logic_file[rule][result_dict_type], result_dict_type)
|
||||||
|
|
||||||
# Change 'then_bool' to 'result_bool'
|
# Change 'then_bool' to 'result_bool'
|
||||||
violates_rule, if_bool, then_bool, full_att_bool = get_rule_break_type(hierarchy, deconstructed_DNA,
|
violates_rule, if_bool, then_bool, full_att_bool = get_rule_break_type(
|
||||||
if_dict, result_dict,
|
hierarchy,
|
||||||
result_dict_type)
|
deconstructed_dna,
|
||||||
|
if_dict,
|
||||||
|
result_dict,
|
||||||
|
result_dict_type,
|
||||||
|
)
|
||||||
if violates_rule:
|
if violates_rule:
|
||||||
# print(f"======={deconstructed_DNA} VIOLATES RULE======")
|
# print(f"======={deconstructed_dna} VIOLATES RULE======")
|
||||||
|
|
||||||
deconstructed_DNA = apply_rules_to_dna(
|
deconstructed_dna = apply_rules_to_dna(
|
||||||
hierarchy, deconstructed_DNA, if_dict, result_dict, result_dict_type, enableRarity
|
hierarchy,
|
||||||
|
deconstructed_dna,
|
||||||
|
if_dict,
|
||||||
|
result_dict,
|
||||||
|
result_dict_type,
|
||||||
|
enable_rarity
|
||||||
)
|
)
|
||||||
|
|
||||||
newDNA = reconstructDNA(deconstructed_DNA)
|
new_dna = reconstruct_dna(deconstructed_dna)
|
||||||
if newDNA != originalDNA:
|
if new_dna != original_dna:
|
||||||
originalDNA = str(newDNA)
|
original_dna = str(new_dna)
|
||||||
didReconstruct = True
|
did_reconstruct = True
|
||||||
break
|
break
|
||||||
|
|
||||||
return str(reconstructDNA(deconstructed_DNA))
|
return str(reconstruct_dna(deconstructed_dna))
|
||||||
|
|
|
@ -3,62 +3,61 @@
|
||||||
# also specified in the .json file. The Materialized DNA is then returned in the following format: 1-1-1:1-1-1
|
# also specified in the .json file. The Materialized DNA is then returned in the following format: 1-1-1:1-1-1
|
||||||
# Where the numbers right of the ":" are the material numbers applied to the respective Variants to the left of the ":"
|
# Where the numbers right of the ":" are the material numbers applied to the respective Variants to the left of the ":"
|
||||||
|
|
||||||
import bpy
|
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import random
|
import random
|
||||||
from .helpers import TextColors
|
from .helpers import TextColors
|
||||||
|
|
||||||
|
|
||||||
def select_material(materialList, variant, enableRarity):
|
def select_material(material_list, variant, enable_rarity):
|
||||||
"""Selects a material from a passed material list. """
|
"""Selects a material from a passed material list. """
|
||||||
material_List_Of_i = [] # List of Material names instead of order numbers
|
material_list_of_i = [] # List of Material names instead of order numbers
|
||||||
rarity_List_Of_i = []
|
rarity_list_of_i = []
|
||||||
ifZeroBool = None
|
if_zero_bool = None
|
||||||
|
|
||||||
for material in materialList:
|
for material in material_list:
|
||||||
# Material Order Number comes from index in the Material List in materials.json for a given Variant.
|
# 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 = list(material_list.keys()).index(material)
|
||||||
|
|
||||||
material_List_Of_i.append(material)
|
material_list_of_i.append(material)
|
||||||
|
|
||||||
material_rarity_percent = materialList[material]
|
material_rarity_percent = material_list[material]
|
||||||
rarity_List_Of_i.append(float(material_rarity_percent))
|
rarity_list_of_i.append(float(material_rarity_percent))
|
||||||
|
|
||||||
# print(f"MATERIAL_LIST_OF_I:{material_List_Of_i}")
|
# print(f"MATERIAL_LIST_OF_I:{material_list_of_i}")
|
||||||
# print(f"RARITY_LIST_OF_I:{rarity_List_Of_i}")
|
# print(f"RARITY_LIST_OF_I:{rarity_list_of_i}")
|
||||||
|
|
||||||
for b in rarity_List_Of_i:
|
for b in rarity_list_of_i:
|
||||||
if b == 0:
|
if b == 0:
|
||||||
ifZeroBool = True
|
if_zero_bool = True
|
||||||
elif b != 0:
|
elif b != 0:
|
||||||
ifZeroBool = False
|
if_zero_bool = False
|
||||||
|
|
||||||
if enableRarity:
|
if enable_rarity:
|
||||||
try:
|
try:
|
||||||
if ifZeroBool:
|
if if_zero_bool:
|
||||||
selected_material = random.choices(material_List_Of_i, k=1)
|
selected_material = random.choices(material_list_of_i, k=1)
|
||||||
elif not ifZeroBool:
|
elif not if_zero_bool:
|
||||||
selected_material = random.choices(material_List_Of_i, weights=rarity_List_Of_i, k=1)
|
selected_material = random.choices(material_list_of_i, weights=rarity_list_of_i, k=1)
|
||||||
except IndexError:
|
except IndexError:
|
||||||
raise IndexError(
|
raise IndexError(
|
||||||
f"\n{TextColors.ERROR}Blend_My_NFTs Error:\n"
|
f"\n{TextColors.ERROR}Blend_My_NFTs Error:\n"
|
||||||
f"An issue was found within the Material List of the Variant collection '{variant}'. For more information on Blend_My_NFTs compatible scenes, "
|
f"An issue was found within the Material List of the Variant collection '{variant}'. For more "
|
||||||
f"see:\n{TextColors.RESET}"
|
f"information on Blend_My_NFTs compatible scenes, see:\n{TextColors.RESET}"
|
||||||
f"https://github.com/torrinworx/Blend_My_NFTs#blender-file-organization-and-structure\n"
|
f"https://github.com/torrinworx/Blend_My_NFTs#blender-file-organization-and-structure\n"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
selected_material = random.choices(material_List_Of_i, k=1)
|
selected_material = random.choices(material_list_of_i, k=1)
|
||||||
except IndexError:
|
except IndexError:
|
||||||
raise IndexError(
|
raise IndexError(
|
||||||
f"\n{TextColors.ERROR}Blend_My_NFTs Error:\n"
|
f"\n{TextColors.ERROR}Blend_My_NFTs Error:\n"
|
||||||
f"An issue was found within the Material List of the Variant collection '{variant}'. For more information on Blend_My_NFTs compatible scenes, "
|
f"An issue was found within the Material List of the Variant collection '{variant}'. For more "
|
||||||
f"see:\n{TextColors.RESET}"
|
f"information on Blend_My_NFTs compatible scenes, see:\n{TextColors.RESET}"
|
||||||
f"https://github.com/torrinworx/Blend_My_NFTs#blender-file-organization-and-structure\n"
|
f"https://github.com/torrinworx/Blend_My_NFTs#blender-file-organization-and-structure\n"
|
||||||
)
|
)
|
||||||
|
|
||||||
return selected_material[0], materialList
|
return selected_material[0], material_list
|
||||||
|
|
||||||
|
|
||||||
def get_variant_att_index(variant, hierarchy):
|
def get_variant_att_index(variant, hierarchy):
|
||||||
variant_attribute = None
|
variant_attribute = None
|
||||||
|
@ -72,26 +71,28 @@ def get_variant_att_index(variant, hierarchy):
|
||||||
variant_order_num = variant.split("_")[1]
|
variant_order_num = variant.split("_")[1]
|
||||||
return attribute_index, variant_order_num
|
return attribute_index, variant_order_num
|
||||||
|
|
||||||
def match_DNA_to_Variant(hierarchy, singleDNA):
|
|
||||||
|
def match_dna_to_variant(hierarchy, single_dna):
|
||||||
"""
|
"""
|
||||||
Matches each DNA number separated by "-" to its attribute, then its variant.
|
Matches each DNA number separated by "-" to its attribute, then its variant.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
listAttributes = list(hierarchy.keys())
|
list_attributes = list(hierarchy.keys())
|
||||||
listDnaDecunstructed = singleDNA.split('-')
|
list_dna_decunstructed = single_dna.split('-')
|
||||||
dnaDictionary = {}
|
dna_dictionary = {}
|
||||||
|
|
||||||
for i, j in zip(listAttributes, listDnaDecunstructed):
|
for i, j in zip(list_attributes, list_dna_decunstructed):
|
||||||
dnaDictionary[i] = j
|
dna_dictionary[i] = j
|
||||||
|
|
||||||
for x in dnaDictionary:
|
for x in dna_dictionary:
|
||||||
for k in hierarchy[x]:
|
for k in hierarchy[x]:
|
||||||
kNum = hierarchy[x][k]["number"]
|
k_num = hierarchy[x][k]["number"]
|
||||||
if kNum == dnaDictionary[x]:
|
if k_num == dna_dictionary[x]:
|
||||||
dnaDictionary.update({x: k})
|
dna_dictionary.update({x: k})
|
||||||
return dnaDictionary
|
return dna_dictionary
|
||||||
|
|
||||||
def apply_materials(hierarchy, singleDNA, materialsFile, enableRarity):
|
|
||||||
|
def apply_materials(hierarchy, single_dna, materials_file, enable_rarity):
|
||||||
"""
|
"""
|
||||||
DNA with applied material example: "1-1:1-1" <Normal DNA>:<Selected Material for each Variant>
|
DNA with applied material example: "1-1:1-1" <Normal DNA>:<Selected Material for each Variant>
|
||||||
|
|
||||||
|
@ -99,20 +100,23 @@ def apply_materials(hierarchy, singleDNA, materialsFile, enableRarity):
|
||||||
list in the Variant_Material.json file.
|
list in the Variant_Material.json file.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
singleDNADict = match_DNA_to_Variant(hierarchy, singleDNA)
|
single_dna_dict = match_dna_to_variant(hierarchy, single_dna)
|
||||||
materialsFile = json.load(open(materialsFile))
|
materials_file = json.load(open(materials_file))
|
||||||
deconstructed_MaterialDNA = {}
|
deconstructed_material_dna = {}
|
||||||
|
|
||||||
for a in singleDNADict:
|
for a in single_dna_dict:
|
||||||
complete = False
|
complete = False
|
||||||
for b in materialsFile:
|
for b in materials_file:
|
||||||
if singleDNADict[a] == b:
|
if single_dna_dict[a] == b:
|
||||||
material_name, materialList, = select_material(materialsFile[b]['Material List'], b, enableRarity)
|
material_name, material_list, = select_material(materials_file[b]['Material List'], b, enable_rarity)
|
||||||
material_order_num = list(materialList.keys()).index(material_name) # Gets the Order Number of the Material
|
|
||||||
deconstructed_MaterialDNA[a] = str(material_order_num + 1)
|
# Gets the Order Number of the Material
|
||||||
|
material_order_num = list(material_list.keys()).index(material_name)
|
||||||
|
|
||||||
|
deconstructed_material_dna[a] = str(material_order_num + 1)
|
||||||
complete = True
|
complete = True
|
||||||
if not complete:
|
if not complete:
|
||||||
deconstructed_MaterialDNA[a] = "0"
|
deconstructed_material_dna[a] = "0"
|
||||||
|
|
||||||
# This section is now incorrect and needs updating:
|
# This section is now incorrect and needs updating:
|
||||||
|
|
||||||
|
@ -121,14 +125,14 @@ def apply_materials(hierarchy, singleDNA, materialsFile, enableRarity):
|
||||||
# Attribute 'B' = 1, 'C' = 2, 'D' = 3, etc. For each pair you want to equal another, add its number it to this list:
|
# Attribute 'B' = 1, 'C' = 2, 'D' = 3, etc. For each pair you want to equal another, add its number it to this list:
|
||||||
# synced_material_attributes = [1, 2]
|
# synced_material_attributes = [1, 2]
|
||||||
#
|
#
|
||||||
# first_mat = deconstructed_MaterialDNA[synced_material_attributes[0]]
|
# first_mat = deconstructed_material_dna[synced_material_attributes[0]]
|
||||||
# for i in synced_material_attributes:
|
# for i in synced_material_attributes:
|
||||||
# deconstructed_MaterialDNA[i] = first_mat
|
# deconstructed_material_dna[i] = first_mat
|
||||||
|
|
||||||
material_DNA = ""
|
material_dna = ""
|
||||||
for a in deconstructed_MaterialDNA:
|
for a in deconstructed_material_dna:
|
||||||
num = "-" + str(deconstructed_MaterialDNA[a])
|
num = "-" + str(deconstructed_material_dna[a])
|
||||||
material_DNA += num
|
material_dna += num
|
||||||
material_DNA = ''.join(material_DNA.split('-', 1))
|
material_dna = ''.join(material_dna.split('-', 1))
|
||||||
|
|
||||||
return f"{singleDNA}:{material_DNA}"
|
return f"{single_dna}:{material_dna}"
|
||||||
|
|
|
@ -3,26 +3,37 @@
|
||||||
# https://discord.gg/QTT7dzcuVs
|
# https://discord.gg/QTT7dzcuVs
|
||||||
|
|
||||||
# Purpose:
|
# Purpose:
|
||||||
# This file returns the specified meta data format to the exporter.py for a given NFT DNA.
|
# This file returns the specified metadata format to the exporter.py for a given NFT DNA.
|
||||||
|
|
||||||
import bpy
|
|
||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
|
|
||||||
def sendMetaDataToJson(metaDataDict, save_path, file_name):
|
|
||||||
jsonMetaData = json.dumps(metaDataDict, indent=1, ensure_ascii=True)
|
|
||||||
with open(os.path.join(save_path, f"{file_name}.json"), 'w') as outfile:
|
|
||||||
outfile.write(jsonMetaData + '\n')
|
|
||||||
|
|
||||||
def stripNums(variant):
|
def send_metadata_to_json(meta_data_dict, save_path, file_name):
|
||||||
|
json_metadata = json.dumps(meta_data_dict, indent=1, ensure_ascii=True)
|
||||||
|
with open(os.path.join(save_path, f"{file_name}.json"), 'w') as outfile:
|
||||||
|
outfile.write(json_metadata + '\n')
|
||||||
|
|
||||||
|
|
||||||
|
def strip_nums(variant):
|
||||||
variant = str(variant).split('_')[0]
|
variant = str(variant).split('_')[0]
|
||||||
return variant
|
return variant
|
||||||
|
|
||||||
# Cardano Template
|
|
||||||
def createCardanoMetadata(name, Order_Num, NFT_DNA, NFT_Variants, Material_Attributes,
|
|
||||||
custom_Fields, enableCustomFields, cardano_description, cardanoMetadataPath):
|
|
||||||
|
|
||||||
metaDataDictCardano = {"721": {
|
# Cardano Template
|
||||||
|
def create_cardano_metadata(
|
||||||
|
name,
|
||||||
|
order_num,
|
||||||
|
nft_dna,
|
||||||
|
nft_variants,
|
||||||
|
material_attributes,
|
||||||
|
custom_fields,
|
||||||
|
enable_custom_fields,
|
||||||
|
cardano_description,
|
||||||
|
cardano_metadata_path
|
||||||
|
):
|
||||||
|
|
||||||
|
meta_data_dict_cardano = {"721": {
|
||||||
"<policy_id>": {
|
"<policy_id>": {
|
||||||
name: {
|
name: {
|
||||||
"name": name,
|
"name": name,
|
||||||
|
@ -35,73 +46,107 @@ def createCardanoMetadata(name, Order_Num, NFT_DNA, NFT_Variants, Material_Attri
|
||||||
}}
|
}}
|
||||||
|
|
||||||
# Variants and Attributes:
|
# Variants and Attributes:
|
||||||
for i in NFT_Variants:
|
for i in nft_variants:
|
||||||
metaDataDictCardano["721"]["<policy_id>"][name][i] = stripNums(NFT_Variants[i])
|
meta_data_dict_cardano["721"]["<policy_id>"][name][i] = strip_nums(nft_variants[i])
|
||||||
|
|
||||||
# Material Variants and Attributes:
|
# Material Variants and Attributes:
|
||||||
for i in Material_Attributes:
|
for i in material_attributes:
|
||||||
metaDataDictCardano["721"]["<policy_id>"][name][i] = Material_Attributes[i]
|
meta_data_dict_cardano["721"]["<policy_id>"][name][i] = material_attributes[i]
|
||||||
|
|
||||||
# Custom Fields:
|
# Custom Fields:
|
||||||
if enableCustomFields:
|
if enable_custom_fields:
|
||||||
for i in custom_Fields:
|
for i in custom_fields:
|
||||||
metaDataDictCardano["721"]["<policy_id>"][name][i] = custom_Fields[i]
|
meta_data_dict_cardano["721"]["<policy_id>"][name][i] = custom_fields[i]
|
||||||
|
|
||||||
sendMetaDataToJson(metaDataDictCardano, cardanoMetadataPath, name)
|
send_metadata_to_json(
|
||||||
|
meta_data_dict_cardano,
|
||||||
|
cardano_metadata_path,
|
||||||
|
name
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# Solana Template
|
# Solana Template
|
||||||
def createSolanaMetaData(name, Order_Num, NFT_DNA, NFT_Variants, Material_Attributes, custom_Fields, enableCustomFields,
|
def createSolanaMetaData(
|
||||||
solana_description, solanaMetadataPath):
|
name,
|
||||||
metaDataDictSolana = {"name": name, "symbol": "", "description": solana_description, "seller_fee_basis_points": None,
|
order_num,
|
||||||
"image": "", "animation_url": "", "external_url": ""}
|
nft_dna,
|
||||||
|
nft_variants,
|
||||||
|
material_attributes,
|
||||||
|
custom_fields,
|
||||||
|
enable_custom_fields,
|
||||||
|
solana_description,
|
||||||
|
solana_metadata_path
|
||||||
|
):
|
||||||
|
metadata_dict_solana = {
|
||||||
|
"name": name,
|
||||||
|
"symbol": "",
|
||||||
|
"description": solana_description,
|
||||||
|
"seller_fee_basis_points": None,
|
||||||
|
"image": "",
|
||||||
|
"animation_url": "",
|
||||||
|
"external_url": ""
|
||||||
|
}
|
||||||
|
|
||||||
attributes = []
|
attributes = []
|
||||||
|
|
||||||
# Variant and Attributes:
|
# Variant and Attributes:
|
||||||
for i in NFT_Variants:
|
for i in nft_variants:
|
||||||
dictionary = {
|
dictionary = {
|
||||||
"trait_type": i,
|
"trait_type": i,
|
||||||
"value": stripNums(NFT_Variants[i])
|
"value": strip_nums(nft_variants[i])
|
||||||
}
|
}
|
||||||
attributes.append(dictionary)
|
attributes.append(dictionary)
|
||||||
|
|
||||||
# Material Variants and Attributes:
|
# Material Variants and Attributes:
|
||||||
for i in Material_Attributes:
|
for i in material_attributes:
|
||||||
dictionary = {
|
dictionary = {
|
||||||
"trait_type": i,
|
"trait_type": i,
|
||||||
"value": Material_Attributes[i]
|
"value": material_attributes[i]
|
||||||
}
|
}
|
||||||
attributes.append(dictionary)
|
attributes.append(dictionary)
|
||||||
|
|
||||||
# Custom Fields:
|
# Custom Fields:
|
||||||
if enableCustomFields:
|
if enable_custom_fields:
|
||||||
for i in custom_Fields:
|
for i in custom_fields:
|
||||||
dictionary = {
|
dictionary = {
|
||||||
"trait_type": i,
|
"trait_type": i,
|
||||||
"value": custom_Fields[i]
|
"value": custom_fields[i]
|
||||||
}
|
}
|
||||||
attributes.append(dictionary)
|
attributes.append(dictionary)
|
||||||
|
|
||||||
metaDataDictSolana["attributes"] = attributes
|
metadata_dict_solana["attributes"] = attributes
|
||||||
metaDataDictSolana["collection"] = {
|
metadata_dict_solana["collection"] = {
|
||||||
"name": "",
|
"name": "",
|
||||||
"family": ""
|
"family": ""
|
||||||
}
|
}
|
||||||
|
|
||||||
metaDataDictSolana["properties"] = {
|
metadata_dict_solana["properties"] = {
|
||||||
"files": [{"uri": "", "type": ""}],
|
"files": [{"uri": "", "type": ""}],
|
||||||
"category": "",
|
"category": "",
|
||||||
"creators": [{"address": "", "share": None}]
|
"creators": [{"address": "", "share": None}]
|
||||||
}
|
}
|
||||||
|
|
||||||
sendMetaDataToJson(metaDataDictSolana, solanaMetadataPath, name)
|
send_metadata_to_json(
|
||||||
|
metadata_dict_solana,
|
||||||
|
solana_metadata_path,
|
||||||
|
name
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# ERC721 Template
|
# ERC721 Template
|
||||||
def createErc721MetaData(name, Order_Num, NFT_DNA, NFT_Variants, Material_Attributes, custom_Fields, enableCustomFields,
|
def create_erc721_meta_data(
|
||||||
erc721_description, erc721MetadataPath):
|
name,
|
||||||
metaDataDictErc721 = {
|
order_num,
|
||||||
|
nft_dna,
|
||||||
|
nft_variants,
|
||||||
|
material_attributes,
|
||||||
|
custom_fields,
|
||||||
|
enable_custom_fields,
|
||||||
|
erc721_description,
|
||||||
|
erc721_metadata_path
|
||||||
|
):
|
||||||
|
|
||||||
|
metadata_dict_erc721 = {
|
||||||
"name": name,
|
"name": name,
|
||||||
"description": erc721_description,
|
"description": erc721_description,
|
||||||
"image": "",
|
"image": "",
|
||||||
|
@ -111,33 +156,36 @@ def createErc721MetaData(name, Order_Num, NFT_DNA, NFT_Variants, Material_Attrib
|
||||||
attributes = []
|
attributes = []
|
||||||
|
|
||||||
# Variants and Attributes:
|
# Variants and Attributes:
|
||||||
for i in NFT_Variants:
|
for i in nft_variants:
|
||||||
dictionary = {
|
dictionary = {
|
||||||
"trait_type": i,
|
"trait_type": i,
|
||||||
"value": stripNums(NFT_Variants[i])
|
"value": strip_nums(nft_variants[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
attributes.append(dictionary)
|
attributes.append(dictionary)
|
||||||
|
|
||||||
# Material Variants and Attributes:
|
# Material Variants and Attributes:
|
||||||
for i in Material_Attributes:
|
for i in material_attributes:
|
||||||
dictionary = {
|
dictionary = {
|
||||||
"trait_type": i,
|
"trait_type": i,
|
||||||
"value": Material_Attributes[i]
|
"value": material_attributes[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
attributes.append(dictionary)
|
attributes.append(dictionary)
|
||||||
|
|
||||||
# Custom Fields:
|
# Custom Fields:
|
||||||
if enableCustomFields:
|
if enable_custom_fields:
|
||||||
for i in custom_Fields:
|
for i in custom_fields:
|
||||||
dictionary = {
|
dictionary = {
|
||||||
"trait_type": i,
|
"trait_type": i,
|
||||||
"value": custom_Fields[i]
|
"value": custom_fields[i]
|
||||||
}
|
}
|
||||||
attributes.append(dictionary)
|
attributes.append(dictionary)
|
||||||
|
|
||||||
metaDataDictErc721["attributes"] = attributes
|
metadata_dict_erc721["attributes"] = attributes
|
||||||
|
|
||||||
sendMetaDataToJson(metaDataDictErc721, erc721MetadataPath, name)
|
|
||||||
|
|
||||||
|
send_metadata_to_json(
|
||||||
|
metadata_dict_erc721,
|
||||||
|
erc721_metadata_path,
|
||||||
|
name
|
||||||
|
)
|
||||||
|
|
|
@ -1,48 +1,46 @@
|
||||||
# Purpose:
|
# Purpose:
|
||||||
# This file goes through all batches, renames, and sorts all nft files to a Complete_Collection folder in Blend_My_NFTs
|
# This file goes through all batches, renames, and sorts all nft files to a Complete_Collection folder in Blend_My_NFTs
|
||||||
|
|
||||||
import bpy
|
|
||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
from .helpers import TextColors, removeList, remove_file_by_extension
|
from .helpers import remove_file_by_extension
|
||||||
|
|
||||||
|
|
||||||
def reformatNFTCollection(refactor_panel_input):
|
def reformat_nft_collection(refactor_panel_input):
|
||||||
completeCollPath = os.path.join(refactor_panel_input.save_path, "Blend_My_NFTs Output", "Complete_Collection")
|
complete_coll_path = os.path.join(refactor_panel_input.save_path, "Blend_My_NFTs Output", "Complete_Collection")
|
||||||
|
|
||||||
if not os.path.exists(completeCollPath):
|
if not os.path.exists(complete_coll_path):
|
||||||
os.mkdir(completeCollPath)
|
os.mkdir(complete_coll_path)
|
||||||
|
|
||||||
batchListDirty = os.listdir(refactor_panel_input.nftBatch_save_path)
|
batch_list_dirty = os.listdir(refactor_panel_input.nft_batch_save_path)
|
||||||
batchList = remove_file_by_extension(batchListDirty)
|
batch_list = remove_file_by_extension(batch_list_dirty)
|
||||||
collection_info = {"Total Time": 0}
|
collection_info = {"Total Time": 0}
|
||||||
|
|
||||||
for folder in batchList:
|
for folder in batch_list:
|
||||||
batch_info = json.load(open(os.path.join(refactor_panel_input.nftBatch_save_path, folder, "batch_info.json")))
|
batch_info = json.load(open(os.path.join(refactor_panel_input.nft_batch_save_path, folder, "batch_info.json")))
|
||||||
collection_info[os.path.basename(folder)] = batch_info
|
collection_info[os.path.basename(folder)] = batch_info
|
||||||
collection_info["Total Time"] = collection_info["Total Time"] + batch_info["Batch Render Time"]
|
collection_info["Total Time"] = collection_info["Total Time"] + batch_info["Batch Render Time"]
|
||||||
|
|
||||||
fileListDirty = os.listdir(os.path.join(refactor_panel_input.nftBatch_save_path, folder))
|
file_list_dirty = os.listdir(os.path.join(refactor_panel_input.nft_batch_save_path, folder))
|
||||||
filelist = remove_file_by_extension(fileListDirty)
|
filelist = remove_file_by_extension(file_list_dirty)
|
||||||
|
|
||||||
for mediaTypeFolder in filelist:
|
for mediaTypeFolder in filelist:
|
||||||
if mediaTypeFolder != "batch_info.json":
|
if mediaTypeFolder != "batch_info.json":
|
||||||
mediaTypeFolderDir = os.path.join(refactor_panel_input.nftBatch_save_path, folder, mediaTypeFolder)
|
media_type_folder_dir = os.path.join(refactor_panel_input.nft_batch_save_path, folder, mediaTypeFolder)
|
||||||
|
|
||||||
for i in os.listdir(mediaTypeFolderDir):
|
for i in os.listdir(media_type_folder_dir):
|
||||||
destination = os.path.join(completeCollPath, mediaTypeFolder)
|
destination = os.path.join(complete_coll_path, mediaTypeFolder)
|
||||||
if not os.path.exists(destination):
|
if not os.path.exists(destination):
|
||||||
os.makedirs(destination)
|
os.makedirs(destination)
|
||||||
|
|
||||||
shutil.move(os.path.join(mediaTypeFolderDir, i), destination)
|
shutil.move(os.path.join(media_type_folder_dir, i), destination)
|
||||||
|
|
||||||
collection_info = json.dumps(collection_info, indent=1, ensure_ascii=True)
|
collection_info = json.dumps(collection_info, indent=1, ensure_ascii=True)
|
||||||
with open(os.path.join(completeCollPath, "collection_info.json"), 'w') as outfile:
|
with open(os.path.join(complete_coll_path, "collection_info.json"), 'w') as outfile:
|
||||||
outfile.write(collection_info + '\n')
|
outfile.write(collection_info + '\n')
|
||||||
|
|
||||||
print(f"All NFT files stored and sorted to the Complete_Collection folder in {refactor_panel_input.save_path}")
|
print(f"All NFT files stored and sorted to the Complete_Collection folder in {refactor_panel_input.save_path}")
|
||||||
|
|
||||||
shutil.rmtree(refactor_panel_input.nftBatch_save_path)
|
shutil.rmtree(refactor_panel_input.nft_batch_save_path)
|
||||||
|
|
||||||
|
|
Ładowanie…
Reference in New Issue