커스텀 모델과 감정 표현
플러그인이 플레이어를 자기 모델로 그리고, 가만히 서 있을 때 감정 표현을 재생합니다. 샘플: custom_model.
모델은 게임의 뼈대를 그대로 써야 합니다. 그래서 걷기, 달리기, 수영, 잠들기, 도구 휘두르기 같은 게임의 모든 동작이 따로 만들지 않아도 그대로 재생됩니다. 뼈가 다르면 맞춰 주지 않고 거절합니다.
빠르게 만들기
- template.glb를 블렌더에서 엽니다. (
파일 › 가져오기 › glTF 2.0, Bone Dir는 Blender) - 뼈는 그대로 두고 메시만 새로 만들어 스키닝합니다. 뼈의 이름, 개수, 부모 관계를 바꾸면 안 됩니다.
파일 › 내보내기 › glTF 2.0, 형식 glTF Binary (.glb), 애니메이션 끄기, +Y Up 켜기.-
fix_model.py와 rig.json을 같은 폴더에 두고 정규화합니다.
python fix_model.py my_model.glb out.glb out.glb를 플러그인assets/plugins/<플러그인 이름>/에 넣고rules.json에 등록합니다.
4번을 건너뛰면 대부분 거절됩니다. 블렌더는 뼈의 기준 회전을 정확히 보존하지 못합니다. 아래를 향한 뼈(발, 엄지)가 20°쯤 틀어지고, 가져오기 옵션에 따라 더 많은 뼈가 돌아갑니다. 그대로 쓰면 발목이 꼬이므로 서버가 거절합니다.
fix_model.py는 뼈 위치와 메시 모양은 그대로 둔 채 회전을 게임 값으로 되돌리고, 바인드 행렬과 애니메이션 값을 다시 계산합니다.
체형은 바꿀 수 있습니다. 뼈의 위치를 옮기면 정규화 후에도 그대로 남습니다. 단, 뼈 길이는 원래의 0.5~2배 안이어야 합니다.
등록
{
"models_add": {
"blue_cat": {"model": "res://plugins/custom_model/blue_cat.glb", "name": "파란 고양이"}
},
"emotes_add": {
"wave": {"file": "res://plugins/custom_model/wave.glb", "name": "손 흔들기", "loop": false}
}
}
| 키 | 값 |
|---|---|
| 표의 키 (id) | 영문 소문자, 숫자, _, 32자 이하 |
model / file | 플러그인 자기 폴더의 .glb: res://plugins/<플러그인 이름>/..., 실제 파일은 assets/plugins/<플러그인 이름>/... |
name | 표시 이름 |
loop | (감정 표현) 끝나도 반복 |
다른 폴더나 게임의 파일은 쓸 수 없습니다.
코드
use greenhaven_plugin::*;
#[command("변신", "파란 고양이가 돼요")]
fn change(c: Command) {
c.player().set_model("blue_cat");
}
#[command("인사", "가만히 서서 손을 흔들어요")]
fn wave(c: Command) {
c.player().play_anim("wave");
}
#[on(Join)]
fn dress(e: Join) {
e.player().set_model("blue_cat"); // 접속할 때마다 입히려면
}
| 함수 | 하는 일 |
|---|---|
Player::set_model(id) | 이 서버에서 이 모델로 그림. 같은 월드의 모두에게 바로 보임 |
Player::clear_model() | 원래 모습으로 |
Player::play_anim(id) | 감정 표현 재생 |
Player::stop_anim() | 재생 중인 감정 표현 끝내기 |
동작 규칙
모델
- 연결되어 있는 동안만 유지됩니다. 계정의 옷차림은 바뀌지 않고 저장되지도 않습니다. 계속 입히려면
Join에서 다시 부르세요. - 서버를 나가면 아무것도 남지 않습니다. 다른 서버나 싱글플레이에 영향이 없습니다.
- 모델을 입는 동안 게임의 옷과 장식은 표시되지 않습니다.
- 도구는 게임과 같은 자리(오른손)에 들립니다.
- 없는 id는 아무 일도 하지 않고 서버 로그에 남습니다.
감정 표현
감정 표현은 가만히 서 있을 때만 재생되는 동작입니다.
- 걷기, 달리기, 점프, 수영, 잠자기, 도구 사용 중이면 시작되지 않습니다.
- 재생 중에 움직이거나 어떤 행동이든 하면 바로 끝나고 게임의 동작으로 돌아갑니다.
loop: true도 마찬가지입니다. - 같은 월드의 다른 플레이어에게도 보이고, 그 사람이 움직이면 똑같이 끝납니다.
- 모델을 입지 않은 기본 동물에게도 재생됩니다. 뼈대가 같기 때문입니다.
검사 규칙
모든 파일은 서버 시작 때 검사하고, 게임이 받을 때 다시 검사합니다.
- 서버에서 실패하면 그 항목만 빠지고 플러그인은 그대로 켜집니다. 로그에 이유가 나옵니다.
plugin my_plugin: models_add knight refused: the bone RightFoot is turned 26.4° from the rig's rest (at most 1°): export it from the template - 게임에서 실패하면 그 플레이어는 원래 모습으로 그려집니다.
공통
| 항목 | 규칙 |
|---|---|
| 형식 | GLB (glTF 2.0 바이너리). 전체 길이가 맞아야 하고 JSON + BIN 청크만 |
| 버퍼 | 파일 안에 하나. 외부 파일 경로 불가 |
| 접근자 | 모든 데이터가 범위 안. sparse 불가 |
| 확장 | extensionsRequired 불가. 재질과 노드의 확장 불가 |
| 그 외 금지 | 카메라, 조명, 노드의 matrix |
뼈대
| 항목 | 규칙 |
|---|---|
| 뼈 | rig.json의 81개 전부. 이름과 부모 관계 일치 |
| 기준 회전 | 뼈마다 1° 이내 |
| 배율 | 1 (±1%) |
| 길이 | 원래의 0.5~2배 |
| 노드 수 | 96개 이하 |
모델
| 항목 | 규칙 |
|---|---|
| 파일 크기 | 16MB 이하 |
| 삼각형 | 20,000개 이하 |
| 메시 / 재질 | 각각 4개 이하 |
| 스킨 | 정확히 1개, 조인트는 81개 뼈 전부. 모든 메시가 이 스킨에 묶임 |
| 정점 | 모든 정점의 조인트가 스킨 안의 뼈 |
| 프리미티브 | 삼각형만. 모프 타깃 불가 |
| 크기 | 높이는 게임 모델의 0.25~2배, 폭과 깊이는 2배 이하 |
| 이미지 | 4장 이하, PNG 또는 JPEG, 한 변 2048 이하, 파일에 내장 |
| 애니메이션 | 불가. 게임의 동작이 재생되고, 감정 표현은 별도 파일 |
감정 표현
| 항목 | 규칙 |
|---|---|
| 파일 크기 | 2MB 이하 |
| 내용 | 뼈대와 클립 1개. 메시, 스킨, 재질, 이미지 불가 |
| 채널 | 뼈의 회전. 이동은 Hips만. 크기 채널 불가 |
| 보간 | LINEAR 또는 STEP |
| 길이 | 30초 이하, 채널당 키 4096개 이하 |
블렌더의 감정 표현도 정규화합니다. 메시를 빼고 불필요한 채널을 지웁니다.
python fix_model.py --emote wave.glb out.glb
조심할 것
용량과 성능은 서버의 책임입니다. 받을 파일의 합이 200MB를 넘으면 서버 목록에
고사양으로 표시됩니다.
유료 상품을 흉내 낸 모델이나 저작권이 있는 캐릭터를 공개 서버에 올리면 서버 목록에서 제외될 수 있습니다.