저장 데이터 생성 시스템

목차

1. 요구 사항

2. 흐름도

3. 구현

        3.1. 저장 데이터 생성

4. 개발 의도

1. 시스템 요구 사항

Grid 기반 건축 시스템에서 구조물 상태를 저장하기 위해서는, 런타임에서 사용되는 데이터 구조를 그대로 저장하는 것이 아니라, 저장과 복원에 적합한 형태로 변환하는 과정이 필요하다.

현재 시스템은 구조물 데이터를 Dictionary<Vector3Int, ...>와 Dictionary<Edge, ...> 형태로 관리하고 있으며, 각 좌표는 구조물 전체 데이터를 공유하는 방식으로 연결되어 있다.

이 구조는 조회와 성능 측면에서는 효율적이지만, 직렬화에는 적합하지 않다.

Dictionary는 직렬화 시 키-값 구조를 그대로 유지하기 어렵고, 내부적으로 참조를 공유하는 구조 역시 저장 데이터로는 불안정하다.

따라서 저장 시스템은 다음 요구사항을 만족해야 한다.

구조물의 중복 정보를 제거하고, 구조물 단위로 데이터를 정리해야 하며, 직렬화 가능한 형태로 변환되어야 하고, 복원 시 동일한 구조를 다시 생성할 수 있어야 한다.

이 시스템은 단순 데이터 반환이 아니라, 런타임 Grid 상태를 저장 가능한 데이터 구조로 변환하는 계층이다.

2. 흐름도

저장 요청 발생

   ↓

GetSaveData 호출

   ↓

gridCellsDictionary / gridEdgesDictionary 순회

   ↓

구조물 단위 데이터로 변환 (중복 제거)

   ↓

PlacementGridSaveData 생성

   ↓

List 기반 저장 구조 구성

   ↓

저장 데이터 반환

이 흐름에서 중요한 점은 Dictionary를 그대로 저장하지 않는다는 것이다.

런타임에서는 좌표 기준으로 데이터를 저장하지만, 저장 시에는 구조물 기준으로 데이터를 재구성해야 한다.

3. 구현

3.1. 저장 데이터 생성
public PlacementGridSaveData GetSaveData()
{
    PlacementGridSaveData saveData = new();

    saveData.cellsData = new List<Vector3Int>();
    saveData.cellObjectData = new List<CellObjectSaveData>();

    saveData.edgesData = new EdgesData();
    saveData.edgesObjectData = new List<EdgeObjectSaveData>();

    HashSet<PlacedCellObjectData> visitedCellData = new();
    HashSet<PlacedEdgeObjectData> visitedEdgeData = new();

    foreach (var cell in gridCellsDictionary)
    {
        PlacedCellObjectData data = cell.Value;

        if (visitedCellData.Contains(data))
            continue;

        visitedCellData.Add(data);

        saveData.cellObjectData.Add(new CellObjectSaveData
        {
            origin = data.origin,
            structureID = data.structureID,
            rotation = data.rotation,
            objectRotation = data.objectRotation
        });

        saveData.cellsData.AddRange(data.PositionsOccupied);
    }

    foreach (var edge in gridEdgesDictionary)
    {
        PlacedEdgeObjectData data = edge.Value;

        if (visitedEdgeData.Contains(data))
            continue;

        visitedEdgeData.Add(data);

        saveData.edgesObjectData.Add(new EdgeObjectSaveData
        {
            origin = data.origin,
            structureID = data.structureID,
            rotation = data.rotation,
            objectRotation = data.objectRotation
        });

        saveData.edgesData.edges.AddRange(data.PositionsOccupied);
    }

    return saveData;
}

이 함수는 현재 Grid 상태를 저장 가능한 구조로 변환하는 함수다.

입력은 없으며, 내부에 저장된 Dictionary 데이터를 기반으로 PlacementGridSaveData를 생성하여 반환한다.

코드의 첫 부분에서는 PlacementGridSaveData를 생성하고, 내부 리스트들을 초기화한다.

여기서 중요한 점은 모든 저장 데이터가 List 기반으로 구성된다는 것이다.

List는 Unity 직렬화 시스템에서 안정적으로 저장 가능한 구조이며, Dictionary보다 저장/로드에 적합하다.

그 다음 HashSet<PlacedCellObjectData>와 HashSet<PlacedEdgeObjectData>가 생성된다.

이 부분이 핵심이다.

현재 Grid 데이터는 하나의 구조물이 여러 좌표에 걸쳐 동일한 데이터를 공유하는 구조다.

따라서 Dictionary를 그대로 순회하면 동일한 구조물이 여러 번 반복해서 등장하게 된다.

HashSet은 중복을 허용하지 않는 자료구조로, 이미 처리한 구조물 데이터를 다시 처리하지 않도록 필터링하는 역할을 한다.

여기서 중요한 점은 좌표가 아니라 구조물 데이터 객체 자체를 기준으로 중복을 제거한다는 것이다.

구조물 단위로 한 번만 저장되도록 만드는 구조다.

첫 번째 foreach는 gridCellsDictionary를 순회한다.

각 셀의 value는 PlacedCellObjectData이며, 이 데이터는 구조물 전체를 대표한다.

먼저 HashSet을 이용해 이미 처리한 구조물인지 확인하고, 처리되지 않은 경우에만 저장을 진행한다.

saveData.cellObjectData.Add(...)에서는 구조물의 핵심 정보만 추출해서 저장한다.

여기에는 origin, structureID, rotation, objectRotation이 포함된다.

이 정보는 구조물을 다시 생성하는 데 필요한 최소 정보다.

그 다음 saveData.cellsData.AddRange(data.PositionsOccupied)가 실행된다.

이 코드는 구조물이 점유한 모든 셀 좌표를 저장한다.

AddRange는 List에 여러 요소를 한 번에 추가하는 C# 메서드로, 반복문 없이 컬렉션 전체를 추가할 수 있다.

Edge 부분도 동일한 흐름을 가진다.

gridEdgesDictionary를 순회하면서 구조물 단위로 중복을 제거하고, Edge 기반 구조물 정보를 저장한다.

이때 Edge 좌표는 edgesData.edges 리스트에 저장된다.

이 함수의 핵심은 다음과 같다.

Dictionary 기반의 좌표 중심 구조를, List 기반의 구조물 중심 구조로 변환한다.

그리고 중복 데이터를 제거하여 저장 효율을 높인다.

4. 개발 의도

저장 시스템의 핵심 의도는 런타임 데이터 구조와 저장 데이터 구조를 분리하는 것이다.

런타임에서는 빠른 조회를 위해 Dictionary와 참조 공유 구조를 사용하지만, 저장 단계에서는 중복을 제거하고 직렬화 가능한 형태로 변환해야 한다.

또한 구조물 단위로 데이터를 저장하도록 설계한 것도 중요하다.

좌표 단위로 저장하면 동일한 구조물이 여러 번 저장되기 때문에 데이터 크기가 증가하고, 복원 시에도 비효율이 발생한다.

따라서 구조물 단위로 한 번만 저장하고, 점유 좌표는 별도로 관리하는 방식이 선택되었다.

결과적으로 이 시스템은 단순히 데이터를 반환하는 함수가 아니라, Grid 상태를 저장/복원에 적합한 구조로 변환하는 핵심 계층이며, 이 구조 덕분에 저장 데이터는 가볍고, 복원 과정은 명확하게 유지된다.