Project_WL/Assets/Script/Map/MapData.cs

198 lines
9.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using CodeStage.AntiCheat.ObscuredTypes;
using System;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;
public class MapData : MonoBehaviourSingletonTemplate<MapData>
{
public Material material_skybox;
public GameObject[] gos_map; // 미궁에서 사용 (여러 맵 중 하나 오픈)
public ChapterPortal m_ChapterPortal;
[SerializeField] public List<MapZoneData> m_MapZoneData;
// 2026-09-05 #746 (배경 어두움 수정) 실측: Ingame 씬은 베이크 데이터가 없고 앰비언트 모드가 Skybox 라 런타임 앰비언트 프로브가 ≈0.04(검정)이었다.
// - 로비는 material_skybox 가 null, 필드맵은 skybox 만 바꾸고 프로브를 재생성하지 않아 #744 의 ambientIntensity 조정은 무효였다.
// - 값은 코드 상수가 아니라 맵 프리팹 필드로 둔다(C45 · 맵마다 인스펙터에서 조정). 색은 선형 값(스크립트 대입은 색공간 변환 없음).
[Header("조명 · 런타임 앰비언트 (#746 · 맵 프리팹에서 조정)")]
[Tooltip("Trilight/Flat 은 skybox 와 무관하게 즉시 적용. Skybox 모드는 material_skybox 가 있고 updateEnvironmentFromSkybox 가 켜진 경우에만 프로브가 생성된다.")]
public UnityEngine.Rendering.AmbientMode ambientMode = UnityEngine.Rendering.AmbientMode.Trilight;
// 기본값 = PD "더 밝게"(2026-09-05) 반영: 로비 실측 평균 휘도 .60/.42/.18 → 0.282, 백색 1.0/.71/.31 → 0.325. 백색 계열을 기본으로.
public Color ambientSky = new Color(1.00f, 1.00f, 1.00f, 1f);
public Color ambientEquator = new Color(0.71f, 0.58f, 0.48f, 1f);
public Color ambientGround = new Color(0.31f, 0.31f, 0.45f, 1f);
[Range(0f, 2f)] public float ambientIntensity = 1f; // Skybox 모드 전용 (Trilight/Flat 은 무시)
[Range(0f, 1f)] public float reflectionIntensity = 0.3f;
[Tooltip("Skybox 모드에서 DynamicGI.UpdateEnvironment() 를 호출해 skybox 기준 프로브를 만든다(맵 로딩 시 1회 비용).")]
public bool updateEnvironmentFromSkybox = false;
// 2026-09-06 #756: 힘민지 로비 모드는 PCActor.Set_Obj 가 무기 장착을 건너뛴다(휴식 공간 설계). 시작 맵(WL_Start)처럼
// 로비 타입이어도 무기를 보여야 하는 맵은 이 플래그를 켠다 → StartWakeSequence 가 플레이어 인식 직후 Change_Weapon() 호출.
[Header("플레이어 표시 (#756)")]
[Tooltip("로비 모드 맵에서도 플레이어 무기를 장착·표시한다 (WL_Start 등)")]
public bool showWeaponInLobby = false;
// 2026-09-06 #764 (PD: "몬스터도 플레이어가 갈 수 없는 지형을 뚫고 이동하거나 이동 불가 지형에 생성되지 않도록")
// 실측(WL_Start · 4m 격자 1806점): NavMesh 위 1144점 중 플레이어 시작 지점에서 도달 가능한 곳은 427점(37%)뿐이다.
// 기존 DSUtil.Get_RandomPos_onNavMesh 는 ① 스냅 반경으로 MobGenRange 를 그대로 써서 최대 2×range 까지 튀고
// ② NavMesh.CalculatePath 의 반환값만 보고 status(PathComplete)를 보지 않아 **부분 경로(벽 너머·다른 섬)를 통과**시킨다.
// → 스포너 19개 × 30점 표집 실측에서 51%(295/570)가 플레이어 시작 지점에서 도달 불가였다.
// 아래 값은 전부 **기본값 = 기존 동작**이라 이 값을 세팅하지 않은 기존 맵은 아무것도 바뀌지 않는다(C8).
[Header("몬스터 스폰 · 이동 (#764 · 맵 프리팹에서 조정)")]
[Tooltip("스포너가 몬스터 생성 위치를 뽑을 때 완전 경로(PathComplete)가 나오는 지점만 쓴다. " +
"WL_Start 처럼 NavMesh 가 섬으로 끊긴 맵에서 켠다. 끄면 기존 표집 방식 그대로.")]
public bool spawnRequireReachableFromPlayer = false;
[Tooltip("스폰 후보의 무작위 점을 NavMesh 로 끌어당길 최대 거리(m). 크면 벽 너머 다른 섬으로 스냅된다. " +
"0 이하면 기존 동작(MobGenRange 를 스냅 반경으로 사용). 실측 권장 = 2")]
public float spawnSnapRadius = 0f;
[Tooltip("스폰 후보 표집 재시도 횟수. 0 이하면 기존 기본값(50)을 쓴다.")]
public int spawnSampleTries = 0;
[Tooltip("몬스터가 넉백·끌어당김·점프로 NavMesh 밖으로 밀렸을 때 되돌릴 최대 거리(m). " +
"0 이하면 스냅하지 않는다(기존 동작). 몬스터에만 적용되고 플레이어·펫·NPC 는 영향이 없다.")]
public float mobNavSnapRadius = 0f;
// 2026-09-06 #771 (WL_Nature 시작 맵): 힘민지 맵은 Start() 에서 RenderSettings.fog=false 로 안개를 껐다.
// Demo_01(LMHPOLY) 처럼 원경이 살아 있는 야외 맵은 안개가 룩의 핵심이라 **맵 프리팹 필드**로 되살린다(#746 과 같은 방식).
// 기본값 = fogEnabled false → 이 값을 켜지 않은 기존 맵은 동작이 전혀 바뀌지 않는다(C8).
[Header("안개 (#771 · 맵 프리팹에서 조정)")]
[Tooltip("끄면 기존 동작 그대로 RenderSettings.fog = false.")]
public bool fogEnabled = false;
public FogMode fogMode = FogMode.Linear;
public Color fogColor = new Color(0.492f, 0.611f, 0.821f, 1f);
[Tooltip("Linear 전용 — 이 거리부터 안개가 시작된다. 게임 카메라는 플레이어에서 3 m 뒤라 12 m 는 캐릭터 바로 뒤다.")]
public float fogStart = 30f;
[Tooltip("Linear 전용 — 이 거리에서 안개가 100%.")]
public float fogEnd = 250f;
[Tooltip("Exponential 계열 전용.")]
public float fogDensity = 0.0017f;
void Start()
{
RenderSettings.skybox = material_skybox;
Apply_Lighting();
Apply_Fog();
if (m_ChapterPortal)
{
var mapData = MyValue.MyChoiceMapData;
var isclear = ServerInfo.Ins.m_ServerData.MapData_isClearChaper(mapData.n_MapID, mapData.n_Difficult);
m_ChapterPortal.Set_NextChapter(isclear);
}
}
// #746: 프리팹 필드의 앰비언트 설정을 RenderSettings 에 적용한다(Start 에서 1회 · 인스펙터 튜닝 후 재호출 가능).
public void Apply_Lighting()
{
RenderSettings.ambientMode = ambientMode;
switch (ambientMode)
{
case UnityEngine.Rendering.AmbientMode.Trilight:
RenderSettings.ambientSkyColor = ambientSky;
RenderSettings.ambientEquatorColor = ambientEquator;
RenderSettings.ambientGroundColor = ambientGround;
break;
case UnityEngine.Rendering.AmbientMode.Flat:
RenderSettings.ambientLight = ambientSky;
break;
default: // Skybox: 프로브는 material_skybox 로부터 명시적으로 재생성해야 값이 바뀐다
RenderSettings.ambientIntensity = ambientIntensity;
if (updateEnvironmentFromSkybox && material_skybox != null)
DynamicGI.UpdateEnvironment();
break;
}
RenderSettings.reflectionIntensity = reflectionIntensity;
}
// #771: 안개도 맵 프리팹 필드에서 적용한다. fogEnabled=false 면 기존 동작(끔) 그대로.
public void Apply_Fog()
{
RenderSettings.fog = fogEnabled;
if (!fogEnabled) return;
RenderSettings.fogMode = fogMode;
RenderSettings.fogColor = fogColor;
RenderSettings.fogStartDistance = fogStart;
RenderSettings.fogEndDistance = fogEnd;
RenderSettings.fogDensity = fogDensity;
}
public MapZoneData Get_MapZoneData(int index) { return m_MapZoneData[index]; }
public void Set_MazeMap(int index)
{
DSUtil.InActivateGameObjects(gos_map, index);
Set_MazeNextPortal(index, false);
}
public void Set_MazeNextPortal(int index, bool active)
{
var mzd = Get_MapZoneData(index);
if (!DSUtil.CheckNull(mzd.go_mazeNextPortal))
mzd.go_mazeNextPortal.SetActive(active);
}
}
[Serializable]
public class MapZoneData
{
public GameObject go_portal;
public float CamRot_Portal;
public GameObject go_reincarnation;
public float CamRot_Reincarnation;
public GameObject go_mazeNextPortal;
public Transform tf_Farmer;
public Transform[] tf_Obj;
}
public class ChoiceMapData
{
ObscuredInt _Difficult;
public int n_Difficult
{
get { return _Difficult; }
set { _Difficult = value; _Difficult.RandomizeCryptoKey(); }
}
ObscuredInt _MapID;
public int n_MapID
{
get { return _MapID; }
set { _MapID = value; _MapID.RandomizeCryptoKey(); }
}
ObscuredInt _PortalIndex;
public int n_PortalIndex
{
get { return _PortalIndex; }
set { _PortalIndex = value; _PortalIndex.RandomizeCryptoKey(); }
}
ObscuredInt _DungeonLv;
public int n_DungeonLv
{
get { return _DungeonLv; }
set { _DungeonLv = value; _DungeonLv.RandomizeCryptoKey(); }
}
protected ObscuredDouble _NightmareBeforeDmg;
public double d_NightmareBeforeDmg
{
get { return _NightmareBeforeDmg; }
set { _NightmareBeforeDmg = value; _NightmareBeforeDmg.RandomizeCryptoKey(); }
}
public BattleMapConfigTableData Get_MapData() { return table_battlemapconfig.Ins.Get_Data(n_MapID); }
public DungeonMapConfigTableData Get_DungeonMapData_orNull()
{
var mapData = Get_MapData();
return mapData.e_Dungeon == eDungeon.None ? null :
table_dungeonmapconfig.Ins.Get_Data_orNull(mapData.e_Dungeon, n_DungeonLv);
}
public int Get_DungeonIndex()
{
var dgData = Get_DungeonMapData_orNull();
return DSUtil.CheckNull(dgData) ? 0 : MyEnumToInt.Ins.Get_Int(dgData.e_DungeonType) - 1;
}
public void Set_MazeMapIndex()
{
n_PortalIndex = Random.Range(0, table_GlobalValue.Ins.Get_Int("MazeMapCount"));
}
}