Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrated initial prep material tests, all currently passing. #450

Merged
merged 21 commits into from
Aug 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
fbd1f20
Migrated initial prep material tests, all currently passing.
TheDuckCow Jul 23, 2023
236b06a
Adding tests for utility operators.
TheDuckCow Aug 6, 2023
90967e0
Fix animate textures along with animate texture test migration.
TheDuckCow Aug 6, 2023
f1e6ef9
Migrated tests for some item and effects spawning
TheDuckCow Aug 6, 2023
ed1f368
Migrated the saturation check test.
TheDuckCow Aug 6, 2023
3019bae
Minimizing linting and adding test_matprep_cycles test.
TheDuckCow Aug 6, 2023
5afa19d
Fixing material generation with saturation for 3.4+, added test timings
TheDuckCow Aug 6, 2023
8c2710e
Migrated skin+username tests and fixed bug to skip re-downloads
TheDuckCow Aug 7, 2023
946d70b
Migrated initial prep material tests, all currently passing.
TheDuckCow Jul 23, 2023
e8fb90b
Adding tests for utility operators.
TheDuckCow Aug 6, 2023
c1fe4bb
Fix animate textures along with animate texture test migration.
TheDuckCow Aug 6, 2023
999f2b7
Migrated tests for some item and effects spawning
TheDuckCow Aug 6, 2023
8fa110d
Migrated the saturation check test.
TheDuckCow Aug 6, 2023
a3fdba8
Minimizing linting and adding test_matprep_cycles test.
TheDuckCow Aug 6, 2023
d5ef84c
Fixing material generation with saturation for 3.4+, added test timings
TheDuckCow Aug 6, 2023
fbc5431
Migrated skin+username tests and fixed bug to skip re-downloads
TheDuckCow Aug 7, 2023
33361e8
Merge remote-tracking branch 'origin/424-migrate-unittests' into 424-…
TheDuckCow Aug 7, 2023
c31574d
World import split tests and merging in new build system.
TheDuckCow Aug 9, 2023
21b3aaf
Migrated add sky tests with permutations.
TheDuckCow Aug 11, 2023
3b7014d
Migrated tests for sky creation with 4.0 bug fix and mob spawning test
TheDuckCow Aug 11, 2023
3ee90c4
Updated poetry.lock
StandingPadAnimations Aug 13, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ As a quick start:
# Highly recommended, create a local virtual environment (could also define globally)
python3 -m pip install --user virtualenv


python3 -m pip install --upgrade pip # Install/upgrade pip
python3 -m venv ./venv # Add a local virtual env called `venv`

Expand All @@ -67,6 +66,8 @@ source venv/bin/activate
# Now with the env active, do the pip install (or upgrade)
pip install --upgrade bpy-addon-build

