[WL-816g] 발판 1회성(자리마다 한 번) + 새 타일 외곽선 맞춤 + 던전 로딩 보정 (#816)
PD 추가 지시 2건. ① 「던전 열기는 한 번만 · 이후 같은 자리에 또 등장하면 안 된다」 던전 한 줄 = 발판 한 자리(`WLDungeonDef.platformUseFarm`·`platformPosition`). 값을 치르면 그 자리는 영영 비고 다음 발판은 표가 지정한 **다른 자리**에 선다. 해금 수는 PlayerPrefs 에 남겨 껐다 켜도 유지된다(실측: Play 재시작 후에도 던전 1 그대로 · 밭 자리 발판 없음 · 다음 발판만 (-2,0,-2) 가격 30). FI `RefreshIsland` 의 가격표 재생성이 우리 발판을 되살리지 않는 것도 실측 (섬 확장 4→5칸 후 발판 수 1 유지 · 자리 그대로). 덤으로, 골드가 많을 때 가만히 서서 던전이 연달아 팔리던 것도 막았다. ② 던전 진입 멈춤 던전 씬에는 `MobControlMgrList` 가 0개다(실측: WL_Dungeon01·02·ArenaProto 전부 0). 섬과 같은 이유로 로딩 칸 0 이 안 찬다 → 던전 표의 씬 이름을 로딩 보정 대상에 포함. ③ §1 남은 몫 — 새로 연 타일이 `WL/HullOutline` 패스를 못 받아(슬롯 1 vs 2) 경계에서 테두리 유무가 갈렸다. 열린 직후 기존 타일의 머티리얼 배열을 그대로 물려준다(새 머티리얼 0개). 실측: 8칸 전부 재질 조합 1가지. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
71d29a4621
commit
b661d16bb1
|
|
@ -48,6 +48,7 @@ MonoBehaviour:
|
|||
gateFlowEnabled: 1
|
||||
hideFarms: 1
|
||||
farmReHideDelaySeconds: 3
|
||||
matchNewTileMaterials: 1
|
||||
dungeonUnlockPrefsKey: WL_Island_DungeonsUnlocked
|
||||
dungeonUnlockPrices:
|
||||
- 10
|
||||
|
|
|
|||
|
|
@ -292,10 +292,10 @@ namespace WL.Island
|
|||
return haveCenter;
|
||||
}
|
||||
|
||||
/// <summary>섬이 나중에 열리면 그 섬의 밭도 다시 숨긴다(확장해도 밭이 안 보이게).</summary>
|
||||
/// <summary>섬이 나중에 열리면 ① 그 섬의 밭을 다시 숨기고 ② 타일 재질을 기존 타일과 맞춘다(§1).</summary>
|
||||
static void HookIslandActivation(WLIslandSettings cfg, Scene scene)
|
||||
{
|
||||
if (cfg.hideFarms == 0) return;
|
||||
if (cfg.hideFarms == 0 && cfg.matchNewTileMaterials == 0) return;
|
||||
var islands = Object.FindObjectsByType<FIIsland>(FindObjectsInactive.Include, FindObjectsSortMode.None);
|
||||
for (int i = 0; i < islands.Length; i++)
|
||||
{
|
||||
|
|
@ -311,7 +311,8 @@ namespace WL.Island
|
|||
|
||||
static void OnIslandActivated(WLIslandSettings cfg, FIIsland isl)
|
||||
{
|
||||
if (cfg == null || cfg.gateFlowEnabled == 0 || cfg.hideFarms == 0) return;
|
||||
if (cfg == null || cfg.gateFlowEnabled == 0) return;
|
||||
if (cfg.hideFarms == 0 && cfg.matchNewTileMaterials == 0) return;
|
||||
var runner = WLIslandBridge.Runner;
|
||||
if (runner == null || isl == null) return;
|
||||
runner.StartCoroutine(Co_ReHide(cfg, isl));
|
||||
|
|
@ -319,10 +320,14 @@ namespace WL.Island
|
|||
|
||||
static IEnumerator Co_ReHide(WLIslandSettings cfg, FIIsland isl)
|
||||
{
|
||||
// 확장 애니메이션(DOScale 1초) + 소품 배치(AnimateSoils 0.05초 × 30칸)가 끝나기를 기다린다
|
||||
// 확장 애니메이션(DOScale 1초) + 소품 배치(AnimateSoils 0.05초 × 30칸) + 룩 재적용
|
||||
// (`WLIslandLookSettings.rebuildDelaySeconds` = 1.4 실측)이 끝나기를 기다린다.
|
||||
yield return new WaitForSeconds(cfg.farmReHideDelaySeconds);
|
||||
if (isl == null) yield break;
|
||||
|
||||
MatchTileMaterials(cfg, isl);
|
||||
|
||||
if (cfg.hideFarms == 0) yield break;
|
||||
var farms = isl.GetComponentsInChildren<FIFarm>(true);
|
||||
for (int i = 0; i < farms.Length; i++)
|
||||
{
|
||||
|
|
@ -336,6 +341,82 @@ namespace WL.Island
|
|||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────
|
||||
// §1 새 타일 경계 색차 — 남은 몫(외곽선 패스)
|
||||
//
|
||||
// 실측(2026-09-13 · Play):
|
||||
// · **바닥 색 자체는 Lead 의 `b1e58d795`(대비 복제 제외)로 해결됐다** — 새로 연 타일도
|
||||
// 기존 타일과 **같은 머티리얼 인스턴스** `Farm_IslandTop_Demo#83780` 을 쓴다.
|
||||
// · 다만 새로 연 타일은 슬롯이 **1개**뿐이다(기존 타일은 2개 = 바닥 + `WL/HullOutline`).
|
||||
// `WLReferenceLook.Apply` 가 씬 로드 때 **활성 렌더러만** 훑는데 잠긴 타일은 꺼져 있어
|
||||
// 외곽선 패스를 못 받는다. 그래서 **경계에서 테두리 유무가 갈린다.**
|
||||
// 조치: 열린 직후, 이미 열려 있는 타일의 머티리얼 배열을 **그대로** 물려준다(새 머티리얼 0개).
|
||||
// ─────────────────────────────────────────────────────────────────
|
||||
public static int TilesMatched, SlotsMatched;
|
||||
|
||||
static void MatchTileMaterials(WLIslandSettings cfg, FIIsland isl)
|
||||
{
|
||||
if (cfg.matchNewTileMaterials == 0 || isl == null) return;
|
||||
|
||||
var mine = isl.GetComponentsInChildren<Renderer>(true);
|
||||
if (mine.Length == 0) return;
|
||||
|
||||
// 기준 = 이미 열려 있고 **슬롯이 더 많은** 타일(= 외곽선을 받은 타일)
|
||||
FIIsland refIsl = null;
|
||||
int bestSlots = 0;
|
||||
var all = Object.FindObjectsByType<FIIsland>(FindObjectsInactive.Include, FindObjectsSortMode.None);
|
||||
for (int i = 0; i < all.Length; i++)
|
||||
{
|
||||
var o = all[i];
|
||||
if (o == null || o == isl || !o.IsUnlocked || !o.gameObject.activeInHierarchy) continue;
|
||||
if (o.gameObject.scene != isl.gameObject.scene) continue;
|
||||
var r = o.GetComponent<MeshRenderer>();
|
||||
if (r == null) continue;
|
||||
int n = r.sharedMaterials != null ? r.sharedMaterials.Length : 0;
|
||||
if (n > bestSlots) { bestSlots = n; refIsl = o; }
|
||||
}
|
||||
if (refIsl == null) return;
|
||||
|
||||
// 🔴 이름으로 짝을 지으면 **타일 본체**(GameObject 이름이 `Island (3)` / `Island (6)` 처럼 다 다르다)가
|
||||
// 안 맞는다(실측 — 첫 시도에서 본체만 슬롯 1개로 남았다). 루트 기준 **상대 경로**로 짝 짓는다.
|
||||
var refs = refIsl.GetComponentsInChildren<Renderer>(true);
|
||||
var byPath = new Dictionary<string, Renderer>(refs.Length);
|
||||
for (int j = 0; j < refs.Length; j++)
|
||||
if (refs[j] != null) byPath[RelPath(refIsl.transform, refs[j].transform)] = refs[j];
|
||||
|
||||
int changed = 0;
|
||||
for (int i = 0; i < mine.Length; i++)
|
||||
{
|
||||
var m = mine[i];
|
||||
if (m == null || m is ParticleSystemRenderer) continue;
|
||||
var mm = m.sharedMaterials;
|
||||
if (mm == null || mm.Length == 0 || mm[0] == null) continue;
|
||||
|
||||
Renderer r;
|
||||
if (!byPath.TryGetValue(RelPath(isl.transform, m.transform), out r) || r == null) continue;
|
||||
var rm = r.sharedMaterials;
|
||||
if (rm == null || rm.Length <= mm.Length || rm[0] != mm[0]) continue;
|
||||
m.sharedMaterials = rm; // 같은 인스턴스 배열 = 픽셀이 같아진다
|
||||
changed++; SlotsMatched += rm.Length - mm.Length;
|
||||
}
|
||||
if (changed > 0)
|
||||
{
|
||||
TilesMatched++;
|
||||
WLIslandBridge.Log(cfg, "새 타일 재질 맞춤 — " + isl.name + " 렌더러 " + changed +
|
||||
"개를 기존 타일(" + refIsl.name + ")과 같은 배열로(외곽선 포함)");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>타일 루트 기준 상대 경로(프리팹 인스턴스끼리 짝 짓는 열쇠 · 루트 자신은 빈 문자열).</summary>
|
||||
static string RelPath(Transform root, Transform t)
|
||||
{
|
||||
if (t == root) return "";
|
||||
string s = t.name;
|
||||
var p = t.parent;
|
||||
while (p != null && p != root) { s = p.name + "/" + s; p = p.parent; }
|
||||
return s;
|
||||
}
|
||||
|
||||
/// <summary>우리가 끈 것만 되살린다(C8).</summary>
|
||||
public static void RestoreFarms()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -220,9 +220,15 @@ namespace WL.Island
|
|||
"꺼진 오브젝트에서 코루틴을 시작해 콘솔 에러가 난다.")]
|
||||
public int hideFarms = 1;
|
||||
|
||||
[Tooltip("섬이 나중에 열렸을 때 그 밭을 다시 숨기기까지 기다리는 초(확장 연출 + 흙칸 연출이 끝날 시간).")]
|
||||
[Tooltip("섬이 나중에 열렸을 때 그 밭을 다시 숨기고 타일 재질을 맞추기까지 기다리는 초 " +
|
||||
"(확장 연출 1초 + 흙칸 연출 + 룩 재적용 1.4초가 끝날 시간).")]
|
||||
public float farmReHideDelaySeconds = 3.0f;
|
||||
|
||||
[Tooltip("🔴 §1 — 1 이면 **새로 열린 타일**의 머티리얼 배열을 이미 열려 있는 타일과 **같게** 만든다. " +
|
||||
"실측: 바닥 색 자체는 이미 같지만(main b1e58d795), 새 타일만 외곽선 패스(WL/HullOutline)를 " +
|
||||
"못 받아 경계에서 테두리 유무가 갈린다. 새 머티리얼을 만들지 않고 기존 배열을 물려준다.")]
|
||||
public int matchNewTileMaterials = 1;
|
||||
|
||||
[Tooltip("해금된 던전 수를 적어 두는 PlayerPrefs 키(FI 세이브 파일은 건드리지 않는다).")]
|
||||
public string dungeonUnlockPrefsKey = "WL_Island_DungeonsUnlocked";
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue