working auto-tags on implemented UGC Categories
This commit is contained in:
+115
-14
@@ -39,11 +39,12 @@ from .zips import (
|
||||
read_animation_manifest,
|
||||
read_logical_manifest,
|
||||
read_models_manifest,
|
||||
read_mod_version_manifest,
|
||||
read_pack_meta,
|
||||
read_pack_mcmeta,
|
||||
read_plugins_manifest,
|
||||
read_skins_manifest,
|
||||
read_mod_version_manifest,
|
||||
_mc_from_filename,
|
||||
)
|
||||
|
||||
|
||||
@@ -543,19 +544,120 @@ ANIMATION_API_WARNING = (
|
||||
)
|
||||
|
||||
|
||||
def _apply_content_tags(project, tag_names, actor):
|
||||
"""Auto-create a content:<tag> for every distinct animation content tag."""
|
||||
content_cat = TagCategory.objects.filter(slug='content').first()
|
||||
if content_cat is None:
|
||||
return
|
||||
for name in tag_names:
|
||||
def _clean_mc_version(value):
|
||||
"""Extract the first X.Y from an MC version/range ('>=26.2 <26.3' -> '26.2')."""
|
||||
m = re.search(r'(\d+\.\d+)', str(value or ''))
|
||||
return m.group(1) if m else ''
|
||||
|
||||
|
||||
def _vanilla_entities():
|
||||
"""Set of real Minecraft entity names from the bundled vanilla index.
|
||||
|
||||
Excludes renderer aliases (slime_size_*, player_slim) that are model
|
||||
variants rather than Minecraft entities.
|
||||
"""
|
||||
aliases = {'slime_size_0', 'slime_size_1', 'slime_size_3', 'player_slim'}
|
||||
try:
|
||||
with open(settings.BASE_DIR / 'static' / 'vanilla' / 'entity_index.json') as f:
|
||||
return set(json.load(f).keys()) - aliases
|
||||
except (OSError, ValueError):
|
||||
return set()
|
||||
|
||||
|
||||
def _species_entity(entity):
|
||||
"""Map model-variant names to their real Minecraft entity."""
|
||||
return {
|
||||
'player_slim': 'player',
|
||||
'slime_size_0': 'slime',
|
||||
'slime_size_1': 'slime',
|
||||
'slime_size_3': 'slime',
|
||||
}.get(entity, entity)
|
||||
|
||||
|
||||
def _auto_tag_specs(project, version):
|
||||
"""Deduped list of (category_slug, tag_name) auto-tags for a version."""
|
||||
specs = []
|
||||
|
||||
def add(cat, name):
|
||||
name = slugify_tag(name)
|
||||
if not name:
|
||||
if name and (cat, name) not in specs:
|
||||
specs.append((cat, name))
|
||||
|
||||
if project.category == 'mod':
|
||||
for m in (version.mod_manifest or {}).get('mods', []):
|
||||
if m.get('modloader'):
|
||||
add('loader', m['modloader'])
|
||||
mc = _clean_mc_version(m.get('minecraft'))
|
||||
if not mc:
|
||||
mc = _mc_from_filename(m.get('file_name') or '')
|
||||
if mc:
|
||||
add('version', mc)
|
||||
elif project.category == 'modpack':
|
||||
for loader in (version.mods_manifest or {}).get('modloaders', []):
|
||||
add('loader', loader)
|
||||
mc = (version.mods_manifest or {}).get('minecraft')
|
||||
if mc:
|
||||
add('version', mc)
|
||||
elif project.category == 'model':
|
||||
vanilla = _vanilla_entities()
|
||||
for m in (version.models_manifest or {}).get('models', []):
|
||||
ext = (m.get('ext') or '').lstrip('.')
|
||||
if ext == 'geo.json':
|
||||
ext = 'geo'
|
||||
if ext:
|
||||
add('format', ext)
|
||||
entity = _species_entity(m.get('entity') or '')
|
||||
if entity and entity in vanilla:
|
||||
add('species', entity)
|
||||
elif project.category == 'skin':
|
||||
add('general', 'skin')
|
||||
elif project.category == 'guide':
|
||||
add('general', 'guide')
|
||||
elif project.category == 'non_pack':
|
||||
# NoN packs may carry custom/modded species — no vanilla whitelist.
|
||||
# Only skip placeholder model names (pregnancy-egg stubs, etc.).
|
||||
placeholders = {'default', 'minecraft_spider'}
|
||||
for tag in (version.animation_manifest or {}).get('content_tags', []):
|
||||
add('content', tag)
|
||||
for m in (version.models_manifest or {}).get('models', []):
|
||||
entity = _species_entity(m.get('entity') or '')
|
||||
if entity and entity not in placeholders:
|
||||
add('species', entity)
|
||||
return specs
|
||||
|
||||
|
||||
def _sync_auto_tags(project, actor=None, version=None):
|
||||
"""Apply auto tags (loader/version/format/species/general/content) from the
|
||||
given version's manifests. Marks auto links, cleans stale ones, and never
|
||||
touches manual links (arbitrary tags like creator:LiZo are preserved)."""
|
||||
actor = actor or project.owner
|
||||
version = version or project.versions.first()
|
||||
if version is None:
|
||||
return
|
||||
|
||||
TagCategory.objects.get_or_create(slug='format', defaults={'name': 'Format', 'color': '#0e7490'})
|
||||
specs = _auto_tag_specs(project, version)
|
||||
spec_set = set(specs)
|
||||
|
||||
cats = {}
|
||||
for cat_slug, name in specs:
|
||||
cat = cats.get(cat_slug) or TagCategory.objects.filter(slug=cat_slug).first()
|
||||
if cat is None:
|
||||
continue
|
||||
cats[cat_slug] = cat
|
||||
tag, _ = Tag.objects.get_or_create(
|
||||
name=name, category=content_cat, defaults={'created_by': actor},
|
||||
name=name, category=cat, defaults={'created_by': actor},
|
||||
)
|
||||
TagList.objects.get_or_create(project=project, tag=tag, defaults={'added_by': actor})
|
||||
link, created = TagList.objects.get_or_create(
|
||||
project=project, tag=tag, defaults={'added_by': actor, 'auto': True},
|
||||
)
|
||||
if not created and not link.auto:
|
||||
link.auto = True
|
||||
link.save(update_fields=['auto'])
|
||||
|
||||
for link in project.tag_links.select_related('tag__category').filter(auto=True).all():
|
||||
if (link.tag.category.slug, link.tag.name) not in spec_set:
|
||||
link.delete()
|
||||
|
||||
|
||||
def _established_animation_id(project):
|
||||
@@ -689,6 +791,7 @@ def _reparse_version(version):
|
||||
version.pack_format = fmt
|
||||
version.pack_description = desc
|
||||
version.save()
|
||||
_sync_auto_tags(version.project, version.project.owner, version.project.versions.first())
|
||||
|
||||
|
||||
def _finalize_version(project, version_name, changelog, temp_uploads, actor):
|
||||
@@ -792,10 +895,7 @@ def _finalize_version(project, version_name, changelog, temp_uploads, actor):
|
||||
if update_fields:
|
||||
version.save(update_fields=update_fields)
|
||||
|
||||
if animation_manifest is not None:
|
||||
_apply_content_tags(
|
||||
project, animation_manifest.get('content_tags') or [], actor,
|
||||
)
|
||||
_sync_auto_tags(project, actor, version)
|
||||
return version, missing_animation_id
|
||||
|
||||
|
||||
@@ -912,6 +1012,7 @@ def project_edit(request, slug):
|
||||
project.save()
|
||||
_apply_tags(project, data['tags'], request.user)
|
||||
project.sync_creator_tags(actor=request.user)
|
||||
_sync_auto_tags(project, request.user)
|
||||
messages.success(request, 'Project updated.')
|
||||
return redirect('library:project_detail', slug=project.slug)
|
||||
else:
|
||||
|
||||
Reference in New Issue
Block a user