finishing with Phase 2
This commit is contained in:
@@ -5,5 +5,6 @@ Packs_DB
|
|||||||
.migrations_done
|
.migrations_done
|
||||||
nonpacks/staticfiles/
|
nonpacks/staticfiles/
|
||||||
nonpacks/media/
|
nonpacks/media/
|
||||||
|
nonpacks/static/vanilla/entity_index.json
|
||||||
*.log
|
*.log
|
||||||
AGENTS/
|
AGENTS/
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from library.vanilla_textures import refresh_vanilla_index
|
|||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
help = 'Rebuild the vanilla entity-texture index (media/vanilla/entity_index.json).'
|
help = 'Rebuild the vanilla entity-texture index (static/vanilla/entity_index.json).'
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
index = refresh_vanilla_index()
|
index = refresh_vanilla_index()
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ urlpatterns = [
|
|||||||
path('packs/<slug:slug>/versions/<int:version_id>/download/', views.version_download, name='version_download'),
|
path('packs/<slug:slug>/versions/<int:version_id>/download/', views.version_download, name='version_download'),
|
||||||
path('packs/<slug:slug>/versions/<int:version_id>/files/<uuid:file_uuid>/download/', views.version_file_download, name='version_file_download'),
|
path('packs/<slug:slug>/versions/<int:version_id>/files/<uuid:file_uuid>/download/', views.version_file_download, name='version_file_download'),
|
||||||
path('packs/<slug:slug>/versions/<int:version_id>/asset/<path:asset_path>', views.pack_asset, name='pack_asset'),
|
path('packs/<slug:slug>/versions/<int:version_id>/asset/<path:asset_path>', views.pack_asset, name='pack_asset'),
|
||||||
path('vanilla/<path:asset_path>', views.vanilla_asset, name='vanilla_asset'),
|
|
||||||
path('packs/<slug:slug>/guide/<int:version_id>/<uuid:file_uuid>/', views.guide_doc, name='guide_doc'),
|
path('packs/<slug:slug>/guide/<int:version_id>/<uuid:file_uuid>/', views.guide_doc, name='guide_doc'),
|
||||||
path('packs/<slug:slug>/gallery/upload/', views.asset_upload, name='asset_upload'),
|
path('packs/<slug:slug>/gallery/upload/', views.asset_upload, name='asset_upload'),
|
||||||
path('packs/<slug:slug>/gallery/<int:asset_id>/thumb/', views.asset_thumbnail, name='asset_thumbnail'),
|
path('packs/<slug:slug>/gallery/<int:asset_id>/thumb/', views.asset_thumbnail, name='asset_thumbnail'),
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
"""Build the vanilla entity-texture index for the model viewer.
|
"""Build the vanilla entity-texture index for the model viewer.
|
||||||
|
|
||||||
Scans ``MEDIA_ROOT/vanilla/entity/`` (extracted from a Minecraft client jar)
|
Scans ``static/vanilla/entity/`` (extracted from a Minecraft client jar,
|
||||||
and writes ``MEDIA_ROOT/vanilla/entity_index.json`` mapping each entity name to
|
tracked in git) and writes ``static/vanilla/entity_index.json`` mapping each
|
||||||
the best "base skin" relative path, so the renderer can fall back to real
|
entity name to the best "base skin" relative path, so the renderer can fall
|
||||||
vanilla textures for models that have no pack textures of their own.
|
back to real vanilla textures for models that have no pack textures of their
|
||||||
|
own.
|
||||||
"""
|
"""
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
@@ -13,6 +14,11 @@ from django.conf import settings
|
|||||||
ENTITY_ROOT = 'entity'
|
ENTITY_ROOT = 'entity'
|
||||||
INDEX_NAME = 'entity_index.json'
|
INDEX_NAME = 'entity_index.json'
|
||||||
|
|
||||||
|
|
||||||
|
def vanilla_dir():
|
||||||
|
"""The tracked static directory holding the vanilla texture set."""
|
||||||
|
return os.path.join(settings.BASE_DIR, 'static', 'vanilla')
|
||||||
|
|
||||||
# Entity names whose vanilla layout differs from the model-name convention.
|
# Entity names whose vanilla layout differs from the model-name convention.
|
||||||
ALIASES = {
|
ALIASES = {
|
||||||
'polar_bear': 'bear/polarbear.png',
|
'polar_bear': 'bear/polarbear.png',
|
||||||
@@ -75,7 +81,7 @@ def _base_candidates(entity):
|
|||||||
"""Return (entity, [candidate relative paths]) in priority order."""
|
"""Return (entity, [candidate relative paths]) in priority order."""
|
||||||
if entity in ALIASES:
|
if entity in ALIASES:
|
||||||
return entity, [ALIASES[entity]]
|
return entity, [ALIASES[entity]]
|
||||||
root = os.path.join(settings.MEDIA_ROOT, 'vanilla', ENTITY_ROOT)
|
root = os.path.join(vanilla_dir(), ENTITY_ROOT)
|
||||||
top = os.path.join(root, entity + '.png')
|
top = os.path.join(root, entity + '.png')
|
||||||
if os.path.isfile(top):
|
if os.path.isfile(top):
|
||||||
return entity, [entity + '.png']
|
return entity, [entity + '.png']
|
||||||
@@ -98,7 +104,7 @@ def _base_candidates(entity):
|
|||||||
|
|
||||||
def refresh_vanilla_index():
|
def refresh_vanilla_index():
|
||||||
"""Rebuild the entity → {default, variants} skin map from the vanilla set."""
|
"""Rebuild the entity → {default, variants} skin map from the vanilla set."""
|
||||||
root = os.path.join(settings.MEDIA_ROOT, 'vanilla', ENTITY_ROOT)
|
root = os.path.join(vanilla_dir(), ENTITY_ROOT)
|
||||||
if not os.path.isdir(root):
|
if not os.path.isdir(root):
|
||||||
raise FileNotFoundError(f'{root} missing — extract vanilla entity textures first')
|
raise FileNotFoundError(f'{root} missing — extract vanilla entity textures first')
|
||||||
|
|
||||||
@@ -125,7 +131,7 @@ def refresh_vanilla_index():
|
|||||||
index[entity]['default'] = variants[0]
|
index[entity]['default'] = variants[0]
|
||||||
index[entity]['variants'] = variants
|
index[entity]['variants'] = variants
|
||||||
|
|
||||||
out = os.path.join(settings.MEDIA_ROOT, 'vanilla', INDEX_NAME)
|
out = os.path.join(vanilla_dir(), INDEX_NAME)
|
||||||
with open(out, 'w') as f:
|
with open(out, 'w') as f:
|
||||||
json.dump(index, f, indent=1, sort_keys=True)
|
json.dump(index, f, indent=1, sort_keys=True)
|
||||||
return index
|
return index
|
||||||
|
|||||||
@@ -423,19 +423,6 @@ def api_packs_latest(request, namespace, pack_id):
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
def vanilla_asset(request, asset_path):
|
|
||||||
"""Serve a bundled Minecraft vanilla resource (e.g. entity textures) — gated."""
|
|
||||||
if not asset_path or asset_path.startswith('/') or '..' in asset_path.split('/'):
|
|
||||||
raise Http404
|
|
||||||
full = Path(settings.MEDIA_ROOT) / 'vanilla' / asset_path
|
|
||||||
if not full.is_file():
|
|
||||||
raise Http404
|
|
||||||
content_type = mimetypes.guess_type(asset_path)[0] or 'application/octet-stream'
|
|
||||||
response = HttpResponse(full.read_bytes(), content_type=content_type)
|
|
||||||
response['Cache-Control'] = 'public, max-age=86400'
|
|
||||||
return response
|
|
||||||
|
|
||||||
|
|
||||||
def guide_doc(request, slug, version_id, file_uuid):
|
def guide_doc(request, slug, version_id, file_uuid):
|
||||||
"""Render one markdown guide document server-side (used by the switcher)."""
|
"""Render one markdown guide document server-side (used by the switcher)."""
|
||||||
version = get_object_or_404(
|
version = get_object_or_404(
|
||||||
|
|||||||
@@ -147,6 +147,18 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// The vanilla/base texture must always be loaded first, then features.
|
// The vanilla/base texture must always be loaded first, then features.
|
||||||
|
// Wide player models additionally always load L1Z0's custom skins
|
||||||
|
// alongside the default Steve skin (tracked in static/player_skins/).
|
||||||
|
if (entity === 'player') {
|
||||||
|
for (const name of ['destroyed_skin.png', 'russian_goat.png']) {
|
||||||
|
try {
|
||||||
|
const img = await loadImage('/static/player_skins/' + name);
|
||||||
|
baseTextures.push({ name: name, dataUrl: imageDataUrl(img) });
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('packs: skip player skin', name, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return baseTextures.concat(featureTextures);
|
return baseTextures.concat(featureTextures);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -244,7 +244,7 @@
|
|||||||
data-member="{{ model.member }}" data-name="{{ model.name }}"
|
data-member="{{ model.member }}" data-name="{{ model.name }}"
|
||||||
data-default-texture="{{ model.default_texture }}"
|
data-default-texture="{{ model.default_texture }}"
|
||||||
data-base-url="{% url 'library:pack_asset' project.slug versions.0.pk 'ASSET' %}"
|
data-base-url="{% url 'library:pack_asset' project.slug versions.0.pk 'ASSET' %}"
|
||||||
data-vanilla-base-url="{% url 'library:vanilla_asset' 'ASSET' %}"><i class="fas fa-cube"></i> Render</button>
|
data-vanilla-base-url="/static/vanilla/ASSET"><i class="fas fa-cube"></i> Render</button>
|
||||||
</div>
|
</div>
|
||||||
<p class="model-meta">{{ model.bones }} bones · {{ model.cubes }} cubes</p>
|
<p class="model-meta">{{ model.bones }} bones · {{ model.cubes }} cubes</p>
|
||||||
<div class="model-textures">
|
<div class="model-textures">
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# Packs site dependencies (Python 3.14)
|
||||||
|
Django==6.0.3
|
||||||
|
gunicorn==25.1.0
|
||||||
|
markdown-it-py==4.0.0
|
||||||
|
pillow==12.2.0
|
||||||
|
PyMySQL==1.1.2
|
||||||
|
whitenoise==6.12.0
|
||||||
@@ -28,5 +28,9 @@ else
|
|||||||
echo "To force re-run, use: $0 --force-setup"
|
echo "To force re-run, use: $0 --force-setup"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Rebuild the vanilla entity-texture index (gitignored generated file)
|
||||||
|
echo "Rebuilding vanilla entity-texture index..."
|
||||||
|
"$PYTHON_BIN" manage.py refresh_vanilla_index
|
||||||
|
|
||||||
echo "Starting Django development server on 0.0.0.0:8000..."
|
echo "Starting Django development server on 0.0.0.0:8000..."
|
||||||
exec "$PYTHON_BIN" manage.py runserver 0.0.0.0:8000
|
exec "$PYTHON_BIN" manage.py runserver 0.0.0.0:8000
|
||||||
|
|||||||
@@ -29,6 +29,10 @@ else
|
|||||||
echo "To force re-run, use: $0 --force-setup"
|
echo "To force re-run, use: $0 --force-setup"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Rebuild the vanilla entity-texture index (gitignored generated file)
|
||||||
|
echo "Rebuilding vanilla entity-texture index..."
|
||||||
|
"$PYTHON_BIN" manage.py refresh_vanilla_index
|
||||||
|
|
||||||
# Collect static files (served by gunicorn via whitenoise)
|
# Collect static files (served by gunicorn via whitenoise)
|
||||||
"$PYTHON_BIN" manage.py collectstatic --noinput
|
"$PYTHON_BIN" manage.py collectstatic --noinput
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user