diff --git a/MCprep_addon/materials/prep.py b/MCprep_addon/materials/prep.py
index 80573b23..3da5db96 100644
--- a/MCprep_addon/materials/prep.py
+++ b/MCprep_addon/materials/prep.py
@@ -310,9 +310,8 @@ def execute(self, context):
 		else:
 			self.report(
 				{"ERROR"},
-				"Nothing modified, be sure you selected objects with existing materials!"
-			)
-
+				"Nothing modified, be sure you selected objects with existing materials!")
+		
 		addon_prefs = util.get_user_preferences(context)
 		self.track_param = context.scene.render.engine
 		self.track_exporter = addon_prefs.MCprep_exporter_type
diff --git a/MCprep_addon/materials/skin.py b/MCprep_addon/materials/skin.py
index 43b1c3ba..a949a90a 100644
--- a/MCprep_addon/materials/skin.py
+++ b/MCprep_addon/materials/skin.py
@@ -31,8 +31,17 @@
 from . import generate
 from .. import tracking
 from .. import util
+from ..spawner import spawn_util
 
 from ..conf import env
+from .prep import McprepMaterialProps
+
+
+swap_all_imgs_desc = (
+	"Swap textures in all image nodes that exist on the selected \n"
+	"material; if off, will instead seek to only replace the images of \n"
+	"nodes (not image blocks) named MCPREP_SKIN_SWAP"
+)
 
 
 swap_all_imgs_desc = (
@@ -335,7 +344,29 @@ def download_user(self, context: Context, username: str) -> Optional[Path]:
 		self.track_param = "username"
 	return saveloc
 
+def check_entity_texture(texture_path: str) -> Optional[Path]:
+	context = bpy.context
+	addon_prefs = util.get_user_preferences(context)
+	active_pack = bpy.path.abspath(context.scene.mcprep_texturepack_path)
+	active_pack = os.path.join(
+		active_pack, "assets", "minecraft", "textures", "entity")
+
+	base_pack = bpy.path.abspath(addon_prefs.custom_texturepack_path)
+	base_pack = os.path.join(
+		base_pack, "assets", "minecraft", "textures", "entity")
+
+	# if not os.path.isdir(active_pack):
+	# 	env.log(f"No models found for active path {active_pack}")
+	# 	return None
+	base_has_textures = os.path.isdir(base_pack)
 
+
+	if base_has_textures:
+		return generate.find_from_texturepack(texture_path)
+	else:
+		env.log(f"Base resource pack has no entity texture folder: {base_pack}")
+		return None
+	
 # -----------------------------------------------------------------------------
 # Operators / UI classes
 # -----------------------------------------------------------------------------
@@ -395,7 +426,6 @@ def execute(self, context):
 
 		return {'FINISHED'}
 
-
 class MCPREP_OT_apply_skin(bpy.types.Operator):
 	"""Apply the active UIlist skin to select characters"""
 	bl_idname = "mcprep.applyskin"
@@ -703,6 +733,77 @@ def execute(self, context):
 		return {'FINISHED'}
 
 
+class MCPREP_OT_swap_skin_variant(bpy.types.Operator, spawn_util.VariationProp):
+	"""Apply the active UIlist skin to select characters"""
+	bl_idname = "mcprep.swap_skin"
+	bl_label = "Swap mob skin"
+	bl_description = "Swap the mobs variant"
+	bl_options = {'REGISTER', 'UNDO'}
+	
+	# def invoke(self, context, event):
+	# 	return context.window_manager.invoke_props_dialog(
+	# 		self, width=300 * util.ui_scale())
+
+	# def draw(self, context: Context):
+	# 	layout = self.layout
+	# 	self.draw_variation_ui(context, layout)
+	
+	@tracking.report_error
+	def execute(self, context: Context):
+		obj = context.object
+		if obj.type != 'ARMATURE':
+			self.report({'ERROR'}, "Please select an armature")
+			return {'CANCELLED'}
+		mats, skipped = getMatsFromSelected(obj, False)
+		mob_type = obj.get("MCPREP_mob_type", "Custom")
+		
+		if mob_type == "Custom":
+			self.report({'ERROR'}, "You are not allowed to use on Custom rig")
+			return {'CANCELLED'}
+		
+		texture_paths = self.get_texture_paths(mob_type)
+		name = mob_type.lower().replace(" ", "_")
+		if mob_type == "Villager":
+			self.doVillager(mats, texture_paths)
+		elif mob_type == "Zombie":
+			check_entity_texture(context)
+			if self.zombie_variation in ["ZOMBIE", "HUSK"]:
+				# Using Player model so convert player skin to 1.8 format
+				# loadSkinFile()
+				pass
+			else:
+				# Assign textures materials for drown
+				pass
+		elif mob_type == "Skeleton":
+			pass
+		
+		elif mob_type in ("Allay", "Vex"):
+			if mob_type == "Allay":
+				name += "/" + name
+			else:
+				name = "illager"
+			
+		else:
+			pass
+		return {'FINISHED'}
+
+	def doVillager(self, materials: List[Material], texture_paths: List[str]):
+		""" materials texture path order follows by profession, profession level, type """
+		prof_mat, biome_mat, level_mat = None, None, None
+		if mat[0].get("MCPREP_VILLAGER_PROFESSION"):
+				image = util.loadTexture(texture_paths[0])
+				proStat = generate.assert_textures_on_materials(image, [mat])
+			if mat.get("MCPREP_VILLAGER_BIOME"):
+				image = util.loadTexture(texture_paths[1])
+				biomeStat = generate.assert_textures_on_materials(image, [mat])
+			if mat.get("MCPREP_VILLAGER_LEVEL"):
+				image = util.loadTexture(texture_paths[2])
+				levelStat = generate.assert_textures_on_materials(image, [mat])
+			if not all([proStat, biomeStat, levelStat]):
+				self.report({'ERROR'}, "Something wrong happen during swap variant texture")
+			else:
+				pass
+
 class MCPREP_OT_download_username_list(bpy.types.Operator):
 	"""Apply the active UIlist skin to select characters"""
 	bl_idname = "mcprep.download_username_list"
@@ -788,6 +889,7 @@ def execute(self, context):
 	ListColl,
 	MCPREP_OT_swap_skin_from_file,
 	MCPREP_OT_apply_skin,
+	MCPREP_OT_swap_skin_variant,
 	MCPREP_OT_apply_username_skin,
 	MCPREP_OT_download_username_list,
 	# MCPREP_OT_skin_fix_eyes,
diff --git a/MCprep_addon/mcprep_ui.py b/MCprep_addon/mcprep_ui.py
index 7639768d..88ea440b 100644
--- a/MCprep_addon/mcprep_ui.py
+++ b/MCprep_addon/mcprep_ui.py
@@ -943,6 +943,8 @@ class MCPREP_PT_skins(bpy.types.Panel):
 
 	def draw(self, context):
 		layout = self.layout
+		wm_props = context.window_manager.mcprep
+
 		if addon_just_updated():
 			restart_layout(layout)
 			return
@@ -951,56 +953,63 @@ def draw(self, context):
 		sind = context.scene.mcprep_skins_list_index
 		mob_ind = context.scene.mcprep_props.mob_list_index
 		skinname = None
-
 		row = layout.row()
 		row.label(text=env._("Select skin"))
 		row.operator(
 			"mcprep.open_help", text="", icon="QUESTION", emboss=False
 		).url = "https://theduckcow.com/dev/blender/mcprep/skin-swapping/"
-
-		# set size of UIlist
 		row = layout.row()
-		col = row.column()
-
-		is_sortable = len(env.skin_list) > 1
-		rows = 1
-		if (is_sortable):
-			rows = 4
-
-		# any other conditions for needing reloading?
-		if not env.skin_list:
-			col = layout.column()
-			col.label(text=env._("No skins found/loaded"))
-			p = col.operator(
-				"mcprep.reload_skins", text=env._("Press to reload"), icon="ERROR")
-		elif env.skin_list and len(env.skin_list) <= sind:
-			col = layout.column()
-			col.label(text=env._("Reload skins"))
-			p = col.operator(
-				"mcprep.reload_skins", text=env._("Press to reload"), icon="ERROR")
-		else:
-			col.template_list(
-				"MCPREP_UL_skins", "",
-				context.scene, "mcprep_skins_list",
-				context.scene, "mcprep_skins_list_index",
-				rows=rows)
-
-			col = layout.column(align=True)
-
-			row = col.row(align=True)
-			row.scale_y = 1.5
-			if env.skin_list:
-				skinname = bpy.path.basename(env.skin_list[sind][0])
-				p = row.operator("mcprep.applyskin", text=f"Apply {skinname}")
-				p.filepath = env.skin_list[sind][1]
+		row.prop(wm_props, "skin_modes",expand=True)
+		if wm_props.skin_modes == 'PLAYER':
+		
+			# set size of UIlist
+			row = layout.row()
+			col = row.column()
+
+			is_sortable = len(env.skin_list) > 1
+			rows = 1
+			if (is_sortable):
+				rows = 4
+
+			# any other conditions for needing reloading?
+			if not env.skin_list:
+				col = layout.column()
+				col.label(text="No skins found/loaded")
+				p = col.operator(
+					"mcprep.reload_skins", text="Press to reload", icon="ERROR")
+			elif env.skin_list and len(env.skin_list) <= sind:
+				col = layout.column()
+				col.label(text="Reload skins")
+				p = col.operator(
+					"mcprep.reload_skins", text="Press to reload", icon="ERROR")
 			else:
-				row.enabled = False
-				p = row.operator("mcprep.skin_swapper", text=env._("No skins found"))
-			row = col.row(align=True)
-			row.operator("mcprep.skin_swapper", text=env._("Skin from file"))
-			row = col.row(align=True)
-			row.operator("mcprep.applyusernameskin", text=env._("Skin from username"))
+				col.template_list(
+					"MCPREP_UL_skins", "",
+					context.scene, "mcprep_skins_list",
+					context.scene, "mcprep_skins_list_index",
+					rows=rows)
+
+				col = layout.column(align=True)
+
+				row = col.row(align=True)
+				row.scale_y = 1.5
+				if env.skin_list:
+					skinname = bpy.path.basename(env.skin_list[sind][0])
+					p = row.operator("mcprep.applyskin", text=f"Apply {skinname}")
+					p.filepath = env.skin_list[sind][1]
+				else:
+					row.enabled = False
+					p = row.operator("mcprep.skin_swapper", text="No skins found")
+				row = col.row(align=True)
+				row.operator("mcprep.skin_swapper", text="Skin from file")
+				row = col.row(align=True)
+				row.operator("mcprep.applyusernameskin", text="Skin from username")
+		else:
+			row = layout.row()
+			col = row.column()
 
+			wm_props.draw_variation_ui(context, col)
+			col.operator("mcprep.swap_skin")
 		split = layout.split()
 		col = split.column(align=True)
 		row = col.row(align=True)
@@ -1044,6 +1053,12 @@ def draw(self, context):
 					# datapass = scn_props.mob_list[mob_ind].mcmob_type
 					tx = f"Spawn {name} with {skinname}"
 					row.operator("mcprep.spawn_with_skin", text=tx)
+			b_row.label(text="Resource pack")
+			subrow = b_row.row(align=True)
+			subrow.prop(context.scene, "mcprep_texturepack_path", text="")
+			subrow.operator(
+				"mcprep.reset_texture_path", icon=LOAD_FACTORY, text="")
+			
 
 
 class MCPREP_PT_materials(bpy.types.Panel):
@@ -1969,6 +1984,25 @@ class McprepProps(bpy.types.PropertyGroup):
 	effects_list_index: bpy.props.IntProperty(default=0)
 
 
+class MCprepWindowManager(spawn_util.VariationProp, bpy.types.PropertyGroup):
+	skin_modes : bpy.props.EnumProperty(
+		name="Modes",
+		description="Skinswap modes",
+		items=(
+			('PLAYER', "Player", ""),
+			('MOB', "Mob/Entity", "")
+		)
+	)
+
+	@classmethod
+	def register(cls):
+		bpy.types.WindowManager.mcprep = bpy.props.PointerProperty(type=cls)
+	
+	@classmethod
+	def unregister(cls):
+		del bpy.types.WindowManager.mcprep
+		
+		
 # -----------------------------------------------------------------------------
 # Register functions
 # -----------------------------------------------------------------------------
@@ -1977,6 +2011,7 @@ class McprepProps(bpy.types.PropertyGroup):
 classes = (
 	McprepPreference,
 	McprepProps,
+	MCprepWindowManager,
 	MCPREP_MT_mob_spawner,
 	MCPREP_MT_meshswap_place,
 	MCPREP_MT_item_spawn,
diff --git a/MCprep_addon/spawner/entities.py b/MCprep_addon/spawner/entities.py
index 96b70711..f2e57a3d 100644
--- a/MCprep_addon/spawner/entities.py
+++ b/MCprep_addon/spawner/entities.py
@@ -21,7 +21,10 @@
 
 import bpy
 
-from bpy.types import Context
+from bpy.types import (
+	Context, 
+	Event
+)
 from ..conf import env, Entity
 from .. import util
 from .. import tracking
diff --git a/MCprep_addon/spawner/spawn_util.py b/MCprep_addon/spawner/spawn_util.py
index a8031347..4a370da5 100644
--- a/MCprep_addon/spawner/spawn_util.py
+++ b/MCprep_addon/spawner/spawn_util.py
@@ -18,11 +18,15 @@
 
 import os
 import re
-from typing import List, Optional
+from typing import List, Optional, Tuple, Union
 from pathlib import Path
 
 import bpy
-from bpy.types import Context, Collection, BlendDataLibraries
+from bpy.types import (
+	Context, Collection, 
+	BlendDataLibraries,
+	UILayout
+)
 
 from ..conf import env
 from .. import util
@@ -41,11 +45,298 @@
 COLL_ICON = 'OUTLINER_COLLECTION' if util.bv30() else 'COLLECTION_NEW'
 
 
+class VariationProp:
+	def color_items(self, context: Context) -> List[Tuple[str,str,str]]:
+		"""Color variation in ID order"""
+		items = [
+			('WHITE', "White", ""),
+			('ORANGE', "Orange", ""),
+			('MAGENTA', "Magenta", ""),
+			('LIGHTBLUE', "Light Blue", ""),
+			('YELLOW', "Yellow", ""),
+			('LIME', "Lime", ""),
+			('PINK', "Pink", ""),
+			('GRAY', "Gray", ""), 
+			('LIGHTGRAY', "Light Gray", ""),
+			('CYAN', "Cyan", ""),
+			('PURPLE', "Purple", ""),
+			('BLUE', "Blue", ""),
+			('BROWN', "Brown", ""),
+			('GREEN', "Green", ""),
+			('RED', "Red", ""),
+			('BLACK', "Black", ""),
+		]
+		return items
+		
+	def profession_items(self, context: Context) -> List[Tuple[str, str, str]]:
+		"""Villager Professional"""
+		items = [
+			('ARMORER', "Armorer", ""),
+			('BUTCHER', "Butcher", ""),
+			('CARTOGRAPHER', "Cartographer", ""),
+			('CLERIC', "Cleric", ""),
+			('FARMER', "Farmer", ""),
+			('FISHERMAN', "Fisherman", ""),
+			('FLETCHER', "Fletcher", ""),
+			('LEATHERWORKER', "Leatherworker", ""),
+			('LIBRARIAN', "Librarian", ""),
+			('MASON', "Mason", ""),
+			('NITWIT', "Nitwit", ""),
+			('SHEPHERD', "Shepherd", ""),
+			('TOOLSMITH', "Toolsmith", ""),
+			('WEAPONSMITH', "Weaponsmith", ""),
+			('WANDER', "Wandering", ""), # Wandering Trader is not a villager but leave it there, illagers could be in the list too (witch?)
+		]
+		return items
+	
+	def level_items(self, context: Context) -> List[Tuple[str, str, str]]:
+		"""Villager Level """
+		items = [
+			('NOVICE', "Novice", ""), # Stone
+			('APPRENTICE', "Apprentice", ""), # Iron
+			('JOURNEYMAN', "Journeyman", ""), # Gold
+			('EXPERT', "Expert", ""), # Emerald
+			('MASTER', "Master", ""), # Diamond
+		]
+		return items
+	
+	def biome_items(self, context: Context) -> List[Tuple[str, str, str]]:
+		items = [
+			('DESERT', "Desert", ""),
+			('JUNGLE', "Jungle", ""),
+			('PLAINS', "Plains", ""),
+			('SAVANNA', "Savanna", ""),
+			('SNOWY', "Snowy", ""),
+			('SWAMP', "Swamp", ""),
+			('TAIGA', "Taiga", ""),
+		]
+		return items
+	
+	def zombie_items(self, context: Context) -> List[Tuple[str, str, str]]:
+		items = [
+			('DEFAULT', "Default", ""),
+			('DROWN', "Drown", ""),
+			('HUSK', "Husk", ""),
+		]
+		return items
+	
+	def skeleton_items(self, context: Context) -> List[Tuple[str, str, str]]:
+		items = [
+			('DEFAULT', "Default", ""),
+			('STRAY', "Stray", ""),
+			('WITHER', "Wither", ""),
+			# ('BOGGED', "Bogged", "") # 1.21 Added new skeleton varia
+		]
+		return items
+	
+	def axolotl_items(self, context: Context) -> List[Tuple[str, str, str]]:
+		items = [
+			('BLUE', "Blue", ""),
+			('CYAN', "Cyan", ""),
+			('GOLD', "Gold", ""),
+			('LUCY', "Lucy", ""),
+			('WILD', "Wild", ""),
+		]
+		return items
+	
+	def rabbit_items(self, context: Context) -> List[Tuple[str, str, str]]:
+		items = [
+			('BLACK', "Black", ""),
+			('BROWN', "Brown", ""),
+			('CAERBANNOG', "Caerbannog", ""),
+			('GOLD', "Gold", ""),
+			('SALT', "Salt", ""),
+			('TOAST',"Toast", ""),
+			('WHITE', "White", ""),
+			('WHITE_SPLOTCHED',"White splotched", ""),
+		]
+		return items
+	
+	def frog_items(self, context: Context) -> List[Tuple[str, str, str]]:
+		items = [
+			('COLD', "Cold", ""),
+			('TEMPERATE', "Temperate", ""),
+			('WARM', "Warm", ""),
+		]
+		return items
+	
+	def parrot_items(self, context: Context) -> List[Tuple[str, str, str]]:
+		items = [
+			('BLUE', "Blue", ""),
+			('GREEN',"Green", ""),
+			('GREY', "Grey", ""), 
+			('RED_BLUE', "Red blue", ""),
+			('YELLOW_BLUE', "Yellow blue", ""),
+		]
+		return items
+		
+	def llama_items(self, context: Context) -> List[Tuple[str, str, str]]:
+		items = [
+			('BROWN',"Brown", ""),
+			('CREAMY',"Creamy",""),
+			('GRAY', "Gray", ""),
+			('WHITE', "White", ""),
+		]
+		return items
+	
+	def horse_items(self, context: Context) -> List[Tuple[str, str, str]]:
+		items = [
+			('BLACK', "Black", ""),
+			('BROWN', "BROWN", ""),
+			('CHESTNUT', "CHESTNUT", ""),
+			('CREAMY', "CREAMY", ""),
+			('DARK_BROWN', "DARK_BROWN", ""),
+			('GRAY', "GRAY", ""),
+			('ZOMBIE', "ZOMBIE", ""),
+			('SKELETON', "SKELETON", ""),
+		]
+		return items
+		
+	def cat_items(self, context: Context) -> List[Tuple[str, str, str]]:
+		items = [
+			('ALL_BLACK', "All Black",""),
+			('BLACK', "Black", ""),
+			('BRITISH_SHORTHAIR', "British Shorthair", ""),
+			('CALICO', "Calico", ""),
+			('JELLIE', "Jellie", ""),
+			('OCELOT', "Ocelot", ""),
+			('PERSIAN', "Persian", ""),
+			('RAGDOLL', "Ragdoll", ""),
+			('RED', "Red", ""),
+			('SIAMESE', "Siamese", ""),
+			('TABBY', "Tabby", ""),
+			('WHITE', "White", ""),
+			# ('CAT_COLLAR', "", "")
+		]
+		return items
+	
+	def fox_items(self, context: Context) -> List[Tuple[str, str, str]]:
+		items = [
+			('NORMAL', "Normal", ""),
+			('SNOW', "Snow", "")
+		]
+		return items
+	
+	def squid_items(self, context: Context) -> List[Tuple[str, str, str]]:
+		items = [
+			('NORMAL', "Squid", ""),
+			('GLOW', "Glow", "")
+		]
+		return items
+	
+	def tropical_pattern_items(self, context: Context) -> List[Tuple[str, str, str]]:
+		items = [
+			('PATTERN_1', "Pattern 1", ""),
+			('PATTERN_2', "Pattern 2", ""),
+			('PATTERN_3', "Pattern 3", ""),
+			('PATTERN_4', "Pattern 4", ""),
+			('PATTERN_5', "Pattern 5", ""),
+			("PATTERN_6", "Pattern 6", ""),
+		]
+		return items
+	
+	def dog_items(self, context) -> List[Tuple[str, str, str]]:
+		items = [ 
+			# ignore this just placeholder for 1.21 wolf variations
+			('DEF', "def", ""),
+			('DEA', "dea", "")
+		]
+		return items
+	
+	def get_villager_names(self) -> Tuple[str, str, str]:
+		"""Returns profession, profession level, type path in order"""
+		# (adds villager/{}.png to get the texture path, same for zombie_villager/)
+		return f"profession/{self.profession_variation}", f"profession_level/{self.level_variation}", f"type/{self.biome_variation}"
+	
+	def get_squid_name(self) -> str:
+		return self.squid_variation == 'GLOW' if 'glow_squid' else 'squid'
+	
+	def get_fox_name(self) -> Tuple[str, str]:
+		return ("snow_fox", "snow_fox_sleeping") if self.fox_variation == 'SNOW' else ("fox", "fox_sleeping")
+	
+	def get_tropical_name(self) -> str:
+		"""Returns the tropical fish type and pattern"""
+		# (adds fish/{}.png to get the texture path)
+		type = self.tropical_type_variation.lower()
+		pattern = self.tropical_pattern_variation.replace("PATTERN_", "")
+		return f"tropical_{type}_pattern_{pattern}"
+			
+	def get_texture_path(self, mob_type: str, is_zombified: bool = False) -> List[Union[str, Path]]:
+		if mob_type == "Villager":
+			names = self.get_villager_names()
+			return [f"zombie_villager/{t}.png" for t in names] if is_zombified else[f"villager/{t}.png" for t in names]
+		elif mob_type == "Zombie":
+			return [f"zombie/{self.zombie_variation.lower()}.png"]
+		elif mob_type == "Skeleton":
+			return [f"zombie/{self.skeleton_variation.lower()}.png"]
+		elif mob_type == "Allay" or mob_type == "Vex":
+			return [] if self.is_zombiefied or mob_type == "Vex" else []
+			# TODO: Add the rest of the mobs
+			
+	profession_variation: bpy.props.EnumProperty(name="Profession", items=profession_items)
+	level_variation: bpy.props.EnumProperty(name="Level", items=level_items)
+	biome_variation: bpy.props.EnumProperty(name="Biome", items=biome_items)
+	zombie_variation: bpy.props.EnumProperty(name="Zombie Variation", items=zombie_items)
+	skeleton_variation: bpy.props.EnumProperty(name="Skeleton Variation", items=skeleton_items)
+	is_zombiefied: bpy.props.BoolProperty(name="Is Zombiefied")  # Use this for Allay-Vex
+	fox_variation: bpy.props.EnumProperty(items=fox_items)
+	dog_variation: bpy.props.EnumProperty(items=dog_items)
+	cat_variation: bpy.props.EnumProperty(items=cat_items)
+	
+	def draw_variation_ui(self, context: Context, layout: UILayout):
+		""" Sharable method for drawing"""
+		obj = context.object
+		mob_type = getmob_type(obj)
+		if mob_type in ["Villager", "Trader"]:
+			layout.prop(self, "profession_variation")
+			layout.prop(self, "level_variation")
+			layout.prop(self, "biome_variation")
+			
+		elif mob_type == "Zombie":
+			layout.prop(self, "zombie_variation")
+		elif mob_type == "Skeleton":
+			layout.prop(self, "skeleton_variation")
+		elif mob_type == "Axolotl":
+			layout.prop(self, "axolotl_variation")
+		elif mob_type == "Rabbit":
+			layout.prop(self, "rabbit_variation")
+		elif mob_type == "Frog":
+			layout.prop(self, "frog_variation")
+		elif mob_type == "Parrot":
+			layout.prop(self, "parrot_variation")
+		elif mob_type == "Llama":
+			layout.prop(self, "llama_variation")
+		elif mob_type == "Horse":
+			layout.prop(self, "horse_variation")
+		elif mob_type == "Cat" or mob_type == "Ocelot":
+			layout.prop(self, "cat_variation")
+		elif mob_type == "Dog" or mob_type == "Wolf":
+			layout.prop(self, "dog_variation")
+			
+		counter_variant = ["Villager", "Piglin", "Hoglin", "Allay", "Vex"]
+		if mob_type in counter_variant:
+			text = "Is Vex" if mob_type == "Allay" else "Is Zombified"
+			layout.prop(self, "is_zombiefied", text=text)
+		
+		has_variant = counter_variant + ["Zombie", "Skeleton", "Llama", "Axolotl", "Rabbit", "Llama", "Parrot", "Frog", "Horse", "Cat", "Ocelot"]
+		if mob_type == "Custom" or mob_type not in has_variant:
+			layout.label(text="This mob doesn't has any variant to swap skin yet")
+		elif mob_type == "Player":
+			layout.label(text="Please use Player for this")
+
 # -----------------------------------------------------------------------------
 # Reusable functions for spawners
 # -----------------------------------------------------------------------------
 
 
+def getmob_type(rig: bpy.types.Object):
+	""" Get mob type from rig
+	args
+		obj: Armature Object
+	"""
+	return rig.type == 'ARMATURE' and rig.get("MCPREP_MOBTYPE", "Custom")
+
+
 def filter_collections(data_from: BlendDataLibraries) -> List[str]:
 	""" TODO 2.7 groups 
 	Generalized way to prefilter collections in a blend file.
diff --git a/MCprep_addon/util.py b/MCprep_addon/util.py
index 85921ce5..2f3c48eb 100644
--- a/MCprep_addon/util.py
+++ b/MCprep_addon/util.py
@@ -17,7 +17,7 @@
 # ##### END GPL LICENSE BLOCK #####
 
 from subprocess import Popen, PIPE
-from typing import List, Optional, Union, Tuple
+from typing import List, Optional, Union, Tuple, Any, Dict
 import enum
 import json
 import operator
@@ -35,7 +35,8 @@
 	Material,
 	Image,
 	Node,
-	UILayout
+	UILayout,
+	ID
 )
 from mathutils import Vector, Matrix
 
@@ -778,3 +779,16 @@ def move_assets_to_excluded_layer(context: Context, collections: List[Collection
 			continue  # not linked, likely a sub-group not added to scn
 		spawner_exclude_vl.collection.children.link(grp)
 		initial_view_coll.collection.children.unlink(grp)
+
+
+def set_prop(id_block: ID, key: str, value: Any, **kwargs: Dict[str, Any]):
+	"""Create or set the properties
+		3.0 got more functionalities
+	"""
+	id_block[key] = value
+	if bv30():
+		id_props = id_block.id_properties_ui(key)
+		id_props.update(**kwargs)
+		overrides = kwargs.get("overridable_library", True)
+		if overrides is not None:
+			id_block.property_overridable_library_set(f'["{key}"]', overrides)