# Finally, you can compile MCprep using:
bpy-addon-build --during-build dev # Use dev to use non-prod related resources and tracking.
```

Moving forward, you can now build the addon for all intended supported versions using: `bpy-addon-build -b dev`
Expand Down
20 changes: 12 additions & 8 deletions MCprep_addon/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ def __init__(self):
# -----------------------------------------------------------------------------

def icons_init(self):
self.clear_previews()

collection_sets = [
"main", "skins", "mobs", "entities", "blocks", "items", "effects", "materials"]

Expand Down Expand Up @@ -178,6 +180,15 @@ def icons_init(self):
for iconset in collection_sets:
self.preview_collections[iconset] = ""

def clear_previews(self):
for pcoll in self.preview_collections.values():
try:
bpy.utils.previews.remove(pcoll)
except Exception as e:
self.log('Issue clearing preview set ' + str(pcoll))
print(e)
self.preview_collections.clear()

def log(self, statement: str, vv_only: bool = False):
if self.verbose and vv_only and self.very_verbose:
print(statement)
Expand Down Expand Up @@ -398,14 +409,7 @@ def register():


def unregister():
if env.use_icons:
for pcoll in env.preview_collections.values():
try:
bpy.utils.previews.remove(pcoll)
except:
env.log('Issue clearing preview set ' + str(pcoll))
env.preview_collections.clear()

env.clear_previews()
env.json_data = None # actively clearing out json data for next open

env.loaded_all_spawners = False
Expand Down
88 changes: 48 additions & 40 deletions MCprep_addon/materials/generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,74 +251,81 @@ def checklist(matName: str, listName: str) -> bool:
return True
return False

# Dataclass representing all options

# Dataclass representing all options
# for prep materials
#
# We use __slots__ since __slots__ prevents the
#
# We use __slots__ since __slots__ prevents the
# following bug:
# p = PrepOptions(...)
# p.psses["..."] = "..."
#
# Where a non-existant variable is used. In
# Python, this would create a new variable
# p = PrepOptions(...)
# p.psses["..."] = "..."
#
# Where a non-existant variable is used. In
# Python, this would create a new variable
# "psses" on p. To prevent this, we use __slots__.
#
# In addition, access to objects in __slots__ is
# In addition, access to objects in __slots__ is
# faster then it would be normally
#
# Python dataclasses have native support for __slots__
# in 3.10, but since 2.8 uses 3.7, we have to use
# Python dataclasses have native support for __slots__
# in 3.10, but since 2.8 uses 3.7, we have to use
# __slots__ directly

@dataclass
class PrepOptions:
__slots__ = ("passes",
"use_reflections",
"use_principled",
"only_solid",
"pack_format",
"use_emission_nodes",
"use_emission")
passes: Dict[str, str]
"""Class defining structure for prepping or generating materials

passes: dictionary struc of all found pass names
use_reflections: whether to turn reflections on
use_principled: if available and cycles, use principled node
saturate: if a desaturated texture (by canonical resource), add color
pack_format: which format of PBR, string ("Simple", Specular", "SEUS")
"""
__slots__ = (
"passes",
"use_reflections",
"use_principled",
"only_solid",
"pack_format",
"use_emission_nodes",
"use_emission")
passes: Dict[str, bpy.types.Image]
use_reflections: bool
use_principled: bool
only_solid: bool
pack_format: str
pack_format: str # TODO: Enforce enum value assignment.
use_emission_nodes: bool
use_emission: bool


def matprep_cycles(mat: Material, options: PrepOptions) -> Optional[bool]:
"""Determine how to prep or generate the cycles materials.

Args:
mat: the existing material
passes: dictionary struc of all found pass names
use_reflections: whether to turn reflections on
use_principled: if available and cycles, use principled node
saturate: if a desaturated texture (by canonical resource), add color
pack_format: which format of PBR, string ("Simple", Specular", "SEUS")
options: All PrepOptions for this configuration, see class definition

Returns:
int: 0 only if successful, otherwise None or other
"""
if util.bv28():
# ensure nodes are enabled esp. after importing from BI scenes
mat.use_nodes = True
# ensure nodes are enabled
mat.use_nodes = True

matGen = util.nameGeneralize(mat.name)
canon, _ = get_mc_canonical_name(matGen)
options.use_emission = checklist(canon, "emit") or "emit" in mat.name.lower()

# TODO: Update different options for water before enabling this
# if use_reflections and checklist(canon, "water"):
# res = matgen_special_water(mat, passes)
# res = matgen_special_water(mat, passes)
# if use_reflections and checklist(canon, "glass"):
# res = matgen_special_glass(mat, passes)
if options.pack_format == "simple" and util.bv28():
# res = matgen_special_glass(mat, passes)
if options.pack_format == "simple":
res = matgen_cycles_simple(mat, options)
elif options.use_principled and hasattr(bpy.types, 'ShaderNodeBsdfPrincipled'):
res = matgen_cycles_principled(mat, options)
elif options.use_principled:
res = matgen_cycles_principled(mat, options)
else:
res = matgen_cycles_original(mat, options)
res = matgen_cycles_original(mat, options)
return res


Expand Down Expand Up @@ -426,6 +433,7 @@ def set_cycles_texture(image: Image, material: Material, extra_passes: bool=Fals

return changed


def get_node_for_pass(material: Material, pass_name: str) -> Optional[Node]:
"""Assumes cycles material, returns texture node for given pass in mat."""
if pass_name not in ["diffuse", "specular", "normal", "displace"]:
Expand Down Expand Up @@ -754,7 +762,7 @@ def create_node(tree_nodes: Nodes, node_type: str, **attrs: Dict[str, Any]) -> N
return node


def get_node_socket(node: Node, is_input: bool=True) -> list:
def get_node_socket(node: Node, is_input: bool = True) -> list:
"""Gets the input or output sockets indicies for node"""
n_type = node.bl_idname
if n_type == 'ShaderNodeMix' or n_type == 'ShaderNodeMixRGB':
Expand Down Expand Up @@ -1192,7 +1200,7 @@ def matgen_cycles_simple(mat: Material, options: PrepOptions) -> Optional[bool]:
mat.blend_method = 'HASHED'
if hasattr(mat, "shadow_method"):
mat.shadow_method = 'HASHED'

if options.use_emission_nodes and options.use_emission:
inputs = [inp.name for inp in principled.inputs]
if 'Emission Strength' in inputs: # Later 2.9 versions only.
Expand All @@ -1212,8 +1220,8 @@ def matgen_cycles_simple(mat: Material, options: PrepOptions) -> Optional[bool]:
else:
env.log(f"Texture desaturated: {canon}", vv_only=True)
desat_color = env.json_data['blocks']['desaturated'][canon]
if len(desat_color) < len(nodeSaturateMix.inputs[2].default_value):
desat_color.append(1.0)
if len(desat_color) < len(nodeSaturateMix.inputs[saturateMixIn[2]].default_value):
desat_color.append(1.0)
nodeSaturateMix.inputs[saturateMixIn[2]].default_value = desat_color
nodeSaturateMix.mute = False
nodeSaturateMix.hide = False
Expand Down Expand Up @@ -1374,15 +1382,15 @@ def matgen_cycles_principled(mat: Material, options: PrepOptions) -> Optional[bo
# both work fine with depth of field.

# but, BLEND does NOT work well with Depth of Field or layering

# reapply animation data if any to generated nodes
apply_texture_animation_pass_settings(mat, animated_data)

return 0


def matgen_cycles_original(mat: Material, options: PrepOptions):
"""Generate principled cycles material"""
"""Generate non-principled cycles material"""

matGen = util.nameGeneralize(mat.name)
canon, form = get_mc_canonical_name(matGen)
Expand Down
43 changes: 22 additions & 21 deletions MCprep_addon/materials/prep.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,6 @@ def execute(self, context):
self.report({'ERROR'}, "No materials found on selected objects")
return {'CANCELLED'}


# check if linked material exists
engine = context.scene.render.engine
count = 0
Expand Down Expand Up @@ -248,13 +247,13 @@ def execute(self, context):

if engine == 'CYCLES' or engine == 'BLENDER_EEVEE':
options = generate.PrepOptions(
passes,
self.useReflections,
self.usePrincipledShader,
self.makeSolid,
self.packFormat,
self.useEmission,
False # This is for an option set in matprep_cycles
passes=passes,
use_reflections=self.useReflections,
use_principled=self.usePrincipledShader,
only_solid=self.makeSolid,
pack_format=self.packFormat,
use_emission_nodes=self.useEmission,
use_emission=False # This is for an option set in matprep_cycles
)
res = generate.matprep_cycles(
mat=mat,
Expand All @@ -270,26 +269,26 @@ def execute(self, context):

if self.animateTextures:
sequences.animate_single_material(
mat, context.scene.render.engine)
mat,
context.scene.render.engine,
export_location="original")

# Sync materials.
if self.syncMaterials is True:
bpy.ops.mcprep.sync_materials(
selected=True, link=False, replace_materials=False, skipUsage=True)


# Combine materials.
if self.combineMaterials is True:
bpy.ops.mcprep.combine_materials(selection_only=True, skipUsage=True)

# Improve UI.
# Improve UI.
if self.improveUiSettings:
try:
bpy.ops.mcprep.improve_ui()
except RuntimeError as err:
print(f"Failed to improve UI with error: {err}")


if self.optimizeScene and engine == 'CYCLES':
bpy.ops.mcprep.optimize_scene()

Expand Down Expand Up @@ -484,7 +483,9 @@ def execute(self, context):
res += generate.set_texture_pack(mat, folder, self.useExtraMaps)
if self.animateTextures:
sequences.animate_single_material(
mat, context.scene.render.engine)
mat,
context.scene.render.engine,
export_location="original")
# may be a double call if was animated tex
generate.set_saturation_material(mat)

Expand Down Expand Up @@ -642,13 +643,13 @@ def update_material(self, context, mat):

if engine == 'CYCLES' or engine == 'BLENDER_EEVEE':
options = generate.PrepOptions(
passes,
self.useReflections,
self.usePrincipledShader,
self.makeSolid,
self.packFormat,
self.useEmission,
False # This is for an option set in matprep_cycles
passes=passes,
use_reflections=self.useReflections,
use_principled=self.usePrincipledShader,
only_solid=self.makeSolid,
pack_format=self.packFormat,
use_emission_nodes=self.useEmission,
use_emission=False # This is for an option set in matprep_cycles
)
res = generate.matprep_cycles(
mat=mat,
Expand All @@ -661,7 +662,7 @@ def update_material(self, context, mat):

if self.animateTextures:
sequences.animate_single_material(
mat, context.scene.render.engine)
mat, context.scene.render.engine, export_location="original")

return success, None

Expand Down
12 changes: 7 additions & 5 deletions MCprep_addon/materials/skin.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ def handler_skins_load(scene):

def loadSkinFile(self, context: Context, filepath: Path, new_material: bool=False):
if not os.path.isfile(filepath):
self.report({'ERROR'}, "Image file not found")
self.report({'ERROR'}, f"Image file not found: {filepath}")
return 1
# special message for library linking?

Expand Down Expand Up @@ -469,9 +469,11 @@ def execute(self, context):
self.report({"ERROR"}, "Invalid username")
return {'CANCELLED'}

user_ref = self.username.lower() + ".png"

skins = [str(skin[0]).lower() for skin in env.skin_list]
paths = [skin[1] for skin in env.skin_list]
if self.username.lower() not in skins or not self.skip_redownload:
if user_ref not in skins or not self.skip_redownload:
# Do the download
saveloc = download_user(self, context, self.username)
if not saveloc:
Expand All @@ -485,8 +487,8 @@ def execute(self, context):
return {'FINISHED'}
else:
env.log("Reusing downloaded skin")
ind = skins.index(self.username.lower())
res = loadSkinFile(self, context, paths[ind][1], self.new_material)
ind = skins.index(user_ref)
res = loadSkinFile(self, context, paths[ind], self.new_material)
if res != 0:
return {'CANCELLED'}
return {'FINISHED'}
Expand Down Expand Up @@ -579,7 +581,7 @@ def draw(self, context):
skin_path = env.skin_list[context.scene.mcprep_skins_list_index]
col = self.layout.column()
col.scale_y = 0.7
col.label(text= f"Warning, will delete file {os.path.basename(skin_path[0])} from")
col.label(text=f"Warning, will delete file {os.path.basename(skin_path[0])} from")
col.label(text=os.path.dirname(skin_path[-1]))

@tracking.report_error
Expand Down
3 changes: 2 additions & 1 deletion MCprep_addon/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,8 @@ def obj_copy(base: bpy.types.Object, context: Optional[Context]=None, vertex_gro
setattr(dest, prop, getattr(mod_src, prop))
return new_ob

def min_bv(version: Tuple, *, inclusive: bool=True) -> bool:

def min_bv(version: Tuple, *, inclusive: bool = True) -> bool:
if hasattr(bpy.app, "version"):
if inclusive is False:
return bpy.app.version > version
Expand Down
Loading