최종 갱신 (KST)

← 일감 목록
T-058

서버 — 인벤토리 칸 위치 저장 · 정렬 요청 · 자리 이동 (자원 · 캐릭터)

진우 Closed 우선순위 보통 목표 261010 · 보관됨

T-015에서 갈라져 나왔다 (2026-09-16). 클라가 [정렬] 버튼을 먼저 넣었지만 순서를 세션 동안만 기억한다 — 재접속하면 사라진다.

배경

인벤토리 격자는 i번째 항목을 i번째 칸에 그린다. 그런데 그 순서가 지금은 서버가 보내 준 목록 순서다. 사람이 정한 자리가 아니라서, 정렬해도 다시 접속하면 원래대로 돌아가고 드래그로 옮길 수도 없다.

칸 위치를 서버가 들고 있어야 재접속·다른 기기에서도 자리가 유지된다. 클라가 저장하면(PlayerPrefs 등) 계정과 기기가 어긋나는 순간 조용히 틀린다.

지금 패킷에는 위치가 없다 — ItemInfo { ItemId, Count }, CharacterInfo { CharacterId, CharacterTid, … }.

정렬 기준 셋 (2026-09-20 추가)

원래 이 일감의 정렬은 클라 임시 정렬과 같은 규칙 하나였다. QA 피드백으로 '이름순'·'보유 수량순' 이 더해져 기준이 셋이 됐다 — 자원이 150종을 넘어 등급 하나로는 찾을 수가 없다 (0920-피드백 및 답변 정리.md 2번).

기준 자체는 클라가 먼저 넣는다 → T-073. 줄 세우는 것은 받아 둔 목록을 다시 정렬하는 것이라 서버가 필요 없다. 이 일감이 맡는 것은 "그 순서가 재접속해도 남는가" 다 — 지금은 로그인할 때 버려서(세션 한정) 껐다 켜면 원래대로 돌아간다. 그래서 여기서 정할 기준 목록은 T-073과 같아야 한다 — 다르면 서버 정렬을 켠 순간 순서가 바뀐다. (찾기(검색·필터)도 서버 없이 클라만으로 간다 → T-069.)

2026-09-25 — 클라가 먼저 같은 규칙으로 움직인다

장착·배치로 개체가 빠질 때 뒤의 것이 앞으로 당겨지던 문제를 클라에서 고쳤다(T-044). 지금 클라는 떠난 칸을 비워 두고, 들어오는 것은 앞에서부터 첫 빈 칸에 넣는다 — 다만 세션 한정이다.

서버 규칙을 여기에 맞춰 주셔야 한다 — 아래 "새 항목은 첫 빈 칸에 둔다"와 같은 규칙이다. 다르면 서버 위치를 켜는 순간 자리가 한 번 뒤집힌다. ⚠️ 장비만 EquipInfo.SlotPosition이 이미 있는데, 클라는 그것을 칸 번호로 쓰지 않는다(도착 순서로만). 자원·캐릭터에 같은 필드가 없어 세 탭의 자리 규칙이 갈라지기 때문이다 — 세 탭을 같은 필드·같은 규칙으로 함께 옮겨 주셔야 한다. ※ 장착 중인 장비도 인벤토리 칸을 그대로 차지한다(2026-09-25 결정) — 서버가 SlotPosition을 비우지 않는 지금 동작이 맞다. 비우면 안 된다.

할 일

