Add facial diversity gate for character assets
This commit is contained in:
@@ -16,6 +16,12 @@
|
||||
python3 scripts/validate_content.py
|
||||
```
|
||||
|
||||
- For character image asset changes, run:
|
||||
|
||||
```bash
|
||||
python3 scripts/validate_assets.py
|
||||
```
|
||||
|
||||
## Creative Direction
|
||||
|
||||
- This is a romance dating game for adult players.
|
||||
@@ -24,4 +30,6 @@ python3 scripts/validate_content.py
|
||||
- Prefer semi-realistic, high-quality, cinematic character art when creating base images or visual references.
|
||||
- The target look is closer to polished Korean dating-sim key art than pure photography: realistic lighting and fabric, but idealized illustrated faces, refined skin, and expressive character silhouettes.
|
||||
- Even shy, pure-hearted, or reserved characters should retain visible adult charm through styling, silhouette, gaze, posture, and lighting.
|
||||
- Preserve distinct facial identities across the cast. Do not accept images that look like the same model in different clothes.
|
||||
- Use `docs/art/facial_identity_matrix.md` when writing prompts or approving character images.
|
||||
- Avoid making characters look underage, childlike, or styled as school students.
|
||||
|
||||
@@ -9,8 +9,11 @@
|
||||
- `data/characters.json`: 22명의 성인 여성 캐릭터와 각자의 루트 구조
|
||||
- `data/locations.json`: 맵 클릭 지점, 주요 시간대, 우연한 만남 태그
|
||||
- `data/progression.json`: 만남에서 연인 전환까지의 공통 진행 규칙
|
||||
- `data/character_assets.json`: 캐릭터 기본 이미지의 통과 상태와 파일 경로
|
||||
- `docs/game_structure.md`: 게임 루프와 시스템 설계 메모
|
||||
- `docs/art/facial_identity_matrix.md`: 캐릭터별 얼굴형, 눈매, 헤어, 표정 차별화 기준
|
||||
- `scripts/validate_content.py`: 캐릭터 나이와 장소 참조 무결성 검증
|
||||
- `scripts/validate_assets.py`: 캐릭터 이미지 매니페스트와 PNG 해상도 검증
|
||||
|
||||
## 콘텐츠 원칙
|
||||
|
||||
@@ -22,4 +25,5 @@
|
||||
|
||||
```bash
|
||||
python3 scripts/validate_content.py
|
||||
python3 scripts/validate_assets.py
|
||||
```
|
||||
|
||||
@@ -8,9 +8,13 @@ Base standing images should feel like high-end promotional portraits for a matur
|
||||
|
||||
## Current Files
|
||||
|
||||
- `han_seoyun_v1.png`: current preferred semi-realistic style target.
|
||||
- `yu_harin_v1.png`: accepted semi-realistic base image.
|
||||
- `kang_mirae_v1.png`: accepted semi-realistic base image.
|
||||
- `han_seoyun_v1.png`: semi-realistic style/composition candidate; needs facial diversity revision.
|
||||
- `yu_harin_v1.png`: semi-realistic base candidate; needs facial diversity revision.
|
||||
- `kang_mirae_v2.png`: accepted semi-realistic base image with revised facial identity.
|
||||
- `kang_mirae_v1.png`: earlier semi-realistic base candidate; same-face risk remains.
|
||||
- `jung_naeun_v1.png`: semi-realistic base candidate; needs facial diversity revision.
|
||||
- `oh_sera_v1.png`: semi-realistic base candidate; needs facial diversity revision.
|
||||
- `park_minseo_v1.png`: semi-realistic base candidate; needs facial diversity revision.
|
||||
- `style_references/semirealistic_main_reference.png`: user-approved reference for the target look.
|
||||
- `style_tests/han_seoyun_photoreal_test.png`: pure photoreal comparison candidate.
|
||||
- `style_tests/kang_mirae_photoreal_test.png`: pure photoreal comparison candidate.
|
||||
@@ -23,3 +27,11 @@ Base standing images should feel like high-end promotional portraits for a matur
|
||||
- Use `<character_id>_v<number>.png` for main candidates.
|
||||
- Use `style_tests/<character_id>_<style>_test.png` for experiments.
|
||||
- Keep generated originals in their default generator folder; copy selected candidates into this project.
|
||||
|
||||
## Validation
|
||||
|
||||
```bash
|
||||
python3 scripts/validate_assets.py
|
||||
```
|
||||
|
||||
`accepted` should be used only after the image passes both route-fit and facial-diversity review. Use `needs_revision` for useful style/composition candidates that still look too similar to other cast members.
|
||||
|
||||
BIN
assets/characters/jung_naeun_v1.png
Normal file
BIN
assets/characters/jung_naeun_v1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.9 MiB |
BIN
assets/characters/kang_mirae_v2.png
Normal file
BIN
assets/characters/kang_mirae_v2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.9 MiB |
BIN
assets/characters/oh_sera_v1.png
Normal file
BIN
assets/characters/oh_sera_v1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.2 MiB |
BIN
assets/characters/park_minseo_v1.png
Normal file
BIN
assets/characters/park_minseo_v1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.1 MiB |
114
data/character_assets.json
Normal file
114
data/character_assets.json
Normal file
@@ -0,0 +1,114 @@
|
||||
{
|
||||
"version": "0.1.0",
|
||||
"style": {
|
||||
"id": "premium_semirealistic",
|
||||
"reference": "assets/characters/style_references/semirealistic_main_reference.png",
|
||||
"description": "Premium semi-realistic Korean dating-sim key art with realistic lighting and fabric, idealized illustrated faces, polished skin, and expressive adult silhouettes."
|
||||
},
|
||||
"minimum_dimensions": {
|
||||
"width": 800,
|
||||
"height": 1600
|
||||
},
|
||||
"assets": [
|
||||
{
|
||||
"character_id": "han_seoyun",
|
||||
"status": "needs_revision",
|
||||
"path": "assets/characters/han_seoyun_v1.png",
|
||||
"notes": "Style and composition candidate. Needs a facial identity pass because the current set trends toward similar facial structure."
|
||||
},
|
||||
{
|
||||
"character_id": "yu_harin",
|
||||
"status": "needs_revision",
|
||||
"path": "assets/characters/yu_harin_v1.png",
|
||||
"notes": "Strong shy bookstore route candidate. Needs a more distinct face shape, eye shape, and expression signature."
|
||||
},
|
||||
{
|
||||
"character_id": "kang_mirae",
|
||||
"status": "accepted",
|
||||
"path": "assets/characters/kang_mirae_v2.png",
|
||||
"notes": "Accepted sharp career route image after facial identity revision: shorter sleek hair, narrower eyes, sharper jawline, and controlled executive expression."
|
||||
},
|
||||
{
|
||||
"character_id": "jung_naeun",
|
||||
"status": "needs_revision",
|
||||
"path": "assets/characters/jung_naeun_v1.png",
|
||||
"notes": "Strong tsundere cafe route candidate. Needs a sharper mischievous facial identity distinct from Han/Yu."
|
||||
},
|
||||
{
|
||||
"character_id": "baek_chaewon",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"character_id": "oh_sera",
|
||||
"status": "needs_revision",
|
||||
"path": "assets/characters/oh_sera_v1.png",
|
||||
"notes": "Strong mature florist route candidate. Needs a softer late-twenties mature face distinct from younger routes."
|
||||
},
|
||||
{
|
||||
"character_id": "moon_jia",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"character_id": "lim_sohee",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"character_id": "cha_yuri",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"character_id": "shin_yerim",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"character_id": "kim_doa",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"character_id": "park_minseo",
|
||||
"status": "needs_revision",
|
||||
"path": "assets/characters/park_minseo_v1.png",
|
||||
"notes": "Strong fitness trainer route candidate. Needs a sportier facial identity and more distinct facial proportions."
|
||||
},
|
||||
{
|
||||
"character_id": "seo_irin",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"character_id": "yoon_gayoung",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"character_id": "choi_ria",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"character_id": "hong_sua",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"character_id": "lee_bom",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"character_id": "go_eunjae",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"character_id": "ryu_haena",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"character_id": "nam_juhee",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"character_id": "marina",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"character_id": "song_arin",
|
||||
"status": "pending"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -22,6 +22,8 @@ An image passes only when all of these are true:
|
||||
|
||||
- The character clearly reads as an adult.
|
||||
- Outfit, pose, expression, and silhouette match the character brief.
|
||||
- Face identity is distinct from the rest of the cast, not just the same face with different hair or clothing.
|
||||
- Face shape, eye shape, brow style, nose/mouth proportions, hairstyle, makeup intensity, and expression habit should all reinforce the character archetype.
|
||||
- Even shy or pure-hearted characters still carry visible adult sensual charm through styling, posture, and lighting.
|
||||
- Body type is distinct from the rest of the cast.
|
||||
- Face is appealing, stable, and not uncanny.
|
||||
@@ -32,15 +34,27 @@ An image passes only when all of these are true:
|
||||
## Cast Variety Targets
|
||||
|
||||
- Avoid making every character the same face, height, pose, and body shape.
|
||||
- Do not default every character to the same oval face, long dark hair, soft eyes, small nose, and gentle smile.
|
||||
- Rotate visual tone: warm, shy, sharp, glamorous, mature, athletic, artistic, elegant, casual.
|
||||
- Use fashion to signal route identity before the player reads text.
|
||||
- Keep sensuality character-specific: shy routes should feel quietly irresistible, career routes sharply confident, public-image routes glamorous, and mature routes restrained but intense.
|
||||
|
||||
## Facial Identity Rules
|
||||
|
||||
- Every character prompt must include at least three facial differentiators: face shape, eye shape, brow style, hairstyle, makeup level, expression habit, or facial maturity.
|
||||
- Similar hairstyle and face structure are allowed only when the route concept demands it; otherwise vary hair length, bangs, parting, styling, and volume.
|
||||
- Approval requires comparing the candidate against existing assets at thumbnail size and full size.
|
||||
- If a candidate looks like another character in cosplay, mark it `needs_revision` instead of `accepted`.
|
||||
|
||||
## Current Asset Notes
|
||||
|
||||
- `assets/characters/han_seoyun_v1.png`: current preferred semi-realistic style target.
|
||||
- `assets/characters/yu_harin_v1.png`: accepted semi-realistic base image for the shy bookstore route.
|
||||
- `assets/characters/kang_mirae_v1.png`: accepted semi-realistic base image for the sharp career route.
|
||||
- `assets/characters/han_seoyun_v1.png`: current preferred semi-realistic style/composition candidate; needs facial diversity revision.
|
||||
- `assets/characters/yu_harin_v1.png`: strong shy bookstore candidate; needs facial diversity revision.
|
||||
- `assets/characters/kang_mirae_v2.png`: accepted sharp career image after facial identity revision.
|
||||
- `assets/characters/kang_mirae_v1.png`: earlier sharp career candidate; same-face risk remains.
|
||||
- `assets/characters/jung_naeun_v1.png`: strong tsundere cafe candidate; needs facial diversity revision.
|
||||
- `assets/characters/oh_sera_v1.png`: strong mature florist candidate; needs facial diversity revision.
|
||||
- `assets/characters/park_minseo_v1.png`: strong fitness trainer candidate; needs facial diversity revision.
|
||||
- `assets/characters/style_references/semirealistic_main_reference.png`: user-approved reference for the target look.
|
||||
- `assets/characters/style_tests/han_seoyun_photoreal_test.png`: useful pure-photoreal comparison, but no longer the main direction.
|
||||
- `assets/characters/style_tests/kang_mirae_photoreal_test.png`: useful pure-photoreal comparison, but no longer the main direction.
|
||||
|
||||
48
docs/art/facial_identity_matrix.md
Normal file
48
docs/art/facial_identity_matrix.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# Facial Identity Matrix
|
||||
|
||||
The cast must not look like one model wearing different outfits. Use this matrix when writing image prompts and during QA. Each generated candidate should be checked against nearby routes for face, hair, expression, and silhouette overlap.
|
||||
|
||||
## Global Face-Diversity Rules
|
||||
|
||||
- Every prompt must specify at least three of: face shape, eye shape, brow style, nose/mouth impression, hair length, hair volume, parting/bangs, makeup intensity, expression habit, and maturity impression.
|
||||
- Avoid defaulting to long dark hair, oval face, soft eyes, small nose, and gentle smile.
|
||||
- If two candidates look interchangeable at thumbnail size, both require revision.
|
||||
- Hair color should stay plausible for the setting, but tone, styling, cut, bangs, and volume should vary aggressively.
|
||||
- The semi-realistic style reference defines rendering quality, not one shared face.
|
||||
|
||||
## Character Face Anchors
|
||||
|
||||
| ID | Face Shape | Eyes/Brows | Hair Identity | Expression Habit | QA Notes |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `han_seoyun` | Soft oval with fuller cheeks | Warm almond eyes, softly arched brows | Long dark brown, loose side wave, natural volume | Gentle smile with quiet possessiveness | Keep her warm and domestic; avoid making every soft route copy her. |
|
||||
| `yu_harin` | Small heart-shaped face, delicate jaw | Downturned shy eyes, fine straight brows | Chestnut-black half-up hair or low loose braid, wispy bangs | Looks slightly away before smiling | Should feel bookish and reserved, not identical to Seo-yun's open warmth. |
|
||||
| `kang_mirae` | Long refined face, sharper jawline | Narrow catlike eyes, clean assertive brows | Sleek shoulder-length dark hair, side part, polished blowout | Cool evaluating gaze, minimal smile | Must read sharper and more executive than other dark-haired characters. |
|
||||
| `jung_naeun` | Compact round face with sharper chin | Large alert eyes, angled expressive brows | High ponytail or short layered bob, loose side bangs | Pout, side-eye, hidden blush | Tsundere energy should distinguish her from shy routes. |
|
||||
| `baek_chaewon` | V-line glam face, defined cheekbones | Long-lashed smiling eyes, arched brows | Voluminous auburn-brown waves, glossy party styling | Playful smile with unreadable eyes | Should look socially dangerous and glamorous, not soft domestic. |
|
||||
| `oh_sera` | Mature oval face, softer jaw, calm cheekbones | Deep gentle eyes, relaxed brows | Long dark hair in low elegant waves or half-up twist | Sad calm smile, composed gaze | Older and more serene than the early-20s routes. |
|
||||
| `moon_jia` | Bright round face, lively cheeks | Wide energetic eyes, lifted brows | Medium brown ponytail, messy festival ribbon or colorful clip | Big open grin, forward energy | High energy and youthful adult, but never childlike. |
|
||||
| `lim_sohee` | Petite oval face, soft lower cheeks | Slightly anxious round eyes, timid brows | Short bob or shoulder-length soft curls, pastel hairpin | Nervous small smile, searching gaze | Vulnerable without looking underage. |
|
||||
| `cha_yuri` | Long model face, high cheekbones | Cool long eyes, straight detached brows | Long black straight hair, center part, glossy runway styling | Neutral almost unreadable stare | Tall, aloof, and editorial; avoid warm smiles. |
|
||||
| `shin_yerim` | Elegant oval face, refined cheekbones | Calm intelligent eyes, graceful brows | Neat low chignon or sleek updo | Polite smile with subtle teasing | Classical and poised, not office-cold like Mi-rae. |
|
||||
| `kim_doa` | Fresh adult heart face, clear jawline | Bright curious eyes, natural brows | Medium-length dark hair with campus-casual waves | Curious direct smile | Clearly adult college styling, no school cues. |
|
||||
| `park_minseo` | Athletic face, healthy cheekbones, defined jaw | Direct confident eyes, strong brows | High sporty ponytail, flyaway strands, practical styling | Competitive smirk | Sporty confidence; avoid the same soft beauty face. |
|
||||
| `seo_irin` | Slender angular face, artistic fragility | Dreamy tired eyes, slightly uneven brows | Messy wolf cut or long loose artist hair with paint smudges | Distant half-smile, emotional stare | More eccentric and melancholic than Harin. |
|
||||
| `yoon_gayoung` | Natural round-oval face | Friendly crescent eyes, relaxed brows | Short ponytail or casual shoulder bob | Playful grin that turns sincere | Comfortable friend energy, not polished glamour. |
|
||||
| `choi_ria` | Slim influencer V-face | Camera-aware eyes, precise brows | Long glossy styled hair with trendy highlights | Practiced camera smile | Public-image polish; avoid looking like Chaewon by using sharper modern styling. |
|
||||
| `hong_sua` | Mature soft-square face | Knowing deep eyes, confident brows | Shoulder-length wavy dark hair, side-swept | Relaxed direct smile | Strong 30-year-old bar-owner maturity. |
|
||||
| `lee_bom` | Soft round face, gentle cheeks | Clear kind eyes, natural brows | Light brown loose waves, flower clip or airy bangs | Bright smile with stubborn eyes | Soft daylight route; avoid childlike proportions. |
|
||||
| `go_eunjae` | Sharp rectangular-oval face | Piercing eyes, straight severe brows | Sleek black bob or low ponytail | Dry neutral expression | Legal precision, colder and more severe than Mi-rae. |
|
||||
| `ryu_haena` | Petite V-face, fuller lips | Sweet upturned eyes, groomed brows | Long curled hair with glossy salon finish | Sweet possessive smile | Cute-adult and glamorous, not timid. |
|
||||
| `nam_juhee` | Strong oval face, defined jaw | Steady protective eyes, firm brows | Tied-back practical hair, clean duty styling | Calm controlled expression | Athletic authority, not fashion-model aloofness. |
|
||||
| `marina` | Mixed international features, sunlit cheekbones | Expressive open eyes, confident brows | Wavy brown hair, travel scarf or loose windblown styling | Playful direct smile | Free-spirited and culturally distinct without caricature. |
|
||||
| `song_arin` | Petite mature oval face | Cautious warm eyes, soft brows | Short wavy bob or neat low bun | Careful smile, guarded warmth | Second-chance maturity, not anxious like Sohee. |
|
||||
|
||||
## Approval Gate
|
||||
|
||||
Before marking an asset `accepted`, compare it to every existing candidate:
|
||||
|
||||
1. Thumbnail check: the face and hair must be identifiable without reading the filename.
|
||||
2. Full-size check: eyes, brows, jawline, mouth, hairstyle, and expression habit must match the matrix.
|
||||
3. Route check: outfit, posture, and environment must still match the character's story role.
|
||||
4. Adult appeal check: the character should feel mature and alluring without relying on explicit content.
|
||||
5. Revision rule: if the image looks like another cast member in different clothes, keep it as `needs_revision`.
|
||||
@@ -8,6 +8,7 @@ These briefs are the preferred direction for base character images. They should
|
||||
- Full-body solo woman, clearly adult, vertical composition.
|
||||
- Cinematic lighting, realistic fabric and space, idealized illustrated faces, polished skin rendering, and clean character-select readability.
|
||||
- Character-specific sensuality through silhouette, fashion, gaze, posture, and lighting.
|
||||
- Character-specific face identity through face shape, eye shape, brow style, hairstyle, and expression habit. Use `docs/art/facial_identity_matrix.md`.
|
||||
- No school uniform, childlike styling, ambiguous age, explicit nudity, sex acts, text, logo, watermark, or extra characters.
|
||||
|
||||
## Character Briefs
|
||||
|
||||
109
scripts/validate_assets.py
Normal file
109
scripts/validate_assets.py
Normal file
@@ -0,0 +1,109 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Validate generated character asset manifest and PNG files."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import struct
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
DATA = ROOT / "data"
|
||||
PNG_SIGNATURE = b"\x89PNG\r\n\x1a\n"
|
||||
|
||||
|
||||
def load_json(path: Path) -> dict:
|
||||
with path.open("r", encoding="utf-8") as handle:
|
||||
return json.load(handle)
|
||||
|
||||
|
||||
def fail(message: str) -> None:
|
||||
print(f"ERROR: {message}", file=sys.stderr)
|
||||
raise SystemExit(1)
|
||||
|
||||
|
||||
def png_dimensions(path: Path) -> tuple[int, int]:
|
||||
with path.open("rb") as handle:
|
||||
signature = handle.read(8)
|
||||
if signature != PNG_SIGNATURE:
|
||||
fail(f"{path} is not a PNG file")
|
||||
|
||||
length_bytes = handle.read(4)
|
||||
chunk_type = handle.read(4)
|
||||
if len(length_bytes) != 4 or chunk_type != b"IHDR":
|
||||
fail(f"{path} is missing a PNG IHDR chunk")
|
||||
|
||||
length = struct.unpack(">I", length_bytes)[0]
|
||||
if length < 8:
|
||||
fail(f"{path} has an invalid PNG IHDR chunk")
|
||||
|
||||
width, height = struct.unpack(">II", handle.read(8))
|
||||
return width, height
|
||||
|
||||
|
||||
def main() -> None:
|
||||
characters_doc = load_json(DATA / "characters.json")
|
||||
assets_doc = load_json(DATA / "character_assets.json")
|
||||
|
||||
character_ids = [character["id"] for character in characters_doc["characters"]]
|
||||
character_id_set = set(character_ids)
|
||||
asset_entries = assets_doc["assets"]
|
||||
asset_ids = [entry["character_id"] for entry in asset_entries]
|
||||
|
||||
if set(asset_ids) != character_id_set:
|
||||
missing = sorted(character_id_set.difference(asset_ids))
|
||||
extra = sorted(set(asset_ids).difference(character_id_set))
|
||||
fail(f"asset manifest mismatch; missing={missing}, extra={extra}")
|
||||
|
||||
if len(asset_ids) != len(set(asset_ids)):
|
||||
fail("asset manifest contains duplicate character ids")
|
||||
|
||||
minimum = assets_doc["minimum_dimensions"]
|
||||
min_width = minimum["width"]
|
||||
min_height = minimum["height"]
|
||||
accepted = 0
|
||||
|
||||
reference = ROOT / assets_doc["style"]["reference"]
|
||||
if not reference.exists():
|
||||
fail(f"style reference is missing: {reference}")
|
||||
png_dimensions(reference)
|
||||
|
||||
for entry in asset_entries:
|
||||
status = entry["status"]
|
||||
if status not in {"accepted", "needs_revision", "pending", "rejected"}:
|
||||
fail(f"{entry['character_id']} has invalid status {status}")
|
||||
|
||||
if status not in {"accepted", "needs_revision"}:
|
||||
continue
|
||||
|
||||
if status == "accepted":
|
||||
accepted += 1
|
||||
|
||||
if "path" not in entry:
|
||||
fail(f"{entry['character_id']} has status {status} but no path")
|
||||
|
||||
path = ROOT / entry["path"]
|
||||
if not path.exists():
|
||||
fail(f"{entry['character_id']} asset is missing: {path}")
|
||||
|
||||
width, height = png_dimensions(path)
|
||||
if width < min_width or height < min_height:
|
||||
fail(
|
||||
f"{entry['character_id']} asset is too small: "
|
||||
f"{width}x{height}, minimum {min_width}x{min_height}"
|
||||
)
|
||||
|
||||
revision_count = sum(
|
||||
1 for entry in asset_entries if entry["status"] == "needs_revision"
|
||||
)
|
||||
print(
|
||||
"Validated character asset manifest: "
|
||||
f"{accepted}/{len(asset_entries)} accepted, "
|
||||
f"{revision_count} needs revision."
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user