Project_WL/Assets/WL/Island/WLIslandSave.cs

120 lines
6.0 KiB
C#

// ─────────────────────────────────────────────────────────────────────────────
// WLIslandSave.cs — 섬 세이브 파일 이름을 **경로와 무관하게 하나로** 고정한다.
//
// ■ 왜 필요한가 (Lead 실측 · 2026-09-13 · 816f 가 발견)
// `IslandManager.cs:119` 가 `saveFileName = SceneManager.GetActiveScene().name` 이라
// 같은 섬인데도 **들어온 경로에 따라 세이브가 갈린다**:
// · 섬 씬만 단독 Play → `Level01.dat`
// · 게임 정식 경로(로그인 → Load_Map → 섬이 Additive) → **`InGame.dat`**
// → 섬을 키워 놔도 다른 경로로 들어가면 초기 상태가 나온다.
//
// ■ PD 결정(2026-09-13): 「세이브가 경로마다 갈리면 안돼. 그냥 기존 세이브를
// 초기화하고 단일 경로로 맞춰」 → 이름을 하나로 고정한다.
//
// ■ 원본 수정은 `IslandManager.cs` **1줄**(그 대입문)뿐이다 — WL 하우스 규칙의
// 「1줄 훅 + 새 파일」 그대로. `enabled_ = 0` 이면 원래 동작(씬 이름)으로 돌아간다.
// ─────────────────────────────────────────────────────────────────────────────
using UnityEngine;
namespace WL.Island
{
public sealed class WLIslandSaveSettings : ScriptableObject
{
[Tooltip("0 이면 원본 동작(활성 씬 이름)으로 되돌아간다.")]
public int enabled_ = 1;
[Tooltip("모든 경로가 공유할 세이브 파일 이름(확장자 제외).")]
public string saveName = "WL_Island";
[Tooltip("1 이면 해석 결과를 로그로 남긴다.")]
public int verboseLog = 0;
static WLIslandSaveSettings s_cache;
public static WLIslandSaveSettings Get()
{
if (s_cache == null) s_cache = Resources.Load<WLIslandSaveSettings>("WL/WLIslandSaveSettings");
return s_cache;
}
}
public static class WLIslandSave
{
/// <summary>
/// `IslandManager.Awake` 의 **기존 1줄 훅**이 부른다. 끄면 받은 값을 그대로 돌려준다.
///
/// 🔴 WL-816g — 이 호출은 `IslandManager.Awake` 안에서 `LoadGameData()` **바로 앞**에 있다
/// (`IslandManager.cs:119` vs `:120`). 그래서 「새 게임 시작 골드」와 「세이브 1회 초기화」를
/// 걸 수 있는 **유일한 시점**이다 — 덕분에 FI 원본에 새 줄을 한 줄도 넣지 않았다.
/// </summary>
public static string ResolveSaveName(string sceneName)
{
var cfg = WLIslandSaveSettings.Get();
string resolved = sceneName;
if (cfg != null && cfg.enabled_ != 0 && !string.IsNullOrEmpty(cfg.saveName))
{
resolved = cfg.saveName;
if (cfg.verboseLog != 0)
Debug.Log("[WL-816] 섬 세이브 이름 '" + sceneName + "' → '" + resolved + "' (경로 무관 고정)");
}
WLIslandStart.Prepare(resolved);
return resolved;
}
}
/// <summary>
/// 새 게임의 시작 상태(WL-816g §3) — **시작 골드 10** + 필요하면 세이브 1회 초기화.
/// FI 기본 시작 골드는 500 이다(`IslandManager.cs:30` `startingMoney`).
/// </summary>
public static class WLIslandStart
{
public static int LastStartCoin = -1;
public static bool DidReset;
public static string LastLog = "";
const string kTokenKey = "WL_Island_SaveToken";
static System.Reflection.FieldInfo s_startingMoney;
/// <summary>`IslandManager.Awake` 안(= `LoadGameData()` 직전)에서 단 한 번 불린다.</summary>
public static void Prepare(string saveName)
{
var cfg = WLIslandSettings.Instance;
if (cfg == null || cfg.enabled_ == 0 || cfg.gateFlowEnabled == 0) return;
// ① 세이브 1회 초기화 — 토큰이 바뀌었을 때만(PD 에게 새 초기 상태를 보여 줄 때)
if (!string.IsNullOrEmpty(cfg.saveResetToken) &&
PlayerPrefs.GetString(kTokenKey, "") != cfg.saveResetToken)
{
try
{
string path = Application.persistentDataPath + "/" + saveName + ".dat";
if (System.IO.File.Exists(path)) { System.IO.File.Delete(path); DidReset = true; }
}
catch (System.Exception ex) { Debug.LogWarning("[WL-816g] 세이브 초기화 실패 — " + ex.Message); }
PlayerPrefs.SetString(kTokenKey, cfg.saveResetToken);
PlayerPrefs.SetInt(cfg.dungeonUnlockPrefsKey, 0); // 해금한 던전도 0 개로
PlayerPrefs.Save();
WLIslandBridge.ClearPending(); // 보류 보상도 비운다(정적 값까지)
}
// ② 시작 골드 — `startingMoney` 는 `data == null`(세이브 없음)일 때만 쓰인다(IslandManager.cs:397)
if (cfg.applyStartCoin == 0) return;
var mgr = CryingSnow.FarmingIsland.IslandManager.Instance;
if (mgr == null) return;
if (s_startingMoney == null)
s_startingMoney = typeof(CryingSnow.FarmingIsland.IslandManager).GetField("startingMoney",
System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
if (s_startingMoney == null) return;
s_startingMoney.SetValue(mgr, cfg.startCoin);
LastStartCoin = cfg.startCoin;
LastLog = "시작 골드 500 → " + cfg.startCoin + (DidReset ? " · 세이브 초기화함" : " · 기존 세이브 유지");
if (cfg.verboseLog != 0) Debug.Log("[WL-816g] " + LastLog);
}
}
}