2026-10-01 서버 완료 — 설계 Server/docs/인벤토리-창고.md · 계획 2026-10-01-T-058-칸위치.md. 칸은 개체가 든다(Item.Slot·Character.Slot·Equip.SlotPosition), 계산은 순수 함수 StorageSlots·StorageSort. 인벤토리 50칸과 별도 보관소 창고는 T-107로 넘어갔다 — 이 일감의 container 컬럼이 그 자리를 이미 잡아 뒀다.

  • [x] 칸 번호 필드 — ItemInfo·ItemChangeInfo·CharacterInfo에 Container·Slot, EquipInfo에 Container
  • [x] DB 컬럼 — t_user_inventory는 PK (user_id, container, item_id)로 다시 만들고 slot 추가, t_character에 container·slot, t_user_equip에 container. 기존 데이터는 ID 순으로 0부터 (Server/Shared/migrations/2026-10-01-storage-slot.sql)
  • [x] 스냅샷과 증분 푸시에 칸 번호를 싣는다 — 모든 자원 저장이 ItemChangeInfo.Slot을 그대로 쓴다
  • [x] 새 항목은 첫 빈 칸 — 채취·뽑기·치트·우편 캐릭터 수령(#47)까지. 캐릭터는 장비처럼 지급 전에 칸을 예약한다(연속 뽑기 겹침 방지)
  • [x] 수량이 0이 된 자원의 칸 — 행을 지우고 칸을 비운다(기존 동작 그대로). 다음 새 자원이 그 칸을 쓴다
  • [x] 정렬 요청 C_StorageSortRequest { Container, Tab, SortKey, Order } — 클라 CompareByRule과 같은 규칙. ⚠️ 오름차순은 규칙 전체를 뒤집고, 배치·장착 중인 것은 방향과 무관하게 맨 뒤(클라 코드 대조로 확정)
  • [x] 자리 이동 요청 C_StorageMoveSlotRequest — 빈 칸이면 이동, 차 있으면 교환. 응답 S_StorageSlotsResponse
  • [x] 거절 코드 — StorageSlotOutOfRange(1100) · StorageSlotEmpty(1101) · InvalidStorageSortKey(1102) · StorageSlotPending(1103 — 도착 칸이 지급 대기로 예약됨)
  • [x] 테스트 — 칸 계산·정렬 순서·자원 칸·캐릭터 예약·저장 SQL·재로그인·이동·정렬 (전체 721 통과)
  • [x] 프로토콜 미러 커밋 — d42cc04
  • [x] 실서버 확인 (2026-10-01, 더미 클라 · 계정 test) — 이동 0→10 저장 · 재로그인 후 10 유지 · 등급 정렬 후 0~5 촘촘히 · 칸 0을 비우고 치트 지급한 새 자원이 칸 0
  • [x] 클라(T-044)와 맞물려 확인 — 2026-10-06 사용자 실측(이동 · 교환 · 정렬 · 재접속 유지)

완료 조건

더미 클라이언트로 정렬·자리 교환을 보낸 뒤 재로그인해도 스냅샷의 칸 번호가 그대로이고, 새로 채취한 자원이 첫 빈 칸에 들어간다. Unity 미러가 커밋돼 클라 컴파일이 깨지지 않는다.

막고 있는 것 / 선행 일감

  • 없음

관련 커밋

  • 13bc73e · 0223dd5 — 설계 · 계획
  • 39cde95 — 칸 계산 순수 함수
  • 3088d4a — 정렬 순서
  • d42cc04 — 패킷 · Unity 미러
  • ee920cb — 자원 칸
  • ff42f75 — 캐릭터 칸 · 지급 예약 · 우편 수령
  • b461323 — DB 마이그레이션 · 저장 SQL
  • 9aac60c — 자리 이동 요청
  • 3c09ee0 — 정렬 요청
  • 8f3c345 — 더미 클라 메뉴
  • 2d89897 — 재로그인 테스트의 전역 UserManager 누수 수정 (T-089 빈도)
  • 07568fc — 리뷰 반영: 지급 대기 칸을 정렬·이동이 덮지 않게
  • 클라 T-044 커밋 — 클라 연동 확인으로 완료 (2026-10-06)

참고

  • 클라 임시 정렬: Assets/Scripts_Client/UI/Inventory/InventoryGridPresenter/InventorySlotSource.cs(Sort · _rank) — 규칙은 ResourceSlotSource·CharacterSlotSource의 CompareForSort
  • 이 일감이 끝나면 클라 T-044가 임시 기억을 걷어내고 서버 위치로 바꾼다
  • Server/MikaProtocol/MikaPacket.cs · Server/MikaProtocol/PacketInfo.cs(ItemInfo·CharacterInfo)