2026-10-06 — ✅ 완료. 클라가 슬롯 설정 효율 줄 "속도 가산"에 레벨 항을 따로 표시했고(
레벨 +64% · 특성 · 장비), 사용자 실측으로 서버CurrentWorkSpeed와 맞는 것을 확인했다 — 이슈 #35 닫음.2026-10-06 — 재정의: 레벨 효과 = 작업속도 자동 가산 (이슈 #35 기획·서버·클라 동의) — 서버·엑셀·문서 구현 완료. 적성 포인트(수동 찍기 · 산업별 상한 150칸)는 철거했다. 적성은
CharacterTable값으로 고정되고, 레벨은CharacterLevelTable.SpeedAddPermille만큼 속도에 가산된다 — 아래 "2026-10-06 재정의" 절.2026-10-05 — 태웅: 자동 가산 방향에 동의한다. 이슈 #35에 코멘트로 남겼다 — 서버 구현 대기. 클라는 먼저 슬롯 설정(캐릭터 줄·배치 카드)과 슬롯 목록에 캐릭터 레벨을 표시했다(
이름 Lv27). 가산이 들어오면 슬롯 설정의 효율 줄 "속도 가산"(T-095가 만든 특성·장비 내역)에 레벨 항을 따로 더한다 — 장비 가산에 섞지 않는다. 2026-09-24 — ⏸ 기획 간소화를 요청했다 → 이슈 #35. 적성 포인트(수동 찍기 · 캐릭터·산업별 상한 150칸)가 방치형에 과하다고 보고 레벨 자동 가산을 제안했다. 답을 받기 전까지 클라 화면을 만들지 않는다 — 동의되면 화면 자체가 사라진다. 2026-09-17 — 레벨 효과가 적성 포인트로 확정됐고 서버 구현까지 끝났다 → 캐릭터 5.4. 남은 것은 클라 화면뿐이다. 2026-09-13 — 경험치 획득식·레벨 곡선을 확정하고 서버 누적·레벨업·저장·푸시까지 구현했다.
배경
t_character에 level·exp 컬럼을 만들어 두고 Character 객체까지 싣고 있었지만
아무 데서도 읽지 않았다. 캐릭터 속도는 CharacterTable의 고정 적성값으로만 정해져서,
레벨이 올라도 아무 일도 일어나지 않는다 — 이 부분은 여전히 그렇다(레벨 효과 미정).
2026-09-13 확정 — 경험치 획득식 · 레벨 곡선
→ 캐릭터 5.2
| 항목 | 값 |
|---|---|
| 획득 시점 | 판정 1회 성립마다 (WorkStation.Settle이 돌려주는 JudgeCount 단위) |
| 획득량 | IndustryLevelTable.ExpPerJudge — Lv1 1 → Lv5 81 (레벨당 ×3, RequiredScore와 같은 등비) |
| 레벨 곡선 | CharacterLevelTable.RequiredExp — 그 레벨에 도달하는 데 직전 레벨에서 필요한 양. Lv2 10 → 레벨당 ×1.2 (내림) |
| 만렙 | 100 (테이블 마지막 행). 만렙에서는 더 쌓지 않는다 |
| 레벨업 | 필요치를 채우면 +1, 남은 경험치는 이월. 한 정산에서 여러 레벨 가능 |
| 저장 | t_character.exp = 현재 레벨에서 쌓은 양 (누적이 아니다) |
2026-09-13 구현 — 서버
| 조각 | 위치 |
|---|---|
| 레벨 곡선 보관소 (마지막 행 = 만렙) | Server/WSGameServer/Common/CharacterLevelCatalog.cs |
| 경험치 가산 · 레벨업 · 이월 · 만렙 처리 | Character.GainExp |
정산 시 JudgeCount × ExpPerJudge를 배치 캐릭터에 가산 |
User.WorkStation.cs SettleWorkStation → User.Character.cs GrantWorkExp |
확정값 저장 (UPDATE t_character SET level, exp) |
Repository/CharacterGrowthRepository.cs |
| 바뀐 개체 1건 푸시 | S_CharacterSyncResponse(PacketId 21) — Unity ServerPacketHandler.CharacterSynced 이벤트까지 |
| 테스트 17건 | CharacterGrowthTest · CharacterLevelCatalogTest · UserCharacterGrowthTest |
2026-09-17 확정 — 레벨 효과 = 적성 포인트
→ 캐릭터 5.4
| 항목 | 값 |
|---|---|
| 포인트 | 10레벨마다 1 (CharacterLevelTable.AptitudePoint) · 만렙까지 10 |
| 사용 | 원할 때 산업 하나 +1 · 안 쓴 건 남는다 · 되돌리기 없음 |
| 상한 | 캐릭터·산업별 CharacterTable FarmingCap…HuntingCap · 0인 산업도 1로 |
| 저장 | t_character farming_bonus…hunting_bonus — 찍은 양만. 남은 포인트 = 번 총합 − 찍은 합 |
| 패킷 | AptitudeInfo.Cap · CharacterInfo.AptitudePoints · C_AptitudeUpRequest/S_AptitudeUpResponse · 결과 코드 NoAptitudePoint·AptitudeAtCap |
| 반영 | 찍으면 정산 → 속도 재계산 → 슬롯 싱크 |
2026-10-06 재정의 — 레벨 효과 = 작업속도 가산
속도 = 적성기본값(적성 고정) × (1 + 장비 + 특성 + 레벨) × 전역배수
| 항목 | 값 |
|---|---|
| 데이터 | CharacterLevelTable.SpeedAddPermille — 그 레벨의 가산 총량(누적값). 초안 레벨당 +1% (Lv1 0 → Lv100 990‰) |
| 적성 | CharacterTable 기본값 그대로 — 찍기·상한 없음 |
| 반영 | 레벨이 오르면 정산 → 속도 재계산 → 바뀐 슬롯 싱크 (정산 경로 · 치트 경로 둘 다) |
| 클라 | 가산값은 GameData 미러(CharacterLevelTable)에서 읽는다 — 패킷 추가 없음 |
| 조각 | 위치 |
|---|---|
| 레벨 → 가산 | CharacterLevelCatalog.SpeedAddAt · User.GetLevelSpeedAdd |
| 속도식 | User.WorkStation.cs ResolveSlotSpeed — .Add(GetLevelSpeedAdd(...)) |
| 레벨업 시 재계산 | SettleWorkStation 끝에서 ApplyWorkStationSpeed · 치트 GiveCharacterExp는 RefreshWorkStationSpeed |
| 테스트 | CharacterLevelCatalogTest · UserCharacterGrowthTest 3건 (가산 반영 · 소급 없음 · 배치 시 가산) |
| DB 마이그레이션 | Server/Shared/migrations/2026-10-06-drop-aptitude-bonus.sql — 새 서버는 보너스 컬럼을 읽지 않으므로 돌리기 전에도 동작은 같다 |
철거한 것 (2026-09-17 적성 포인트)
- 엑셀
CharacterLevelTable.AptitudePoint·CharacterTableFarmingCap…HuntingCap - DB
t_characterfarming_bonus…hunting_bonus(마이그레이션) - 패킷
C_AptitudeUpRequest(32)/S_AptitudeUpResponse(33) ·AptitudeInfo.Cap·CharacterInfo.AptitudePoints· 결과 코드 700·701 — 번호는 결번 - 서버
AptitudeBonus·TryRaiseAptitude·RaiseAptitude·CharacterAptitudeRepository·CharacterTableValidator· 우편·경매 캐릭터의Bonus
할 일 (2026-10-06 재정의)
- [x] 엑셀 —
CharacterLevelTable.AptitudePoint→SpeedAddPermille·CharacterTable상한 5컬럼 삭제 - [x] 서버 — 속도식에 레벨 가산
.Add()· 레벨업 시 슬롯 속도 재계산 (테스트) - [x] 서버 — 적성 포인트 경로 철거 (위 목록)
- [x] DB 마이그레이션 파일 —
t_character보너스 5컬럼 삭제 (game.sqlite3적용은 서버를 끄고) - [x] 기획 문서 — 캐릭터 5.4 외 이슈 #35 목록
- [x] 이슈 #35 → 클라로 공 넘기기 (2026-10-06)
- [x] 클라 — 슬롯 설정 효율 줄 "속도 가산"에 레벨 항 표시 · 실측 후 #35 닫기 (2026-10-06 · 태웅)
할 일 (2026-09-13 ~ 09-17 — 끝난 것)
- [x] 경험치 획득 경로 결정 → 판정 1회마다 (2026-09-13)
- [x] 레벨업 곡선 결정 →
CharacterLevelTable100행 (2026-09-13) - [x] 경험치 누적 · 레벨업 구현 +
t_character저장 (2026-09-13) - [x] 서버 → 클라 푸시
S_CharacterSyncResponse+ Unity 핸들러·이벤트 (2026-09-13) - [x] 클라 반영 → T-052로 분리 (담당 클라 ·
PlayerDataModel병합 + 레벨·경험치 표시) - [x] 레벨 → 적성/속도 기여식 결정 → 적성 포인트 (2026-09-17)
- [x]
CharacterTable과의 관계 정리 → 기본값은 테이블, 찍은 보너스는 DB, 실효 적성 = 합 (2026-09-17) - [x] 엑셀 —
CharacterTable상한 5컬럼(초안: 등급표 윗값) ·CharacterLevelTable.AptitudePoint(2026-09-17) - [x] DB —
t_character보너스 5컬럼 (2026-09-17) - [x] 프로토콜 —
AptitudeInfo.Cap·CharacterInfo.AptitudePoints·C_AptitudeUpRequest(27)/S_AptitudeUpResponse(28) · 결과 코드 600~ (2026-09-17) - [x] 서버 —
AptitudeBonus·Character.TryRaiseAptitude·User.RaiseAptitude·SaveCharacterAptitudeRepository· 기동 시CharacterTableValidator· 테스트 19건 (2026-09-17) - [x]
클라 — 포인트 찍기 화면— 2026-10-06 재정의로 없어졌다
2026-09-17 구현 — 서버
| 조각 | 위치 |
|---|---|
| 찍은 보너스 값 타입 · 찍기 결과 enum | Server/WSGameServer/User/Character/AptitudeBonus.cs |
| 실효 적성 = 기본 + 보너스 · 상한 · 남은 포인트 · 찍기 | Character.GetAptitude · GetAptitudeCap · RemainingPoints · TryRaiseAptitude |
| 레벨까지 번 포인트 누적 | CharacterLevelCatalog.PointsEarnedBy |
| 검증 → 저장 → 정산·속도 갱신 → 응답 | User.Character.cs RaiseAptitude |
| 확정값 5열 저장 · 로그인 조회 | Repository/CharacterAptitudeRepository.cs · LoginRepository |
| 기본 ≤ 상한 기동 검사 | Common/CharacterTableValidator.cs (GameServer.Run) |
| Unity 수신 이벤트 | ServerPacketHandler.AptitudeUpResponded |
완료 조건
레벨이 오르면 찍는 조작 없이 슬롯 속도가 실제로 달라지고, 그 값이 재접속 후에도 유지된다.
(서버 ✅ 2026-10-06 — 레벨은 DB에 남으므로 재접속하면 같은 가산이 다시 계산된다.)
(경험치·레벨 자체는 이미 재접속 후 유지된다 — LoginRepository가 level·exp를 읽는다.)
막고 있는 것 / 선행 일감
- 없음. 이슈 #35는 2026-10-06 동의로 풀렸다
관련 커밋
-
08d8781— 레벨 효과 = 작업속도 가산 · 적성 포인트 철거 (main 머지4be6fe6) -
이 커밋 — 클라 효율 줄에 레벨 가산 항 (
GameDataLoader.GetLevelSpeedAdd) -
b77bacb— level/exp 컬럼과Character객체 도입 (읽지는 않음) -
5b8939e— 경험치 곡선 데이터(ExpPerJudge·CharacterLevelTable) + 기획 문서
참고
Server/WSGameServer/User/Character/Character.cs—GainExpServer/WSGameServer/User/User.WorkStation.cs—SettleWorkStation·ResolveExpPerJudgeGameDesign/Excel/Character.xlsx—CharacterLevelTable·GameDesign/Excel/Industry.xlsx—ExpPerJudge