Add authentication server, dev CLI, Docker multi-service setup, and cross-platform improvements

This commit is contained in:
Ilya Groshev
2026-04-21 16:49:44 +03:00
parent 43d6527b42
commit a3fbb1aeba
121 changed files with 4523 additions and 2888 deletions
+10 -77
View File
@@ -8,15 +8,6 @@ import (
"lunar-tear/server/internal/utils"
)
type bigHuntBossQuestRow struct {
BigHuntBossQuestId int32 `json:"BigHuntBossQuestId"`
BigHuntBossId int32 `json:"BigHuntBossId"`
BigHuntQuestGroupId int32 `json:"BigHuntQuestGroupId"`
BigHuntBossQuestScoreCoefficientId int32 `json:"BigHuntBossQuestScoreCoefficientId"`
BigHuntScoreRewardGroupScheduleId int32 `json:"BigHuntScoreRewardGroupScheduleId"`
DailyChallengeCount int32 `json:"DailyChallengeCount"`
}
type BigHuntBossQuestRow struct {
BigHuntBossQuestId int32
BigHuntBossId int32
@@ -25,97 +16,39 @@ type BigHuntBossQuestRow struct {
DailyChallengeCount int32
}
type bigHuntQuestRow struct {
BigHuntQuestId int32 `json:"BigHuntQuestId"`
QuestId int32 `json:"QuestId"`
BigHuntQuestScoreCoefficientId int32 `json:"BigHuntQuestScoreCoefficientId"`
}
type BigHuntQuestRow struct {
BigHuntQuestId int32
QuestId int32
BigHuntQuestScoreCoefficientId int32
}
type bigHuntQuestScoreCoefficientRow struct {
BigHuntQuestScoreCoefficientId int32 `json:"BigHuntQuestScoreCoefficientId"`
ScoreDifficultBonusPermil int32 `json:"ScoreDifficultBonusPermil"`
}
type bigHuntBossRow struct {
BigHuntBossId int32 `json:"BigHuntBossId"`
BigHuntBossGradeGroupId int32 `json:"BigHuntBossGradeGroupId"`
AttributeType int32 `json:"AttributeType"`
}
type BigHuntBossRow struct {
BigHuntBossId int32
BigHuntBossGradeGroupId int32
AttributeType int32
}
type bigHuntBossGradeGroupRow struct {
BigHuntBossGradeGroupId int32 `json:"BigHuntBossGradeGroupId"`
NecessaryScore int64 `json:"NecessaryScore"`
AssetGradeIconId int32 `json:"AssetGradeIconId"`
}
type GradeThreshold struct {
NecessaryScore int64
AssetGradeIconId int32
}
type bigHuntScheduleRow struct {
BigHuntScheduleId int32 `json:"BigHuntScheduleId"`
ChallengeStartDatetime int64 `json:"ChallengeStartDatetime"`
ChallengeEndDatetime int64 `json:"ChallengeEndDatetime"`
}
type scoreRewardScheduleRow struct {
BigHuntScoreRewardGroupScheduleId int32 `json:"BigHuntScoreRewardGroupScheduleId"`
GroupIndex int32 `json:"GroupIndex"`
BigHuntScoreRewardGroupId int32 `json:"BigHuntScoreRewardGroupId"`
StartDatetime int64 `json:"StartDatetime"`
}
type ScoreRewardScheduleEntry struct {
BigHuntScoreRewardGroupId int32
StartDatetime int64
}
type scoreRewardGroupRow struct {
BigHuntScoreRewardGroupId int32 `json:"BigHuntScoreRewardGroupId"`
NecessaryScore int64 `json:"NecessaryScore"`
BigHuntRewardGroupId int32 `json:"BigHuntRewardGroupId"`
}
type ScoreRewardThreshold struct {
NecessaryScore int64
BigHuntRewardGroupId int32
}
type rewardGroupRow struct {
BigHuntRewardGroupId int32 `json:"BigHuntRewardGroupId"`
SortOrder int32 `json:"SortOrder"`
PossessionType int32 `json:"PossessionType"`
PossessionId int32 `json:"PossessionId"`
Count int32 `json:"Count"`
}
type RewardItem struct {
PossessionType int32
PossessionId int32
Count int32
}
type weeklyRewardScheduleRow struct {
BigHuntWeeklyAttributeScoreRewardGroupScheduleId int32 `json:"BigHuntWeeklyAttributeScoreRewardGroupScheduleId"`
AttributeType int32 `json:"AttributeType"`
GroupIndex int32 `json:"GroupIndex"`
BigHuntScoreRewardGroupId int32 `json:"BigHuntScoreRewardGroupId"`
StartDatetime int64 `json:"StartDatetime"`
}
type BigHuntWeeklyRewardKey struct {
ScheduleId int32
AttributeType int32
@@ -189,7 +122,7 @@ func (c *BigHuntCatalog) CollectNewRewards(scoreRewardGroupId int32, oldMax, new
}
func LoadBigHuntCatalog() *BigHuntCatalog {
bossQuestRows, err := utils.ReadJSON[bigHuntBossQuestRow]("EntityMBigHuntBossQuestTable.json")
bossQuestRows, err := utils.ReadTable[EntityMBigHuntBossQuest]("m_big_hunt_boss_quest")
if err != nil {
log.Fatalf("load big hunt boss quest table: %v", err)
}
@@ -204,7 +137,7 @@ func LoadBigHuntCatalog() *BigHuntCatalog {
}
}
questRows, err := utils.ReadJSON[bigHuntQuestRow]("EntityMBigHuntQuestTable.json")
questRows, err := utils.ReadTable[EntityMBigHuntQuest]("m_big_hunt_quest")
if err != nil {
log.Fatalf("load big hunt quest table: %v", err)
}
@@ -217,7 +150,7 @@ func LoadBigHuntCatalog() *BigHuntCatalog {
}
}
coeffRows, err := utils.ReadJSON[bigHuntQuestScoreCoefficientRow]("EntityMBigHuntQuestScoreCoefficientTable.json")
coeffRows, err := utils.ReadTable[EntityMBigHuntQuestScoreCoefficient]("m_big_hunt_quest_score_coefficient")
if err != nil {
log.Fatalf("load big hunt quest score coefficient table: %v", err)
}
@@ -226,7 +159,7 @@ func LoadBigHuntCatalog() *BigHuntCatalog {
scoreCoefficients[r.BigHuntQuestScoreCoefficientId] = r.ScoreDifficultBonusPermil
}
bossRows, err := utils.ReadJSON[bigHuntBossRow]("EntityMBigHuntBossTable.json")
bossRows, err := utils.ReadTable[EntityMBigHuntBoss]("m_big_hunt_boss")
if err != nil {
log.Fatalf("load big hunt boss table: %v", err)
}
@@ -239,7 +172,7 @@ func LoadBigHuntCatalog() *BigHuntCatalog {
}
}
gradeRows, err := utils.ReadJSON[bigHuntBossGradeGroupRow]("EntityMBigHuntBossGradeGroupTable.json")
gradeRows, err := utils.ReadTable[EntityMBigHuntBossGradeGroup]("m_big_hunt_boss_grade_group")
if err != nil {
log.Fatalf("load big hunt boss grade group table: %v", err)
}
@@ -256,7 +189,7 @@ func LoadBigHuntCatalog() *BigHuntCatalog {
})
}
scheduleRows, err := utils.ReadJSON[bigHuntScheduleRow]("EntityMBigHuntScheduleTable.json")
scheduleRows, err := utils.ReadTable[EntityMBigHuntSchedule]("m_big_hunt_schedule")
if err != nil {
log.Fatalf("load big hunt schedule table: %v", err)
}
@@ -274,7 +207,7 @@ func LoadBigHuntCatalog() *BigHuntCatalog {
}
}
rewardSchedRows, err := utils.ReadJSON[scoreRewardScheduleRow]("EntityMBigHuntScoreRewardGroupScheduleTable.json")
rewardSchedRows, err := utils.ReadTable[EntityMBigHuntScoreRewardGroupSchedule]("m_big_hunt_score_reward_group_schedule")
if err != nil {
log.Fatalf("load big hunt score reward group schedule table: %v", err)
}
@@ -294,7 +227,7 @@ func LoadBigHuntCatalog() *BigHuntCatalog {
})
}
rewardGroupRows, err := utils.ReadJSON[scoreRewardGroupRow]("EntityMBigHuntScoreRewardGroupTable.json")
rewardGroupRows, err := utils.ReadTable[EntityMBigHuntScoreRewardGroup]("m_big_hunt_score_reward_group")
if err != nil {
log.Fatalf("load big hunt score reward group table: %v", err)
}
@@ -314,7 +247,7 @@ func LoadBigHuntCatalog() *BigHuntCatalog {
})
}
rewardItemRows, err := utils.ReadJSON[rewardGroupRow]("EntityMBigHuntRewardGroupTable.json")
rewardItemRows, err := utils.ReadTable[EntityMBigHuntRewardGroup]("m_big_hunt_reward_group")
if err != nil {
log.Fatalf("load big hunt reward group table: %v", err)
}
@@ -327,7 +260,7 @@ func LoadBigHuntCatalog() *BigHuntCatalog {
})
}
weeklySchedRows, err := utils.ReadJSON[weeklyRewardScheduleRow]("EntityMBigHuntWeeklyAttributeScoreRewardGroupScheduleTable.json")
weeklySchedRows, err := utils.ReadTable[EntityMBigHuntWeeklyAttributeScoreRewardGroupSchedule]("m_big_hunt_weekly_attribute_score_reward_group_schedule")
if err != nil {
log.Fatalf("load big hunt weekly attribute score reward group schedule table: %v", err)
}
+2 -14
View File
@@ -5,18 +5,6 @@ import (
"lunar-tear/server/internal/utils"
)
type cageOrnament struct {
CageOrnamentId int32 `json:"CageOrnamentId"`
CageOrnamentRewardId int32 `json:"CageOrnamentRewardId"`
}
type cageOrnamentRewardRow struct {
CageOrnamentRewardId int32 `json:"CageOrnamentRewardId"`
PossessionType int32 `json:"PossessionType"`
PossessionId int32 `json:"PossessionId"`
Count int32 `json:"Count"`
}
type CageOrnamentReward struct {
PossessionType int32
PossessionId int32
@@ -38,11 +26,11 @@ func (c *CageOrnamentCatalog) LookupReward(cageOrnamentId int32) (CageOrnamentRe
}
func LoadCageOrnamentCatalog() *CageOrnamentCatalog {
ornaments, err := utils.ReadJSON[cageOrnament]("EntityMCageOrnamentTable.json")
ornaments, err := utils.ReadTable[EntityMCageOrnament]("m_cage_ornament")
if err != nil {
log.Fatalf("load cage ornament table: %v", err)
}
rewards, err := utils.ReadJSON[cageOrnamentRewardRow]("EntityMCageOrnamentRewardTable.json")
rewards, err := utils.ReadTable[EntityMCageOrnamentReward]("m_cage_ornament_reward")
if err != nil {
log.Fatalf("load cage ornament reward table: %v", err)
}
@@ -6,24 +6,6 @@ import (
"lunar-tear/server/internal/utils"
)
type CharacterRebirthRow struct {
CharacterId int32 `json:"CharacterId"`
CharacterRebirthStepGroupId int32 `json:"CharacterRebirthStepGroupId"`
}
type CharacterRebirthStepRow struct {
CharacterRebirthStepGroupId int32 `json:"CharacterRebirthStepGroupId"`
BeforeRebirthCount int32 `json:"BeforeRebirthCount"`
CostumeLevelLimitUp int32 `json:"CostumeLevelLimitUp"`
CharacterRebirthMaterialGroupId int32 `json:"CharacterRebirthMaterialGroupId"`
}
type CharacterRebirthMaterialRow struct {
CharacterRebirthMaterialGroupId int32 `json:"CharacterRebirthMaterialGroupId"`
MaterialId int32 `json:"MaterialId"`
Count int32 `json:"Count"`
}
type StepKey struct {
GroupId int32
BeforeRebirthCount int32
@@ -31,22 +13,22 @@ type StepKey struct {
type CharacterRebirthCatalog struct {
StepGroupByCharacterId map[int32]int32
StepByGroupAndCount map[StepKey]CharacterRebirthStepRow
MaterialsByGroupId map[int32][]CharacterRebirthMaterialRow
StepByGroupAndCount map[StepKey]EntityMCharacterRebirthStepGroup
MaterialsByGroupId map[int32][]EntityMCharacterRebirthMaterialGroup
}
func LoadCharacterRebirthCatalog() (*CharacterRebirthCatalog, error) {
rebirthRows, err := utils.ReadJSON[CharacterRebirthRow]("EntityMCharacterRebirthTable.json")
rebirthRows, err := utils.ReadTable[EntityMCharacterRebirth]("m_character_rebirth")
if err != nil {
return nil, fmt.Errorf("load character rebirth table: %w", err)
}
stepRows, err := utils.ReadJSON[CharacterRebirthStepRow]("EntityMCharacterRebirthStepGroupTable.json")
stepRows, err := utils.ReadTable[EntityMCharacterRebirthStepGroup]("m_character_rebirth_step_group")
if err != nil {
return nil, fmt.Errorf("load character rebirth step group table: %w", err)
}
materialRows, err := utils.ReadJSON[CharacterRebirthMaterialRow]("EntityMCharacterRebirthMaterialGroupTable.json")
materialRows, err := utils.ReadTable[EntityMCharacterRebirthMaterialGroup]("m_character_rebirth_material_group")
if err != nil {
return nil, fmt.Errorf("load character rebirth material group table: %w", err)
}
@@ -56,12 +38,12 @@ func LoadCharacterRebirthCatalog() (*CharacterRebirthCatalog, error) {
stepGroupByCharacterId[r.CharacterId] = r.CharacterRebirthStepGroupId
}
stepByGroupAndCount := make(map[StepKey]CharacterRebirthStepRow, len(stepRows))
stepByGroupAndCount := make(map[StepKey]EntityMCharacterRebirthStepGroup, len(stepRows))
for _, s := range stepRows {
stepByGroupAndCount[StepKey{GroupId: s.CharacterRebirthStepGroupId, BeforeRebirthCount: s.BeforeRebirthCount}] = s
}
materialsByGroupId := make(map[int32][]CharacterRebirthMaterialRow)
materialsByGroupId := make(map[int32][]EntityMCharacterRebirthMaterialGroup)
for _, m := range materialRows {
materialsByGroupId[m.CharacterRebirthMaterialGroupId] = append(materialsByGroupId[m.CharacterRebirthMaterialGroupId], m)
}
+24 -84
View File
@@ -7,66 +7,6 @@ import (
"lunar-tear/server/internal/utils"
)
type CharacterBoardPanelRow struct {
CharacterBoardPanelId int32 `json:"CharacterBoardPanelId"`
CharacterBoardId int32 `json:"CharacterBoardId"`
CharacterBoardPanelUnlockConditionGroupId int32 `json:"CharacterBoardPanelUnlockConditionGroupId"`
CharacterBoardPanelReleasePossessionGroupId int32 `json:"CharacterBoardPanelReleasePossessionGroupId"`
CharacterBoardPanelReleaseRewardGroupId int32 `json:"CharacterBoardPanelReleaseRewardGroupId"`
CharacterBoardPanelReleaseEffectGroupId int32 `json:"CharacterBoardPanelReleaseEffectGroupId"`
SortOrder int32 `json:"SortOrder"`
ParentCharacterBoardPanelId int32 `json:"ParentCharacterBoardPanelId"`
PlaceIndex int32 `json:"PlaceIndex"`
}
type CharacterBoardReleasePossessionRow struct {
CharacterBoardPanelReleasePossessionGroupId int32 `json:"CharacterBoardPanelReleasePossessionGroupId"`
PossessionType int32 `json:"PossessionType"`
PossessionId int32 `json:"PossessionId"`
Count int32 `json:"Count"`
SortOrder int32 `json:"SortOrder"`
}
type CharacterBoardReleaseEffectRow struct {
CharacterBoardPanelReleaseEffectGroupId int32 `json:"CharacterBoardPanelReleaseEffectGroupId"`
SortOrder int32 `json:"SortOrder"`
CharacterBoardEffectType int32 `json:"CharacterBoardEffectType"`
CharacterBoardEffectId int32 `json:"CharacterBoardEffectId"`
EffectValue int32 `json:"EffectValue"`
}
type CharacterBoardRow struct {
CharacterBoardId int32 `json:"CharacterBoardId"`
CharacterBoardGroupId int32 `json:"CharacterBoardGroupId"`
CharacterBoardUnlockConditionGroupId int32 `json:"CharacterBoardUnlockConditionGroupId"`
ReleaseRank int32 `json:"ReleaseRank"`
}
type CharacterBoardStatusUpRow struct {
CharacterBoardStatusUpId int32 `json:"CharacterBoardStatusUpId"`
CharacterBoardStatusUpType int32 `json:"CharacterBoardStatusUpType"`
CharacterBoardEffectTargetGroupId int32 `json:"CharacterBoardEffectTargetGroupId"`
}
type CharacterBoardAbilityRow struct {
CharacterBoardAbilityId int32 `json:"CharacterBoardAbilityId"`
CharacterBoardEffectTargetGroupId int32 `json:"CharacterBoardEffectTargetGroupId"`
AbilityId int32 `json:"AbilityId"`
}
type CharacterBoardAbilityMaxLevelRow struct {
CharacterId int32 `json:"CharacterId"`
AbilityId int32 `json:"AbilityId"`
MaxLevel int32 `json:"MaxLevel"`
}
type CharacterBoardEffectTargetRow struct {
CharacterBoardEffectTargetGroupId int32 `json:"CharacterBoardEffectTargetGroupId"`
GroupIndex int32 `json:"GroupIndex"`
CharacterBoardEffectTargetType int32 `json:"CharacterBoardEffectTargetType"`
TargetValue int32 `json:"TargetValue"`
}
type CharacterBoardAssignmentRow struct {
CharacterId int32 `json:"CharacterId"`
CharacterBoardCategoryId int32 `json:"CharacterBoardCategoryId"`
@@ -83,68 +23,68 @@ type CharacterBoardGroupRow struct {
}
type CharacterBoardCatalog struct {
PanelById map[int32]CharacterBoardPanelRow
PanelsByBoardId map[int32][]CharacterBoardPanelRow
ReleaseCostsByGroupId map[int32][]CharacterBoardReleasePossessionRow
ReleaseEffectsByGroupId map[int32][]CharacterBoardReleaseEffectRow
StatusUpById map[int32]CharacterBoardStatusUpRow
AbilityById map[int32]CharacterBoardAbilityRow
PanelById map[int32]EntityMCharacterBoardPanel
PanelsByBoardId map[int32][]EntityMCharacterBoardPanel
ReleaseCostsByGroupId map[int32][]EntityMCharacterBoardPanelReleasePossessionGroup
ReleaseEffectsByGroupId map[int32][]EntityMCharacterBoardPanelReleaseEffectGroup
StatusUpById map[int32]EntityMCharacterBoardStatusUp
AbilityById map[int32]EntityMCharacterBoardAbility
AbilityMaxLevel map[store.CharacterBoardAbilityKey]int32
EffectTargetsByGroupId map[int32][]CharacterBoardEffectTargetRow
BoardById map[int32]CharacterBoardRow
EffectTargetsByGroupId map[int32][]EntityMCharacterBoardEffectTargetGroup
BoardById map[int32]EntityMCharacterBoard
}
func LoadCharacterBoardCatalog() (*CharacterBoardCatalog, error) {
panels, err := utils.ReadJSON[CharacterBoardPanelRow]("EntityMCharacterBoardPanelTable.json")
panels, err := utils.ReadTable[EntityMCharacterBoardPanel]("m_character_board_panel")
if err != nil {
return nil, fmt.Errorf("load character board panel table: %w", err)
}
costs, err := utils.ReadJSON[CharacterBoardReleasePossessionRow]("EntityMCharacterBoardPanelReleasePossessionGroupTable.json")
costs, err := utils.ReadTable[EntityMCharacterBoardPanelReleasePossessionGroup]("m_character_board_panel_release_possession_group")
if err != nil {
return nil, fmt.Errorf("load character board release possession table: %w", err)
}
effects, err := utils.ReadJSON[CharacterBoardReleaseEffectRow]("EntityMCharacterBoardPanelReleaseEffectGroupTable.json")
effects, err := utils.ReadTable[EntityMCharacterBoardPanelReleaseEffectGroup]("m_character_board_panel_release_effect_group")
if err != nil {
return nil, fmt.Errorf("load character board release effect table: %w", err)
}
boards, err := utils.ReadJSON[CharacterBoardRow]("EntityMCharacterBoardTable.json")
boards, err := utils.ReadTable[EntityMCharacterBoard]("m_character_board")
if err != nil {
return nil, fmt.Errorf("load character board table: %w", err)
}
statusUps, err := utils.ReadJSON[CharacterBoardStatusUpRow]("EntityMCharacterBoardStatusUpTable.json")
statusUps, err := utils.ReadTable[EntityMCharacterBoardStatusUp]("m_character_board_status_up")
if err != nil {
return nil, fmt.Errorf("load character board status up table: %w", err)
}
abilities, err := utils.ReadJSON[CharacterBoardAbilityRow]("EntityMCharacterBoardAbilityTable.json")
abilities, err := utils.ReadTable[EntityMCharacterBoardAbility]("m_character_board_ability")
if err != nil {
return nil, fmt.Errorf("load character board ability table: %w", err)
}
abilityMaxLevels, err := utils.ReadJSON[CharacterBoardAbilityMaxLevelRow]("EntityMCharacterBoardAbilityMaxLevelTable.json")
abilityMaxLevels, err := utils.ReadTable[EntityMCharacterBoardAbilityMaxLevel]("m_character_board_ability_max_level")
if err != nil {
return nil, fmt.Errorf("load character board ability max level table: %w", err)
}
targets, err := utils.ReadJSON[CharacterBoardEffectTargetRow]("EntityMCharacterBoardEffectTargetGroupTable.json")
targets, err := utils.ReadTable[EntityMCharacterBoardEffectTargetGroup]("m_character_board_effect_target_group")
if err != nil {
return nil, fmt.Errorf("load character board effect target table: %w", err)
}
catalog := &CharacterBoardCatalog{
PanelById: make(map[int32]CharacterBoardPanelRow, len(panels)),
PanelsByBoardId: make(map[int32][]CharacterBoardPanelRow),
ReleaseCostsByGroupId: make(map[int32][]CharacterBoardReleasePossessionRow),
ReleaseEffectsByGroupId: make(map[int32][]CharacterBoardReleaseEffectRow),
StatusUpById: make(map[int32]CharacterBoardStatusUpRow, len(statusUps)),
AbilityById: make(map[int32]CharacterBoardAbilityRow, len(abilities)),
PanelById: make(map[int32]EntityMCharacterBoardPanel, len(panels)),
PanelsByBoardId: make(map[int32][]EntityMCharacterBoardPanel),
ReleaseCostsByGroupId: make(map[int32][]EntityMCharacterBoardPanelReleasePossessionGroup),
ReleaseEffectsByGroupId: make(map[int32][]EntityMCharacterBoardPanelReleaseEffectGroup),
StatusUpById: make(map[int32]EntityMCharacterBoardStatusUp, len(statusUps)),
AbilityById: make(map[int32]EntityMCharacterBoardAbility, len(abilities)),
AbilityMaxLevel: make(map[store.CharacterBoardAbilityKey]int32, len(abilityMaxLevels)),
EffectTargetsByGroupId: make(map[int32][]CharacterBoardEffectTargetRow),
BoardById: make(map[int32]CharacterBoardRow, len(boards)),
EffectTargetsByGroupId: make(map[int32][]EntityMCharacterBoardEffectTargetGroup),
BoardById: make(map[int32]EntityMCharacterBoard, len(boards)),
}
for _, p := range panels {
@@ -9,11 +9,6 @@ import (
"lunar-tear/server/internal/utils"
)
type characterViewerField struct {
CharacterViewerFieldId int32 `json:"CharacterViewerFieldId"`
ReleaseEvaluateConditionId int32 `json:"ReleaseEvaluateConditionId"`
}
type characterViewerFieldEntry struct {
FieldId int32
RequiredQuestId int32
@@ -39,7 +34,7 @@ func (c *CharacterViewerCatalog) ReleasedFieldIds(user store.UserState) []int32
}
func LoadCharacterViewerCatalog(resolver *ConditionResolver) *CharacterViewerCatalog {
fields, err := utils.ReadJSON[characterViewerField]("EntityMCharacterViewerFieldTable.json")
fields, err := utils.ReadTable[EntityMCharacterViewerField]("m_character_viewer_field")
if err != nil {
log.Fatalf("load character viewer field table: %v", err)
}
+5 -22
View File
@@ -6,23 +6,6 @@ import (
"lunar-tear/server/internal/utils"
)
type companionRow struct {
CompanionId int32 `json:"CompanionId"`
CompanionCategoryType int32 `json:"CompanionCategoryType"`
}
type companionCategoryRow struct {
CompanionCategoryType int32 `json:"CompanionCategoryType"`
EnhancementCostNumericalFunctionId int32 `json:"EnhancementCostNumericalFunctionId"`
}
type companionEnhancementMaterialRow struct {
CompanionCategoryType int32 `json:"CompanionCategoryType"`
Level int32 `json:"Level"`
MaterialId int32 `json:"MaterialId"`
Count int32 `json:"Count"`
}
type CompanionLevelKey struct {
CategoryType int32
Level int32
@@ -34,23 +17,23 @@ type CompanionMaterialCost struct {
}
type CompanionCatalog struct {
CompanionById map[int32]companionRow
CompanionById map[int32]EntityMCompanion
GoldCostByCategory map[int32]NumericalFunc
MaterialsByKey map[CompanionLevelKey]CompanionMaterialCost
}
func LoadCompanionCatalog() (*CompanionCatalog, error) {
companions, err := utils.ReadJSON[companionRow]("EntityMCompanionTable.json")
companions, err := utils.ReadTable[EntityMCompanion]("m_companion")
if err != nil {
return nil, fmt.Errorf("load companion table: %w", err)
}
categories, err := utils.ReadJSON[companionCategoryRow]("EntityMCompanionCategoryTable.json")
categories, err := utils.ReadTable[EntityMCompanionCategory]("m_companion_category")
if err != nil {
return nil, fmt.Errorf("load companion category table: %w", err)
}
materials, err := utils.ReadJSON[companionEnhancementMaterialRow]("EntityMCompanionEnhancementMaterialTable.json")
materials, err := utils.ReadTable[EntityMCompanionEnhancementMaterial]("m_companion_enhancement_material")
if err != nil {
return nil, fmt.Errorf("load companion enhancement material table: %w", err)
}
@@ -60,7 +43,7 @@ func LoadCompanionCatalog() (*CompanionCatalog, error) {
return nil, fmt.Errorf("load function resolver: %w", err)
}
companionById := make(map[int32]companionRow, len(companions))
companionById := make(map[int32]EntityMCompanion, len(companions))
for _, c := range companions {
companionById[c.CompanionId] = c
}
+5 -18
View File
@@ -7,19 +7,6 @@ import (
"lunar-tear/server/internal/utils"
)
type evaluateCondition struct {
EvaluateConditionId int32 `json:"EvaluateConditionId"`
EvaluateConditionFunctionType model.EvaluateConditionFunctionType `json:"EvaluateConditionFunctionType"`
EvaluateConditionEvaluateType model.EvaluateConditionEvaluateType `json:"EvaluateConditionEvaluateType"`
EvaluateConditionValueGroupId int32 `json:"EvaluateConditionValueGroupId"`
}
type evaluateConditionValueGroup struct {
EvaluateConditionValueGroupId int32 `json:"EvaluateConditionValueGroupId"`
GroupIndex int32 `json:"GroupIndex"`
Value int64 `json:"Value"`
}
const defaultGroupIndex = 1
type ConditionResolver struct {
@@ -27,16 +14,16 @@ type ConditionResolver struct {
}
func LoadConditionResolver() (*ConditionResolver, error) {
conditions, err := utils.ReadJSON[evaluateCondition]("EntityMEvaluateConditionTable.json")
conditions, err := utils.ReadTable[EntityMEvaluateCondition]("m_evaluate_condition")
if err != nil {
return nil, fmt.Errorf("load evaluate condition table: %w", err)
}
valueGroups, err := utils.ReadJSON[evaluateConditionValueGroup]("EntityMEvaluateConditionValueGroupTable.json")
valueGroups, err := utils.ReadTable[EntityMEvaluateConditionValueGroup]("m_evaluate_condition_value_group")
if err != nil {
return nil, fmt.Errorf("load evaluate condition value group table: %w", err)
}
condById := make(map[int32]evaluateCondition, len(conditions))
condById := make(map[int32]EntityMEvaluateCondition, len(conditions))
for _, c := range conditions {
condById[c.EvaluateConditionId] = c
}
@@ -52,8 +39,8 @@ func LoadConditionResolver() (*ConditionResolver, error) {
resolved := make(map[int32]int32)
for _, c := range conditions {
if c.EvaluateConditionFunctionType == model.EvaluateConditionFunctionTypeQuestClear &&
c.EvaluateConditionEvaluateType == model.EvaluateConditionEvaluateTypeIdContain {
if model.EvaluateConditionFunctionType(c.EvaluateConditionFunctionType) == model.EvaluateConditionFunctionTypeQuestClear &&
model.EvaluateConditionEvaluateType(c.EvaluateConditionEvaluateType) == model.EvaluateConditionEvaluateTypeIdContain {
if questId, ok := vgByKey[vgKey{c.EvaluateConditionValueGroupId, defaultGroupIndex}]; ok {
resolved[c.EvaluateConditionId] = int32(questId)
}
+1 -6
View File
@@ -7,11 +7,6 @@ import (
"lunar-tear/server/internal/utils"
)
type configRow struct {
ConfigKey string `json:"ConfigKey"`
Value string `json:"Value"`
}
type GameConfig struct {
ConsumableItemIdForGold int32
ConsumableItemIdForMedal int32
@@ -41,7 +36,7 @@ type GameConfig struct {
}
func LoadGameConfig() (*GameConfig, error) {
rows, err := utils.ReadJSON[configRow]("EntityMConfigTable.json")
rows, err := utils.ReadTable[EntityMConfig]("m_config")
if err != nil {
return nil, fmt.Errorf("load config table: %w", err)
}
+3 -8
View File
@@ -6,23 +6,18 @@ import (
"lunar-tear/server/internal/utils"
)
type ConsumableItemRow struct {
ConsumableItemId int32 `json:"ConsumableItemId"`
SellPrice int32 `json:"SellPrice"`
}
type ConsumableItemCatalog struct {
All map[int32]ConsumableItemRow
All map[int32]EntityMConsumableItem
}
func LoadConsumableItemCatalog() (*ConsumableItemCatalog, error) {
rows, err := utils.ReadJSON[ConsumableItemRow]("EntityMConsumableItemTable.json")
rows, err := utils.ReadTable[EntityMConsumableItem]("m_consumable_item")
if err != nil {
return nil, fmt.Errorf("load consumable item table: %w", err)
}
catalog := &ConsumableItemCatalog{
All: make(map[int32]ConsumableItemRow, len(rows)),
All: make(map[int32]EntityMConsumableItem, len(rows)),
}
for _, row := range rows {
catalog.All[row.ConsumableItemId] = row
+34 -129
View File
@@ -8,132 +8,37 @@ import (
"lunar-tear/server/internal/utils"
)
type CostumeMasterRow struct {
CostumeId int32 `json:"CostumeId"`
CharacterId int32 `json:"CharacterId"`
SkillfulWeaponType int32 `json:"SkillfulWeaponType"`
RarityType int32 `json:"RarityType"`
CostumeLimitBreakMaterialGroupId int32 `json:"CostumeLimitBreakMaterialGroupId"`
CostumeActiveSkillGroupId int32 `json:"CostumeActiveSkillGroupId"`
}
type costumeRarityRow struct {
RarityType int32 `json:"RarityType"`
CostumeLimitBreakMaterialRarityGroupId int32 `json:"CostumeLimitBreakMaterialRarityGroupId"`
RequiredExpForLevelUpNumericalParameterMapId int32 `json:"RequiredExpForLevelUpNumericalParameterMapId"`
EnhancementCostByMaterialNumericalFunctionId int32 `json:"EnhancementCostByMaterialNumericalFunctionId"`
LimitBreakCostNumericalFunctionId int32 `json:"LimitBreakCostNumericalFunctionId"`
MaxLevelNumericalFunctionId int32 `json:"MaxLevelNumericalFunctionId"`
ActiveSkillMaxLevelNumericalFunctionId int32 `json:"ActiveSkillMaxLevelNumericalFunctionId"`
ActiveSkillEnhancementCostNumericalFunctionId int32 `json:"ActiveSkillEnhancementCostNumericalFunctionId"`
}
type CostumeAwakenRow struct {
CostumeId int32 `json:"CostumeId"`
CostumeAwakenEffectGroupId int32 `json:"CostumeAwakenEffectGroupId"`
CostumeAwakenStepMaterialGroupId int32 `json:"CostumeAwakenStepMaterialGroupId"`
CostumeAwakenPriceGroupId int32 `json:"CostumeAwakenPriceGroupId"`
}
type costumeAwakenPriceRow struct {
CostumeAwakenPriceGroupId int32 `json:"CostumeAwakenPriceGroupId"`
AwakenStepLowerLimit int32 `json:"AwakenStepLowerLimit"`
Gold int32 `json:"Gold"`
}
type CostumeAwakenEffectRow struct {
CostumeAwakenEffectGroupId int32 `json:"CostumeAwakenEffectGroupId"`
AwakenStep int32 `json:"AwakenStep"`
CostumeAwakenEffectType int32 `json:"CostumeAwakenEffectType"`
CostumeAwakenEffectId int32 `json:"CostumeAwakenEffectId"`
}
type CostumeAwakenStatusUpRow struct {
CostumeAwakenStatusUpGroupId int32 `json:"CostumeAwakenStatusUpGroupId"`
SortOrder int32 `json:"SortOrder"`
StatusKindType int32 `json:"StatusKindType"`
StatusCalculationType int32 `json:"StatusCalculationType"`
EffectValue int32 `json:"EffectValue"`
}
type CostumeAwakenItemAcquireRow struct {
CostumeAwakenItemAcquireId int32 `json:"CostumeAwakenItemAcquireId"`
PossessionType int32 `json:"PossessionType"`
PossessionId int32 `json:"PossessionId"`
Count int32 `json:"Count"`
}
type CostumeActiveSkillGroupRow struct {
CostumeActiveSkillGroupId int32 `json:"CostumeActiveSkillGroupId"`
CostumeLimitBreakCountLowerLimit int32 `json:"CostumeLimitBreakCountLowerLimit"`
CostumeActiveSkillId int32 `json:"CostumeActiveSkillId"`
CostumeActiveSkillEnhancementMaterialId int32 `json:"CostumeActiveSkillEnhancementMaterialId"`
}
type CostumeActiveSkillEnhanceMaterialRow struct {
CostumeActiveSkillEnhancementMaterialId int32 `json:"CostumeActiveSkillEnhancementMaterialId"`
SkillLevel int32 `json:"SkillLevel"`
MaterialId int32 `json:"MaterialId"`
Count int32 `json:"Count"`
SortOrder int32 `json:"SortOrder"`
}
type CostumeLotteryEffectRow struct {
CostumeId int32 `json:"CostumeId"`
SlotNumber int32 `json:"SlotNumber"`
CostumeLotteryEffectOddsGroupId int32 `json:"CostumeLotteryEffectOddsGroupId"`
CostumeLotteryEffectUnlockMaterialGroupId int32 `json:"CostumeLotteryEffectUnlockMaterialGroupId"`
CostumeLotteryEffectDrawMaterialGroupId int32 `json:"CostumeLotteryEffectDrawMaterialGroupId"`
CostumeLotteryEffectReleaseScheduleId int32 `json:"CostumeLotteryEffectReleaseScheduleId"`
}
type CostumeLotteryEffectMaterialGroupRow struct {
CostumeLotteryEffectMaterialGroupId int32 `json:"CostumeLotteryEffectMaterialGroupId"`
MaterialId int32 `json:"MaterialId"`
Count int32 `json:"Count"`
SortOrder int32 `json:"SortOrder"`
}
type CostumeLotteryEffectOddsRow struct {
CostumeLotteryEffectOddsGroupId int32 `json:"CostumeLotteryEffectOddsGroupId"`
OddsNumber int32 `json:"OddsNumber"`
Weight int32 `json:"Weight"`
CostumeLotteryEffectType int32 `json:"CostumeLotteryEffectType"`
CostumeLotteryEffectTargetId int32 `json:"CostumeLotteryEffectTargetId"`
RarityType int32 `json:"RarityType"`
}
type CostumeCatalog struct {
Costumes map[int32]CostumeMasterRow
Materials map[int32]MaterialRow
Costumes map[int32]EntityMCostume
Materials map[int32]EntityMMaterial
ExpByRarity map[int32][]int32
EnhanceCostByRarity map[int32]NumericalFunc
MaxLevelByRarity map[int32]NumericalFunc
LimitBreakCostByRarity map[int32]NumericalFunc
AwakenByCostumeId map[int32]CostumeAwakenRow
AwakenByCostumeId map[int32]EntityMCostumeAwaken
AwakenPriceByGroup map[int32]int32
AwakenEffectsByGroupAndStep map[int32]map[int32]CostumeAwakenEffectRow
AwakenStatusUpByGroup map[int32][]CostumeAwakenStatusUpRow
AwakenItemAcquireById map[int32]CostumeAwakenItemAcquireRow
AwakenEffectsByGroupAndStep map[int32]map[int32]EntityMCostumeAwakenEffectGroup
AwakenStatusUpByGroup map[int32][]EntityMCostumeAwakenStatusUpGroup
AwakenItemAcquireById map[int32]EntityMCostumeAwakenItemAcquire
ActiveSkillGroupsByGroupId map[int32][]CostumeActiveSkillGroupRow // sorted by CostumeLimitBreakCountLowerLimit desc
ActiveSkillEnhanceMats map[[2]int32][]CostumeActiveSkillEnhanceMaterialRow // key: [enhancementMaterialId, skillLevel]
ActiveSkillGroupsByGroupId map[int32][]EntityMCostumeActiveSkillGroup // sorted by CostumeLimitBreakCountLowerLimit desc
ActiveSkillEnhanceMats map[[2]int32][]EntityMCostumeActiveSkillEnhancementMaterial // key: [enhancementMaterialId, skillLevel]
ActiveSkillMaxLevelByRarity map[int32]NumericalFunc
ActiveSkillCostByRarity map[int32]NumericalFunc
LotteryEffects map[[2]int32]CostumeLotteryEffectRow // key: [costumeId, slotNumber]
LotteryEffectMats map[int32][]CostumeLotteryEffectMaterialGroupRow // key: materialGroupId (both unlock and draw)
LotteryEffectOdds map[int32][]CostumeLotteryEffectOddsRow // key: oddsGroupId
LotteryEffects map[[2]int32]EntityMCostumeLotteryEffect // key: [costumeId, slotNumber]
LotteryEffectMats map[int32][]EntityMCostumeLotteryEffectMaterialGroup // key: materialGroupId (both unlock and draw)
LotteryEffectOdds map[int32][]EntityMCostumeLotteryEffectOddsGroup // key: oddsGroupId
}
func LoadCostumeCatalog(matCatalog *MaterialCatalog) (*CostumeCatalog, error) {
costumes, err := utils.ReadJSON[CostumeMasterRow]("EntityMCostumeTable.json")
costumes, err := utils.ReadTable[EntityMCostume]("m_costume")
if err != nil {
return nil, fmt.Errorf("load costume table: %w", err)
}
rarities, err := utils.ReadJSON[costumeRarityRow]("EntityMCostumeRarityTable.json")
rarities, err := utils.ReadTable[EntityMCostumeRarity]("m_costume_rarity")
if err != nil {
return nil, fmt.Errorf("load costume rarity table: %w", err)
}
@@ -148,71 +53,71 @@ func LoadCostumeCatalog(matCatalog *MaterialCatalog) (*CostumeCatalog, error) {
return nil, fmt.Errorf("load function resolver: %w", err)
}
awakenRows, err := utils.ReadJSON[CostumeAwakenRow]("EntityMCostumeAwakenTable.json")
awakenRows, err := utils.ReadTable[EntityMCostumeAwaken]("m_costume_awaken")
if err != nil {
return nil, fmt.Errorf("load costume awaken table: %w", err)
}
awakenPriceRows, err := utils.ReadJSON[costumeAwakenPriceRow]("EntityMCostumeAwakenPriceGroupTable.json")
awakenPriceRows, err := utils.ReadTable[EntityMCostumeAwakenPriceGroup]("m_costume_awaken_price_group")
if err != nil {
return nil, fmt.Errorf("load costume awaken price table: %w", err)
}
awakenEffectRows, err := utils.ReadJSON[CostumeAwakenEffectRow]("EntityMCostumeAwakenEffectGroupTable.json")
awakenEffectRows, err := utils.ReadTable[EntityMCostumeAwakenEffectGroup]("m_costume_awaken_effect_group")
if err != nil {
return nil, fmt.Errorf("load costume awaken effect table: %w", err)
}
awakenStatusUpRows, err := utils.ReadJSON[CostumeAwakenStatusUpRow]("EntityMCostumeAwakenStatusUpGroupTable.json")
awakenStatusUpRows, err := utils.ReadTable[EntityMCostumeAwakenStatusUpGroup]("m_costume_awaken_status_up_group")
if err != nil {
return nil, fmt.Errorf("load costume awaken status up table: %w", err)
}
awakenItemAcquireRows, err := utils.ReadJSON[CostumeAwakenItemAcquireRow]("EntityMCostumeAwakenItemAcquireTable.json")
awakenItemAcquireRows, err := utils.ReadTable[EntityMCostumeAwakenItemAcquire]("m_costume_awaken_item_acquire")
if err != nil {
return nil, fmt.Errorf("load costume awaken item acquire table: %w", err)
}
activeSkillGroupRows, err := utils.ReadJSON[CostumeActiveSkillGroupRow]("EntityMCostumeActiveSkillGroupTable.json")
activeSkillGroupRows, err := utils.ReadTable[EntityMCostumeActiveSkillGroup]("m_costume_active_skill_group")
if err != nil {
return nil, fmt.Errorf("load costume active skill group table: %w", err)
}
activeSkillMatRows, err := utils.ReadJSON[CostumeActiveSkillEnhanceMaterialRow]("EntityMCostumeActiveSkillEnhancementMaterialTable.json")
activeSkillMatRows, err := utils.ReadTable[EntityMCostumeActiveSkillEnhancementMaterial]("m_costume_active_skill_enhancement_material")
if err != nil {
return nil, fmt.Errorf("load costume active skill enhancement material table: %w", err)
}
lotteryEffectRows, err := utils.ReadJSON[CostumeLotteryEffectRow]("EntityMCostumeLotteryEffectTable.json")
lotteryEffectRows, err := utils.ReadTable[EntityMCostumeLotteryEffect]("m_costume_lottery_effect")
if err != nil {
return nil, fmt.Errorf("load costume lottery effect table: %w", err)
}
lotteryEffectMatRows, err := utils.ReadJSON[CostumeLotteryEffectMaterialGroupRow]("EntityMCostumeLotteryEffectMaterialGroupTable.json")
lotteryEffectMatRows, err := utils.ReadTable[EntityMCostumeLotteryEffectMaterialGroup]("m_costume_lottery_effect_material_group")
if err != nil {
return nil, fmt.Errorf("load costume lottery effect material group table: %w", err)
}
lotteryEffectOddsRows, err := utils.ReadJSON[CostumeLotteryEffectOddsRow]("EntityMCostumeLotteryEffectOddsGroupTable.json")
lotteryEffectOddsRows, err := utils.ReadTable[EntityMCostumeLotteryEffectOddsGroup]("m_costume_lottery_effect_odds_group")
if err != nil {
return nil, fmt.Errorf("load costume lottery effect odds group table: %w", err)
}
catalog := &CostumeCatalog{
Costumes: make(map[int32]CostumeMasterRow, len(costumes)),
Costumes: make(map[int32]EntityMCostume, len(costumes)),
Materials: matCatalog.ByType[model.MaterialTypeCostumeEnhancement],
ExpByRarity: make(map[int32][]int32, len(rarities)),
EnhanceCostByRarity: make(map[int32]NumericalFunc, len(rarities)),
MaxLevelByRarity: make(map[int32]NumericalFunc, len(rarities)),
LimitBreakCostByRarity: make(map[int32]NumericalFunc, len(rarities)),
AwakenByCostumeId: make(map[int32]CostumeAwakenRow, len(awakenRows)),
AwakenByCostumeId: make(map[int32]EntityMCostumeAwaken, len(awakenRows)),
AwakenPriceByGroup: make(map[int32]int32, len(awakenPriceRows)),
AwakenEffectsByGroupAndStep: make(map[int32]map[int32]CostumeAwakenEffectRow),
AwakenStatusUpByGroup: make(map[int32][]CostumeAwakenStatusUpRow),
AwakenItemAcquireById: make(map[int32]CostumeAwakenItemAcquireRow, len(awakenItemAcquireRows)),
AwakenEffectsByGroupAndStep: make(map[int32]map[int32]EntityMCostumeAwakenEffectGroup),
AwakenStatusUpByGroup: make(map[int32][]EntityMCostumeAwakenStatusUpGroup),
AwakenItemAcquireById: make(map[int32]EntityMCostumeAwakenItemAcquire, len(awakenItemAcquireRows)),
ActiveSkillGroupsByGroupId: make(map[int32][]CostumeActiveSkillGroupRow),
ActiveSkillEnhanceMats: make(map[[2]int32][]CostumeActiveSkillEnhanceMaterialRow),
ActiveSkillGroupsByGroupId: make(map[int32][]EntityMCostumeActiveSkillGroup),
ActiveSkillEnhanceMats: make(map[[2]int32][]EntityMCostumeActiveSkillEnhancementMaterial),
ActiveSkillMaxLevelByRarity: make(map[int32]NumericalFunc, len(rarities)),
ActiveSkillCostByRarity: make(map[int32]NumericalFunc, len(rarities)),
LotteryEffects: make(map[[2]int32]CostumeLotteryEffectRow, len(lotteryEffectRows)),
LotteryEffectMats: make(map[int32][]CostumeLotteryEffectMaterialGroupRow),
LotteryEffectOdds: make(map[int32][]CostumeLotteryEffectOddsRow),
LotteryEffects: make(map[[2]int32]EntityMCostumeLotteryEffect, len(lotteryEffectRows)),
LotteryEffectMats: make(map[int32][]EntityMCostumeLotteryEffectMaterialGroup),
LotteryEffectOdds: make(map[int32][]EntityMCostumeLotteryEffectOddsGroup),
}
for _, row := range costumes {
@@ -259,7 +164,7 @@ func LoadCostumeCatalog(matCatalog *MaterialCatalog) (*CostumeCatalog, error) {
for _, row := range awakenEffectRows {
m, ok := catalog.AwakenEffectsByGroupAndStep[row.CostumeAwakenEffectGroupId]
if !ok {
m = make(map[int32]CostumeAwakenEffectRow)
m = make(map[int32]EntityMCostumeAwakenEffectGroup)
catalog.AwakenEffectsByGroupAndStep[row.CostumeAwakenEffectGroupId] = m
}
m[row.AwakenStep] = row
+3 -20
View File
@@ -5,17 +5,10 @@ import (
"lunar-tear/server/internal/utils"
)
type costumeDupRow struct {
CostumeId int32 `json:"CostumeId"`
PossessionType int32 `json:"PossessionType"`
PossessionId int32 `json:"PossessionId"`
Count int32 `json:"Count"`
}
func LoadDupExchange() (map[int32][]model.DupExchangeEntry, error) {
result := make(map[int32][]model.DupExchangeEntry)
costumeRows, err := utils.ReadJSON[costumeDupRow]("EntityMCostumeDuplicationExchangePossessionGroupTable.json")
costumeRows, err := utils.ReadTable[EntityMCostumeDuplicationExchangePossessionGroup]("m_costume_duplication_exchange_possession_group")
if err != nil {
return nil, err
}
@@ -30,20 +23,10 @@ func LoadDupExchange() (map[int32][]model.DupExchangeEntry, error) {
return result, nil
}
type lbMaterialRow struct {
CostumeLimitBreakMaterialGroupId int32 `json:"CostumeLimitBreakMaterialGroupId"`
MaterialId int32 `json:"MaterialId"`
}
type costumeLBRef struct {
CostumeId int32 `json:"CostumeId"`
CostumeLimitBreakMaterialGroupId int32 `json:"CostumeLimitBreakMaterialGroupId"`
}
const dupExchangeFallbackCount int32 = 10
func EnrichDupExchange(dupMap map[int32][]model.DupExchangeEntry, pool *GachaCatalog) (int, error) {
lbRows, err := utils.ReadJSON[lbMaterialRow]("EntityMCostumeLimitBreakMaterialGroupTable.json")
lbRows, err := utils.ReadTable[EntityMCostumeLimitBreakMaterialGroup]("m_costume_limit_break_material_group")
if err != nil {
return 0, err
}
@@ -52,7 +35,7 @@ func EnrichDupExchange(dupMap map[int32][]model.DupExchangeEntry, pool *GachaCat
groupToMaterial[r.CostumeLimitBreakMaterialGroupId] = r.MaterialId
}
costumeRows, err := utils.ReadJSON[costumeLBRef]("EntityMCostumeTable.json")
costumeRows, err := utils.ReadTable[EntityMCostume]("m_costume")
if err != nil {
return 0, err
}
File diff suppressed because it is too large Load Diff
+8 -25
View File
@@ -7,48 +7,31 @@ import (
"lunar-tear/server/internal/utils"
)
type ExploreRow struct {
ExploreId int32 `json:"ExploreId"`
ConsumeItemCount int32 `json:"ConsumeItemCount"`
RewardLotteryCount int32 `json:"RewardLotteryCount"`
}
type ExploreGradeScoreRow struct {
ExploreId int32 `json:"ExploreId"`
NecessaryScore int32 `json:"NecessaryScore"`
ExploreGradeId int32 `json:"ExploreGradeId"`
}
type ExploreGradeAssetRow struct {
ExploreGradeId int32 `json:"ExploreGradeId"`
AssetGradeIconId int32 `json:"AssetGradeIconId"`
}
type ExploreCatalog struct {
Explores map[int32]ExploreRow
GradeScores map[int32][]ExploreGradeScoreRow // keyed by ExploreId, sorted desc by NecessaryScore
GradeAssets map[int32]int32 // gradeId -> assetGradeIconId
Explores map[int32]EntityMExplore
GradeScores map[int32][]EntityMExploreGradeScore // keyed by ExploreId, sorted desc by NecessaryScore
GradeAssets map[int32]int32 // gradeId -> assetGradeIconId
}
func LoadExploreCatalog() (*ExploreCatalog, error) {
explores, err := utils.ReadJSON[ExploreRow]("EntityMExploreTable.json")
explores, err := utils.ReadTable[EntityMExplore]("m_explore")
if err != nil {
return nil, fmt.Errorf("load explore table: %w", err)
}
gradeScores, err := utils.ReadJSON[ExploreGradeScoreRow]("EntityMExploreGradeScoreTable.json")
gradeScores, err := utils.ReadTable[EntityMExploreGradeScore]("m_explore_grade_score")
if err != nil {
return nil, fmt.Errorf("load explore grade score table: %w", err)
}
gradeAssets, err := utils.ReadJSON[ExploreGradeAssetRow]("EntityMExploreGradeAssetTable.json")
gradeAssets, err := utils.ReadTable[EntityMExploreGradeAsset]("m_explore_grade_asset")
if err != nil {
return nil, fmt.Errorf("load explore grade asset table: %w", err)
}
catalog := &ExploreCatalog{
Explores: make(map[int32]ExploreRow, len(explores)),
GradeScores: make(map[int32][]ExploreGradeScoreRow),
Explores: make(map[int32]EntityMExplore, len(explores)),
GradeScores: make(map[int32][]EntityMExploreGradeScore),
GradeAssets: make(map[int32]int32, len(gradeAssets)),
}
+4 -22
View File
@@ -10,24 +10,6 @@ import (
"lunar-tear/server/internal/utils"
)
type gachaMedalRow struct {
GachaMedalId int32 `json:"GachaMedalId"`
ShopTransitionGachaId int32 `json:"ShopTransitionGachaId"`
ConsumableItemId int32 `json:"ConsumableItemId"`
AutoConvertDatetime int64 `json:"AutoConvertDatetime"`
ConversionRate int32 `json:"ConversionRate"`
}
type momBannerRow struct {
MomBannerId int32 `json:"MomBannerId"`
SortOrderDesc int32 `json:"SortOrderDesc"`
DestinationDomainType int32 `json:"DestinationDomainType"`
DestinationDomainId int32 `json:"DestinationDomainId"`
BannerAssetName string `json:"BannerAssetName"`
StartDatetime int64 `json:"StartDatetime"`
EndDatetime int64 `json:"EndDatetime"`
}
type GachaMedalInfo struct {
GachaMedalId int32
ConsumableItemId int32
@@ -38,16 +20,16 @@ type GachaMedalInfo struct {
const chapterGachaIdBase int32 = 200000
func LoadGachaCatalog() ([]store.GachaCatalogEntry, map[int32]GachaMedalInfo, error) {
medals, err := utils.ReadJSON[gachaMedalRow]("EntityMGachaMedalTable.json")
medals, err := utils.ReadTable[EntityMGachaMedal]("m_gacha_medal")
if err != nil {
return nil, nil, fmt.Errorf("load gacha medal table: %w", err)
}
banners, err := utils.ReadJSON[momBannerRow]("EntityMMomBannerTable.json")
banners, err := utils.ReadTable[EntityMMomBanner]("m_mom_banner")
if err != nil {
return nil, nil, fmt.Errorf("load mom banner table: %w", err)
}
gachaToMedal := make(map[int32]gachaMedalRow)
gachaToMedal := make(map[int32]EntityMGachaMedal)
medalInfoByGacha := make(map[int32]GachaMedalInfo)
for _, m := range medals {
gachaToMedal[m.ShopTransitionGachaId] = m
@@ -59,7 +41,7 @@ func LoadGachaCatalog() ([]store.GachaCatalogEntry, map[int32]GachaMedalInfo, er
}
}
stepupSteps := make(map[int32][]momBannerRow)
stepupSteps := make(map[int32][]EntityMMomBanner)
var entries []store.GachaCatalogEntry
for _, b := range banners {
+8 -38
View File
@@ -46,58 +46,28 @@ type GachaCatalog struct {
ShopFeaturedByMedal map[int32][]ShopFeaturedEntry // consumableId -> paired entries
}
type costumePoolRow struct {
CostumeId int32 `json:"CostumeId"`
CharacterId int32 `json:"CharacterId"`
SkillfulWeaponType int32 `json:"SkillfulWeaponType"`
RarityType int32 `json:"RarityType"`
}
type weaponPoolRow struct {
WeaponId int32 `json:"WeaponId"`
WeaponType int32 `json:"WeaponType"`
RarityType int32 `json:"RarityType"`
IsRestrictDiscard bool `json:"IsRestrictDiscard"`
}
type catalogCostumeRow struct {
CostumeId int32 `json:"CostumeId"`
CatalogTermId int32 `json:"CatalogTermId"`
}
type catalogWeaponRow struct {
WeaponId int32 `json:"WeaponId"`
CatalogTermId int32 `json:"CatalogTermId"`
}
type materialPoolRow struct {
MaterialId int32 `json:"MaterialId"`
MaterialType int32 `json:"MaterialType"`
RarityType int32 `json:"RarityType"`
}
func LoadGachaPool() (*GachaCatalog, error) {
costumes, err := utils.ReadJSON[costumePoolRow]("EntityMCostumeTable.json")
costumes, err := utils.ReadTable[EntityMCostume]("m_costume")
if err != nil {
return nil, fmt.Errorf("load costume table: %w", err)
}
weapons, err := utils.ReadJSON[weaponPoolRow]("EntityMWeaponTable.json")
weapons, err := utils.ReadTable[EntityMWeapon]("m_weapon")
if err != nil {
return nil, fmt.Errorf("load weapon table: %w", err)
}
catalogCostumes, err := utils.ReadJSON[catalogCostumeRow]("EntityMCatalogCostumeTable.json")
catalogCostumes, err := utils.ReadTable[EntityMCatalogCostume]("m_catalog_costume")
if err != nil {
return nil, fmt.Errorf("load catalog costume table: %w", err)
}
catalogWeapons, err := utils.ReadJSON[catalogWeaponRow]("EntityMCatalogWeaponTable.json")
catalogWeapons, err := utils.ReadTable[EntityMCatalogWeapon]("m_catalog_weapon")
if err != nil {
return nil, fmt.Errorf("load catalog weapon table: %w", err)
}
materials, err := utils.ReadJSON[materialPoolRow]("EntityMMaterialTable.json")
materials, err := utils.ReadTable[EntityMMaterial]("m_material")
if err != nil {
return nil, fmt.Errorf("load material table: %w", err)
}
evoGroupRows, err := utils.ReadJSON[WeaponEvolutionGroupRow]("EntityMWeaponEvolutionGroupTable.json")
evoGroupRows, err := utils.ReadTable[EntityMWeaponEvolutionGroup]("m_weapon_evolution_group")
if err != nil {
return nil, fmt.Errorf("load weapon evolution group table: %w", err)
}
@@ -414,8 +384,8 @@ func (pool *GachaCatalog) BuildBannerPools(entries []store.GachaCatalogEntry) {
len(pool.BannerPools), len(allFeaturedCostumes), len(allFeaturedWeapons))
}
func buildEvolvedWeaponSet(rows []WeaponEvolutionGroupRow) map[int32]bool {
grouped := make(map[int32][]WeaponEvolutionGroupRow)
func buildEvolvedWeaponSet(rows []EntityMWeaponEvolutionGroup) map[int32]bool {
grouped := make(map[int32][]EntityMWeaponEvolutionGroup)
for _, r := range rows {
grouped[r.WeaponEvolutionGroupId] = append(grouped[r.WeaponEvolutionGroupId], r)
}
+1 -9
View File
@@ -9,14 +9,6 @@ import (
"lunar-tear/server/internal/utils"
)
type gimmickScheduleRow struct {
GimmickSequenceScheduleId int32 `json:"GimmickSequenceScheduleId"`
StartDatetime int64 `json:"StartDatetime"`
EndDatetime int64 `json:"EndDatetime"`
FirstGimmickSequenceId int32 `json:"FirstGimmickSequenceId"`
ReleaseEvaluateConditionId int32 `json:"ReleaseEvaluateConditionId"`
}
type gimmickScheduleEntry struct {
ScheduleId int32
StartDatetime int64
@@ -30,7 +22,7 @@ type GimmickCatalog struct {
}
func LoadGimmickCatalog(resolver *ConditionResolver) (*GimmickCatalog, error) {
rows, err := utils.ReadJSON[gimmickScheduleRow]("EntityMGimmickSequenceScheduleTable.json")
rows, err := utils.ReadTable[EntityMGimmickSequenceSchedule]("m_gimmick_sequence_schedule")
if err != nil {
return nil, fmt.Errorf("load gimmick sequence schedule table: %w", err)
}
+1 -10
View File
@@ -5,15 +5,6 @@ import (
"lunar-tear/server/internal/utils"
)
type loginBonusStamp struct {
LoginBonusId int32 `json:"LoginBonusId"`
LowerPageNumber int32 `json:"LowerPageNumber"`
StampNumber int32 `json:"StampNumber"`
RewardPossessionType int32 `json:"RewardPossessionType"`
RewardPossessionId int32 `json:"RewardPossessionId"`
RewardCount int32 `json:"RewardCount"`
}
type loginBonusStampKey struct {
LoginBonusId int32
LowerPageNumber int32
@@ -36,7 +27,7 @@ func (c *LoginBonusCatalog) LookupStampReward(loginBonusId, pageNumber, stampNum
}
func LoadLoginBonusCatalog() *LoginBonusCatalog {
stamps, err := utils.ReadJSON[loginBonusStamp]("EntityMLoginBonusStampTable.json")
stamps, err := utils.ReadTable[EntityMLoginBonusStamp]("m_login_bonus_stamp")
if err != nil {
log.Fatalf("load login bonus stamp table: %v", err)
}
+12 -25
View File
@@ -7,29 +7,15 @@ import (
"lunar-tear/server/internal/utils"
)
type MaterialRow struct {
MaterialId int32 `json:"MaterialId"`
MaterialType model.MaterialType `json:"MaterialType"`
WeaponType int32 `json:"WeaponType"`
EffectValue int32 `json:"EffectValue"`
SellPrice int32 `json:"SellPrice"`
}
type numericalParameterMapRow struct {
NumericalParameterMapId int32 `json:"NumericalParameterMapId"`
ParameterKey int32 `json:"ParameterKey"`
ParameterValue int32 `json:"ParameterValue"`
}
func LoadParameterMap() ([]numericalParameterMapRow, error) {
rows, err := utils.ReadJSON[numericalParameterMapRow]("EntityMNumericalParameterMapTable.json")
func LoadParameterMap() ([]EntityMNumericalParameterMap, error) {
rows, err := utils.ReadTable[EntityMNumericalParameterMap]("m_numerical_parameter_map")
if err != nil {
return nil, fmt.Errorf("load numerical parameter map table: %w", err)
}
return rows, nil
}
func BuildExpThresholds(paramMapRows []numericalParameterMapRow, mapId int32) []int32 {
func BuildExpThresholds(paramMapRows []EntityMNumericalParameterMap, mapId int32) []int32 {
maxKey := int32(0)
for _, r := range paramMapRows {
if r.NumericalParameterMapId == mapId && r.ParameterKey > maxKey {
@@ -46,26 +32,27 @@ func BuildExpThresholds(paramMapRows []numericalParameterMapRow, mapId int32) []
}
type MaterialCatalog struct {
All map[int32]MaterialRow
ByType map[model.MaterialType]map[int32]MaterialRow
All map[int32]EntityMMaterial
ByType map[model.MaterialType]map[int32]EntityMMaterial
}
func LoadMaterialCatalog() (*MaterialCatalog, error) {
rows, err := utils.ReadJSON[MaterialRow]("EntityMMaterialTable.json")
rows, err := utils.ReadTable[EntityMMaterial]("m_material")
if err != nil {
return nil, fmt.Errorf("load material table: %w", err)
}
catalog := &MaterialCatalog{
All: make(map[int32]MaterialRow, len(rows)),
ByType: make(map[model.MaterialType]map[int32]MaterialRow),
All: make(map[int32]EntityMMaterial, len(rows)),
ByType: make(map[model.MaterialType]map[int32]EntityMMaterial),
}
for _, row := range rows {
catalog.All[row.MaterialId] = row
if catalog.ByType[row.MaterialType] == nil {
catalog.ByType[row.MaterialType] = make(map[int32]MaterialRow)
mt := model.MaterialType(row.MaterialType)
if catalog.ByType[mt] == nil {
catalog.ByType[mt] = make(map[int32]EntityMMaterial)
}
catalog.ByType[row.MaterialType][row.MaterialId] = row
catalog.ByType[mt][row.MaterialId] = row
}
return catalog, nil
}
@@ -0,0 +1,257 @@
package memorydb
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"encoding/binary"
"encoding/hex"
"fmt"
"os"
"github.com/pierrec/lz4/v4"
"github.com/vmihailenco/msgpack/v5"
)
var tables map[string][]byte
const (
aesKeyHex = "36436230313332314545356536624265"
aesIVHex = "45666341656634434165356536446141"
lz4ExtCode = int8(99)
)
func Init(binPath string) error {
encrypted, err := os.ReadFile(binPath)
if err != nil {
return fmt.Errorf("read bin.e: %w", err)
}
decrypted, err := decrypt(encrypted)
if err != nil {
return fmt.Errorf("decrypt: %w", err)
}
toc, dataBlob, err := parseHeader(decrypted)
if err != nil {
return fmt.Errorf("parse header: %w", err)
}
tables = make(map[string][]byte, len(toc))
for name, offLen := range toc {
off := offLen[0]
length := offLen[1]
if off+length > len(dataBlob) {
return fmt.Errorf("table %q: offset %d + length %d exceeds data blob size %d", name, off, length, len(dataBlob))
}
tables[name] = dataBlob[off : off+length]
}
return nil
}
func TableCount() int {
return len(tables)
}
func TableBytes(key string) ([]byte, bool) {
b, ok := tables[key]
return b, ok
}
func ReadTable[T any](key string) ([]T, error) {
raw, ok := TableBytes(key)
if !ok {
return nil, fmt.Errorf("table %q not found in master data", key)
}
return decompressAndUnmarshal[T](raw)
}
func decrypt(data []byte) ([]byte, error) {
key, err := hex.DecodeString(aesKeyHex)
if err != nil {
return nil, fmt.Errorf("decode key: %w", err)
}
iv, err := hex.DecodeString(aesIVHex)
if err != nil {
return nil, fmt.Errorf("decode iv: %w", err)
}
block, err := aes.NewCipher(key)
if err != nil {
return nil, fmt.Errorf("new cipher: %w", err)
}
if len(data)%aes.BlockSize != 0 {
return nil, fmt.Errorf("ciphertext length %d is not a multiple of block size %d", len(data), aes.BlockSize)
}
decrypted := make([]byte, len(data))
cbc := cipher.NewCBCDecrypter(block, iv)
cbc.CryptBlocks(decrypted, data)
decrypted, err = pkcs7Unpad(decrypted, aes.BlockSize)
if err != nil {
return nil, fmt.Errorf("unpad: %w", err)
}
return decrypted, nil
}
func pkcs7Unpad(data []byte, blockSize int) ([]byte, error) {
if len(data) == 0 {
return nil, fmt.Errorf("empty data")
}
padLen := int(data[len(data)-1])
if padLen == 0 || padLen > blockSize || padLen > len(data) {
return nil, fmt.Errorf("invalid padding length %d", padLen)
}
for _, b := range data[len(data)-padLen:] {
if int(b) != padLen {
return nil, fmt.Errorf("invalid padding byte")
}
}
return data[:len(data)-padLen], nil
}
func parseHeader(data []byte) (map[string][2]int, []byte, error) {
// Decode the header (first msgpack object) using Decode into interface{},
// then compute how many bytes it consumed to find the data blob start.
r := bytes.NewReader(data)
dec := msgpack.NewDecoder(r)
dec.UseLooseInterfaceDecoding(true)
var headerRaw interface{}
if err := dec.Decode(&headerRaw); err != nil {
return nil, nil, fmt.Errorf("decode header: %w", err)
}
headerMap, ok := headerRaw.(map[string]interface{})
if !ok {
return nil, nil, fmt.Errorf("header is not a map, got %T", headerRaw)
}
toc := make(map[string][2]int, len(headerMap))
for name, val := range headerMap {
arr, ok := val.([]interface{})
if !ok || len(arr) != 2 {
return nil, nil, fmt.Errorf("table %q: expected [offset, length] array, got %T", name, val)
}
offset, err := toInt(arr[0])
if err != nil {
return nil, nil, fmt.Errorf("table %q offset: %w", name, err)
}
length, err := toInt(arr[1])
if err != nil {
return nil, nil, fmt.Errorf("table %q length: %w", name, err)
}
toc[name] = [2]int{offset, length}
}
consumed := int(int64(len(data)) - int64(r.Len()))
return toc, data[consumed:], nil
}
func toInt(v interface{}) (int, error) {
switch n := v.(type) {
case int8:
return int(n), nil
case int16:
return int(n), nil
case int32:
return int(n), nil
case int64:
return int(n), nil
case uint8:
return int(n), nil
case uint16:
return int(n), nil
case uint32:
return int(n), nil
case uint64:
return int(n), nil
default:
return 0, fmt.Errorf("cannot convert %T to int", v)
}
}
func decompressAndUnmarshal[T any](raw []byte) ([]T, error) {
// Peek at the raw msgpack to check if it's an ext type (LZ4 compressed)
// or a plain array.
if len(raw) == 0 {
return nil, nil
}
// Try to decode as ext type first
dec := msgpack.NewDecoder(bytes.NewReader(raw))
code, extData, err := decodeExt(dec)
if err == nil && code == lz4ExtCode {
uncompressedSize, lz4Data, err := readLZ4ExtHeader(extData)
if err != nil {
return nil, fmt.Errorf("read lz4 ext header: %w", err)
}
decompressed := make([]byte, uncompressedSize)
n, err := lz4.UncompressBlock(lz4Data, decompressed)
if err != nil {
return nil, fmt.Errorf("lz4 decompress: %w", err)
}
decompressed = decompressed[:n]
var result []T
if err := msgpack.Unmarshal(decompressed, &result); err != nil {
return nil, fmt.Errorf("unmarshal decompressed table: %w", err)
}
return result, nil
}
// Not LZ4 compressed, try as plain array
var result []T
if err := msgpack.Unmarshal(raw, &result); err != nil {
return nil, fmt.Errorf("unmarshal plain table: %w", err)
}
return result, nil
}
func decodeExt(dec *msgpack.Decoder) (int8, []byte, error) {
var ext msgpack.RawMessage
if err := dec.Decode(&ext); err != nil {
return 0, nil, err
}
// ext is the full msgpack ext bytes including the header.
// Re-decode just the header to get the type code, then the body is the rest.
innerDec := msgpack.NewDecoder(bytes.NewReader(ext))
extID, extLen, err := innerDec.DecodeExtHeader()
if err != nil {
return 0, nil, err
}
extData := make([]byte, extLen)
if _, err := innerDec.Buffered().Read(extData); err != nil {
return 0, nil, fmt.Errorf("read ext data: %w", err)
}
return extID, extData, nil
}
func readLZ4ExtHeader(data []byte) (int, []byte, error) {
if len(data) == 0 {
return 0, nil, fmt.Errorf("empty ext data")
}
tag := data[0]
switch {
case tag == 0xd2: // big-endian int32
if len(data) < 5 {
return 0, nil, fmt.Errorf("not enough data for int32 size")
}
size := int(int32(binary.BigEndian.Uint32(data[1:5])))
return size, data[5:], nil
case tag == 0xce: // big-endian uint32
if len(data) < 5 {
return 0, nil, fmt.Errorf("not enough data for uint32 size")
}
size := int(binary.BigEndian.Uint32(data[1:5]))
return size, data[5:], nil
case tag <= 0x7f: // positive fixint
return int(tag), data[1:], nil
default:
return 0, nil, fmt.Errorf("unexpected tag 0x%02x in LZ4 ext header", tag)
}
}
+3 -15
View File
@@ -8,18 +8,6 @@ import (
"lunar-tear/server/internal/utils"
)
type numericalFunctionRow struct {
NumericalFunctionId int32 `json:"NumericalFunctionId"`
NumericalFunctionType int32 `json:"NumericalFunctionType"`
NumericalFunctionParameterGroupId int32 `json:"NumericalFunctionParameterGroupId"`
}
type numericalFunctionParameterRow struct {
NumericalFunctionParameterGroupId int32 `json:"NumericalFunctionParameterGroupId"`
ParameterIndex int32 `json:"ParameterIndex"`
ParameterValue int32 `json:"ParameterValue"`
}
type NumericalFunc struct {
Type model.NumericalFunctionType
Params []int32
@@ -61,17 +49,17 @@ type FunctionResolver struct {
}
func LoadFunctionResolver() (*FunctionResolver, error) {
funcRows, err := utils.ReadJSON[numericalFunctionRow]("EntityMNumericalFunctionTable.json")
funcRows, err := utils.ReadTable[EntityMNumericalFunction]("m_numerical_function")
if err != nil {
return nil, fmt.Errorf("load numerical function table: %w", err)
}
paramRows, err := utils.ReadJSON[numericalFunctionParameterRow]("EntityMNumericalFunctionParameterGroupTable.json")
paramRows, err := utils.ReadTable[EntityMNumericalFunctionParameterGroup]("m_numerical_function_parameter_group")
if err != nil {
return nil, fmt.Errorf("load numerical function parameter group table: %w", err)
}
paramsByGroup := make(map[int32][]numericalFunctionParameterRow, len(paramRows))
paramsByGroup := make(map[int32][]EntityMNumericalFunctionParameterGroup, len(paramRows))
for _, r := range paramRows {
paramsByGroup[r.NumericalFunctionParameterGroupId] = append(
paramsByGroup[r.NumericalFunctionParameterGroupId], r)
+1 -6
View File
@@ -5,11 +5,6 @@ import (
"lunar-tear/server/internal/utils"
)
type omikujiEntry struct {
OmikujiId int32 `json:"OmikujiId"`
OmikujiAssetId int32 `json:"OmikujiAssetId"`
}
type OmikujiCatalog struct {
assetIds map[int32]int32
}
@@ -22,7 +17,7 @@ func (c *OmikujiCatalog) LookupAssetId(omikujiId int32) int32 {
}
func LoadOmikujiCatalog() *OmikujiCatalog {
entries, err := utils.ReadJSON[omikujiEntry]("EntityMOmikujiTable.json")
entries, err := utils.ReadTable[EntityMOmikuji]("m_omikuji")
if err != nil {
log.Fatalf("load omikuji table: %v", err)
}
+8 -34
View File
@@ -7,63 +7,37 @@ import (
"lunar-tear/server/internal/utils"
)
type PartsRow struct {
PartsId int32 `json:"PartsId"`
RarityType model.RarityType `json:"RarityType"`
PartsGroupId int32 `json:"PartsGroupId"`
PartsStatusMainLotteryGroupId int32 `json:"PartsStatusMainLotteryGroupId"`
}
type PartsRarityRow struct {
RarityType model.RarityType `json:"RarityType"`
PartsLevelUpRateGroupId int32 `json:"PartsLevelUpRateGroupId"`
PartsLevelUpPriceGroupId int32 `json:"PartsLevelUpPriceGroupId"`
SellPriceNumericalFunctionId int32 `json:"SellPriceNumericalFunctionId"`
}
type partsLevelUpRateRow struct {
PartsLevelUpRateGroupId int32 `json:"PartsLevelUpRateGroupId"`
LevelLowerLimit int32 `json:"LevelLowerLimit"`
SuccessRatePermil int32 `json:"SuccessRatePermil"`
}
type partsLevelUpPriceRow struct {
PartsLevelUpPriceGroupId int32 `json:"PartsLevelUpPriceGroupId"`
LevelLowerLimit int32 `json:"LevelLowerLimit"`
Gold int32 `json:"Gold"`
}
type PartsCatalog struct {
PartsById map[int32]PartsRow
PartsById map[int32]EntityMParts
DefaultPartsStatusMainByLotteryGroup map[int32]int32
RarityByRarityType map[model.RarityType]PartsRarityRow
RarityByRarityType map[model.RarityType]EntityMPartsRarity
RateByGroupAndLevel map[int32]map[int32]int32
PriceByGroupAndLevel map[int32]map[int32]int32
SellPriceByRarity map[model.RarityType]NumericalFunc
}
func LoadPartsCatalog() (*PartsCatalog, error) {
partsRows, err := utils.ReadJSON[PartsRow]("EntityMPartsTable.json")
partsRows, err := utils.ReadTable[EntityMParts]("m_parts")
if err != nil {
return nil, fmt.Errorf("load parts table: %w", err)
}
rarityRows, err := utils.ReadJSON[PartsRarityRow]("EntityMPartsRarityTable.json")
rarityRows, err := utils.ReadTable[EntityMPartsRarity]("m_parts_rarity")
if err != nil {
return nil, fmt.Errorf("load parts rarity table: %w", err)
}
rateRows, err := utils.ReadJSON[partsLevelUpRateRow]("EntityMPartsLevelUpRateGroupTable.json")
rateRows, err := utils.ReadTable[EntityMPartsLevelUpRateGroup]("m_parts_level_up_rate_group")
if err != nil {
return nil, fmt.Errorf("load parts level up rate table: %w", err)
}
priceRows, err := utils.ReadJSON[partsLevelUpPriceRow]("EntityMPartsLevelUpPriceGroupTable.json")
priceRows, err := utils.ReadTable[EntityMPartsLevelUpPriceGroup]("m_parts_level_up_price_group")
if err != nil {
return nil, fmt.Errorf("load parts level up price table: %w", err)
}
partsById := make(map[int32]PartsRow, len(partsRows))
partsById := make(map[int32]EntityMParts, len(partsRows))
for _, p := range partsRows {
partsById[p.PartsId] = p
}
@@ -84,7 +58,7 @@ func LoadPartsCatalog() (*PartsCatalog, error) {
return nil, fmt.Errorf("load function resolver: %w", err)
}
rarityByRarityType := make(map[model.RarityType]PartsRarityRow, len(rarityRows))
rarityByRarityType := make(map[model.RarityType]EntityMPartsRarity, len(rarityRows))
sellPriceByRarity := make(map[model.RarityType]NumericalFunc, len(rarityRows))
for _, r := range rarityRows {
rarityByRarityType[r.RarityType] = r
+61 -241
View File
@@ -4,214 +4,34 @@ import (
"fmt"
"sort"
"lunar-tear/server/internal/model"
"lunar-tear/server/internal/utils"
)
type QuestSceneRow struct {
QuestSceneId int32 `json:"QuestSceneId"`
QuestId int32 `json:"QuestId"`
SortOrder int32 `json:"SortOrder"`
QuestSceneType model.QuestSceneType `json:"QuestSceneType"`
AssetBackgroundId int32 `json:"AssetBackgroundId"`
EventMapNumberUpper int32 `json:"EventMapNumberUpper"`
EventMapNumberLower int32 `json:"EventMapNumberLower"`
IsMainFlowQuestTarget bool `json:"IsMainFlowQuestTarget"`
IsBattleOnlyTarget bool `json:"IsBattleOnlyTarget"`
QuestResultType model.QuestResultType `json:"QuestResultType"`
IsStorySkipTarget bool `json:"IsStorySkipTarget"`
}
type QuestRow struct {
QuestId int32 `json:"QuestId"`
NameQuestTextId int32 `json:"NameQuestTextId"`
PictureBookNameQuestTextId int32 `json:"PictureBookNameQuestTextId"`
QuestReleaseConditionListId int32 `json:"QuestReleaseConditionListId"`
StoryQuestTextId int32 `json:"StoryQuestTextId"`
QuestDisplayAttributeGroupId int32 `json:"QuestDisplayAttributeGroupId"`
RecommendedDeckPower int32 `json:"RecommendedDeckPower"`
QuestFirstClearRewardGroupId int32 `json:"QuestFirstClearRewardGroupId"`
QuestPickupRewardGroupId int32 `json:"QuestPickupRewardGroupId"`
QuestDeckRestrictionGroupId int32 `json:"QuestDeckRestrictionGroupId"`
QuestMissionGroupId int32 `json:"QuestMissionGroupId"`
Stamina int32 `json:"Stamina"`
UserExp int32 `json:"UserExp"`
CharacterExp int32 `json:"CharacterExp"`
CostumeExp int32 `json:"CostumeExp"`
Gold int32 `json:"Gold"`
DailyClearableCount int32 `json:"DailyClearableCount"`
IsRunInTheBackground bool `json:"IsRunInTheBackground"`
IsCountedAsQuest bool `json:"IsCountedAsQuest"`
QuestBonusId int32 `json:"QuestBonusId"`
IsNotShowAfterClear bool `json:"IsNotShowAfterClear"`
IsBigWinTarget bool `json:"IsBigWinTarget"`
IsUsableSkipTicket bool `json:"IsUsableSkipTicket"`
QuestReplayFlowRewardGroupId int32 `json:"QuestReplayFlowRewardGroupId"`
InvisibleQuestMissionGroupId int32 `json:"InvisibleQuestMissionGroupId"`
FieldEffectGroupId int32 `json:"FieldEffectGroupId"`
}
type QuestMissionRow struct {
QuestMissionId int32 `json:"QuestMissionId"`
QuestMissionConditionType model.QuestMissionConditionType `json:"QuestMissionConditionType"`
QuestMissionRewardId int32 `json:"QuestMissionRewardId"`
QuestMissionConditionValueGroupId int32 `json:"QuestMissionConditionValueGroupId"`
}
type QuestMissionGroupRow struct {
QuestMissionGroupId int32 `json:"QuestMissionGroupId"`
SortOrder int32 `json:"SortOrder"`
QuestMissionId int32 `json:"QuestMissionId"`
}
type QuestMissionRewardRow struct {
QuestMissionRewardId int32 `json:"QuestMissionRewardId"`
PossessionType model.PossessionType `json:"PossessionType"`
PossessionId int32 `json:"PossessionId"`
Count int32 `json:"Count"`
}
type MainQuestSequenceRow struct {
MainQuestSequenceId int32 `json:"MainQuestSequenceId"`
SortOrder int32 `json:"SortOrder"`
QuestId int32 `json:"QuestId"`
}
type MainQuestRouteRow struct {
MainQuestRouteId int32 `json:"MainQuestRouteId"`
MainQuestSeasonId int32 `json:"MainQuestSeasonId"`
SortOrder int32 `json:"SortOrder"`
CharacterId int32 `json:"CharacterId"`
}
type MainQuestChapterRow struct {
MainQuestChapterId int32 `json:"MainQuestChapterId"`
MainQuestRouteId int32 `json:"MainQuestRouteId"`
SortOrder int32 `json:"SortOrder"`
MainQuestSequenceGroupId int32 `json:"MainQuestSequenceGroupId"`
PortalCageCharacterGroupId int32 `json:"PortalCageCharacterGroupId"`
StartDatetime int64 `json:"StartDatetime"`
IsInvisibleInLibrary bool `json:"IsInvisibleInLibrary"`
JoinLibraryChapterId int32 `json:"JoinLibraryChapterId"`
}
type QuestFirstClearRewardSwitchRow struct {
QuestId int32 `json:"QuestId"`
QuestFirstClearRewardGroupId int32 `json:"QuestFirstClearRewardGroupId"`
SwitchConditionClearQuestId int32 `json:"SwitchConditionClearQuestId"`
}
type QuestFirstClearRewardGroupRow struct {
QuestFirstClearRewardGroupId int32 `json:"QuestFirstClearRewardGroupId"`
QuestFirstClearRewardType int32 `json:"QuestFirstClearRewardType"`
SortOrder int32 `json:"SortOrder"`
PossessionType model.PossessionType `json:"PossessionType"`
PossessionId int32 `json:"PossessionId"`
Count int32 `json:"Count"`
IsPickup bool `json:"IsPickup"`
}
type QuestReplayFlowRewardGroupRow struct {
QuestReplayFlowRewardGroupId int32 `json:"QuestReplayFlowRewardGroupId"`
SortOrder int32 `json:"SortOrder"`
PossessionType model.PossessionType `json:"PossessionType"`
PossessionId int32 `json:"PossessionId"`
Count int32 `json:"Count"`
}
type QuestSceneGrantRow struct {
QuestSceneId int32 `json:"QuestSceneId"`
PossessionType model.PossessionType `json:"PossessionType"`
PossessionId int32 `json:"PossessionId"`
Count int32 `json:"Count"`
}
type QuestPickupRewardGroupRow struct {
QuestPickupRewardGroupId int32 `json:"QuestPickupRewardGroupId"`
SortOrder int32 `json:"SortOrder"`
BattleDropRewardId int32 `json:"BattleDropRewardId"`
}
type BattleDropRewardRow struct {
BattleDropRewardId int32 `json:"BattleDropRewardId"`
PossessionType model.PossessionType `json:"PossessionType"`
PossessionId int32 `json:"PossessionId"`
Count int32 `json:"Count"`
}
type QuestSceneBattleRow struct {
QuestSceneId int32 `json:"QuestSceneId"`
BattleGroupId int32 `json:"BattleGroupId"`
}
type BattleGroupRow struct {
BattleGroupId int32 `json:"BattleGroupId"`
WaveNumber int32 `json:"WaveNumber"`
BattleId int32 `json:"BattleId"`
}
type BattleRow struct {
BattleId int32 `json:"BattleId"`
BattleNpcId int32 `json:"BattleNpcId"`
DeckType model.DeckType `json:"DeckType"`
BattleNpcDeckNumber int32 `json:"BattleNpcDeckNumber"`
}
type BattleNpcDeckRow struct {
BattleNpcId int32 `json:"BattleNpcId"`
DeckType model.DeckType `json:"DeckType"`
BattleNpcDeckNumber int32 `json:"BattleNpcDeckNumber"`
BattleNpcDeckCharacterUuid01 string `json:"BattleNpcDeckCharacterUuid01"`
BattleNpcDeckCharacterUuid02 string `json:"BattleNpcDeckCharacterUuid02"`
BattleNpcDeckCharacterUuid03 string `json:"BattleNpcDeckCharacterUuid03"`
}
type BattleNpcDropCategoryRow struct {
BattleNpcId int32 `json:"BattleNpcId"`
BattleNpcDeckCharacterUuid string `json:"BattleNpcDeckCharacterUuid"`
BattleDropCategoryId int32 `json:"BattleDropCategoryId"`
}
type BattleDropInfo struct {
QuestSceneId int32
BattleDropCategoryId int32
}
type TutorialUnlockConditionRow struct {
TutorialType int32 `json:"TutorialType"`
TutorialUnlockConditionType int32 `json:"TutorialUnlockConditionType"`
ConditionValue int32 `json:"ConditionValue"`
}
type RentalDeckRow struct {
BattleGroupId int32 `json:"BattleGroupId"`
}
type UserLevelRow struct {
UserLevel int32 `json:"UserLevel"`
MaxStamina int32 `json:"MaxStamina"`
}
type QuestCatalog struct {
SceneById map[int32]QuestSceneRow
MissionById map[int32]QuestMissionRow
QuestById map[int32]QuestRow
SceneById map[int32]EntityMQuestScene
MissionById map[int32]EntityMQuestMission
QuestById map[int32]EntityMQuest
MissionIdsByQuestId map[int32][]int32
RouteIdByQuestId map[int32]int32
SceneIdsByQuestId map[int32][]int32
OrderedQuestIds []int32
FirstClearRewardsByGroupId map[int32][]QuestFirstClearRewardGroupRow
FirstClearRewardSwitchesByQuestId map[int32][]QuestFirstClearRewardSwitchRow
MissionRewardsByMissionId map[int32][]QuestMissionRewardRow
FirstClearRewardsByGroupId map[int32][]EntityMQuestFirstClearRewardGroup
FirstClearRewardSwitchesByQuestId map[int32][]EntityMQuestFirstClearRewardSwitch
MissionRewardsByMissionId map[int32][]EntityMQuestMissionReward
WeaponIdsByReleaseConditionGroupId map[int32][]int32
ReleaseConditionsByGroupId map[int32][]WeaponStoryReleaseConditionRow
SceneGrantsBySceneId map[int32][]QuestSceneGrantRow
BattleDropRewardById map[int32]BattleDropRewardRow
ReleaseConditionsByGroupId map[int32][]EntityMWeaponStoryReleaseConditionGroup
SceneGrantsBySceneId map[int32][]EntityMUserQuestSceneGrantPossession
BattleDropRewardById map[int32]EntityMBattleDropReward
PickupRewardIdsByGroupId map[int32][]int32
BattleDropsByQuestId map[int32][]BattleDropInfo
ReplayFlowRewardsByGroupId map[int32][]QuestReplayFlowRewardGroupRow
ReplayFlowRewardsByGroupId map[int32][]EntityMQuestReplayFlowRewardGroup
RentalQuestIds map[int32]bool
TutorialUnlockConditions []TutorialUnlockConditionRow
TutorialUnlockConditions []EntityMTutorialUnlockCondition
ChapterLastSceneByQuestId map[int32]int32
SeasonIdByRouteId map[int32]int32
@@ -221,8 +41,8 @@ type QuestCatalog struct {
CostumeMaxLevelByRarity map[int32]NumericalFunc
MaxStaminaByLevel map[int32]int32
CostumeById map[int32]CostumeMasterRow
WeaponById map[int32]WeaponMasterRow
CostumeById map[int32]EntityMCostume
WeaponById map[int32]EntityMWeapon
WeaponSkillSlots map[int32][]int32
WeaponAbilitySlots map[int32][]int32
@@ -231,7 +51,7 @@ type QuestCatalog struct {
}
func LoadQuestCatalog(partsCatalog *PartsCatalog) (*QuestCatalog, error) {
scenes, err := utils.ReadJSON[QuestSceneRow]("EntityMQuestSceneTable.json")
scenes, err := utils.ReadTable[EntityMQuestScene]("m_quest_scene")
if err != nil {
return nil, fmt.Errorf("load quest scene table: %w", err)
}
@@ -245,17 +65,17 @@ func LoadQuestCatalog(partsCatalog *PartsCatalog) (*QuestCatalog, error) {
return scenes[i].QuestSceneId < scenes[j].QuestSceneId
})
missions, err := utils.ReadJSON[QuestMissionRow]("EntityMQuestMissionTable.json")
missions, err := utils.ReadTable[EntityMQuestMission]("m_quest_mission")
if err != nil {
return nil, fmt.Errorf("load quest mission table: %w", err)
}
quests, err := utils.ReadJSON[QuestRow]("EntityMQuestTable.json")
quests, err := utils.ReadTable[EntityMQuest]("m_quest")
if err != nil {
return nil, fmt.Errorf("load quest table: %w", err)
}
missionGroups, err := utils.ReadJSON[QuestMissionGroupRow]("EntityMQuestMissionGroupTable.json")
missionGroups, err := utils.ReadTable[EntityMQuestMissionGroup]("m_quest_mission_group")
if err != nil {
return nil, fmt.Errorf("load quest mission group table: %w", err)
}
@@ -269,7 +89,7 @@ func LoadQuestCatalog(partsCatalog *PartsCatalog) (*QuestCatalog, error) {
return missionGroups[i].QuestMissionId < missionGroups[j].QuestMissionId
})
sequences, err := utils.ReadJSON[MainQuestSequenceRow]("EntityMMainQuestSequenceTable.json")
sequences, err := utils.ReadTable[EntityMMainQuestSequence]("m_main_quest_sequence")
if err != nil {
return nil, fmt.Errorf("load main quest sequence table: %w", err)
}
@@ -283,12 +103,12 @@ func LoadQuestCatalog(partsCatalog *PartsCatalog) (*QuestCatalog, error) {
return sequences[i].QuestId < sequences[j].QuestId
})
chapters, err := utils.ReadJSON[MainQuestChapterRow]("EntityMMainQuestChapterTable.json")
chapters, err := utils.ReadTable[EntityMMainQuestChapter]("m_main_quest_chapter")
if err != nil {
return nil, fmt.Errorf("load main quest chapter table: %w", err)
}
routes, err := utils.ReadJSON[MainQuestRouteRow]("EntityMMainQuestRouteTable.json")
routes, err := utils.ReadTable[EntityMMainQuestRoute]("m_main_quest_route")
if err != nil {
return nil, fmt.Errorf("load main quest route table: %w", err)
}
@@ -297,12 +117,12 @@ func LoadQuestCatalog(partsCatalog *PartsCatalog) (*QuestCatalog, error) {
seasonIdByRouteId[r.MainQuestRouteId] = r.MainQuestSeasonId
}
firstClearSwitches, err := utils.ReadJSON[QuestFirstClearRewardSwitchRow]("EntityMQuestFirstClearRewardSwitchTable.json")
firstClearSwitches, err := utils.ReadTable[EntityMQuestFirstClearRewardSwitch]("m_quest_first_clear_reward_switch")
if err != nil {
return nil, fmt.Errorf("load quest first clear reward switch table: %w", err)
}
firstClearRewards, err := utils.ReadJSON[QuestFirstClearRewardGroupRow]("EntityMQuestFirstClearRewardGroupTable.json")
firstClearRewards, err := utils.ReadTable[EntityMQuestFirstClearRewardGroup]("m_quest_first_clear_reward_group")
if err != nil {
return nil, fmt.Errorf("load quest first clear reward group table: %w", err)
}
@@ -316,7 +136,7 @@ func LoadQuestCatalog(partsCatalog *PartsCatalog) (*QuestCatalog, error) {
return firstClearRewards[i].QuestFirstClearRewardType < firstClearRewards[j].QuestFirstClearRewardType
})
replayFlowRewards, err := utils.ReadJSON[QuestReplayFlowRewardGroupRow]("EntityMQuestReplayFlowRewardGroupTable.json")
replayFlowRewards, err := utils.ReadTable[EntityMQuestReplayFlowRewardGroup]("m_quest_replay_flow_reward_group")
if err != nil {
return nil, fmt.Errorf("load quest replay flow reward group table: %w", err)
}
@@ -327,52 +147,52 @@ func LoadQuestCatalog(partsCatalog *PartsCatalog) (*QuestCatalog, error) {
return replayFlowRewards[i].SortOrder < replayFlowRewards[j].SortOrder
})
missionRewards, err := utils.ReadJSON[QuestMissionRewardRow]("EntityMQuestMissionRewardTable.json")
missionRewards, err := utils.ReadTable[EntityMQuestMissionReward]("m_quest_mission_reward")
if err != nil {
return nil, fmt.Errorf("load quest mission reward table: %w", err)
}
weapons, err := utils.ReadJSON[WeaponMasterRow]("EntityMWeaponTable.json")
weapons, err := utils.ReadTable[EntityMWeapon]("m_weapon")
if err != nil {
return nil, fmt.Errorf("load weapon table: %w", err)
}
weaponSkillGroups, err := utils.ReadJSON[WeaponSkillGroupRow]("EntityMWeaponSkillGroupTable.json")
weaponSkillGroups, err := utils.ReadTable[EntityMWeaponSkillGroup]("m_weapon_skill_group")
if err != nil {
return nil, fmt.Errorf("load weapon skill group table: %w", err)
}
weaponAbilityGroups, err := utils.ReadJSON[WeaponAbilityGroupRow]("EntityMWeaponAbilityGroupTable.json")
weaponAbilityGroups, err := utils.ReadTable[EntityMWeaponAbilityGroup]("m_weapon_ability_group")
if err != nil {
return nil, fmt.Errorf("load weapon ability group table: %w", err)
}
releaseConditions, err := utils.ReadJSON[WeaponStoryReleaseConditionRow]("EntityMWeaponStoryReleaseConditionGroupTable.json")
releaseConditions, err := utils.ReadTable[EntityMWeaponStoryReleaseConditionGroup]("m_weapon_story_release_condition_group")
if err != nil {
return nil, fmt.Errorf("load weapon story release condition table: %w", err)
}
costumeMasters, err := utils.ReadJSON[CostumeMasterRow]("EntityMCostumeTable.json")
costumeMasters, err := utils.ReadTable[EntityMCostume]("m_costume")
if err != nil {
return nil, fmt.Errorf("load costume table: %w", err)
}
costumeRarities, err := utils.ReadJSON[costumeRarityRow]("EntityMCostumeRarityTable.json")
costumeRarities, err := utils.ReadTable[EntityMCostumeRarity]("m_costume_rarity")
if err != nil {
return nil, fmt.Errorf("load costume rarity table: %w", err)
}
sceneGrants, err := utils.ReadJSON[QuestSceneGrantRow]("EntityMUserQuestSceneGrantPossessionTable.json")
sceneGrants, err := utils.ReadTable[EntityMUserQuestSceneGrantPossession]("m_user_quest_scene_grant_possession")
if err != nil {
return nil, fmt.Errorf("load quest scene grant table: %w", err)
}
battleDropRewards, err := utils.ReadJSON[BattleDropRewardRow]("EntityMBattleDropRewardTable.json")
battleDropRewards, err := utils.ReadTable[EntityMBattleDropReward]("m_battle_drop_reward")
if err != nil {
return nil, fmt.Errorf("load battle drop reward table: %w", err)
}
pickupRewardGroups, err := utils.ReadJSON[QuestPickupRewardGroupRow]("EntityMQuestPickupRewardGroupTable.json")
pickupRewardGroups, err := utils.ReadTable[EntityMQuestPickupRewardGroup]("m_quest_pickup_reward_group")
if err != nil {
return nil, fmt.Errorf("load quest pickup reward group table: %w", err)
}
@@ -383,37 +203,37 @@ func LoadQuestCatalog(partsCatalog *PartsCatalog) (*QuestCatalog, error) {
return pickupRewardGroups[i].SortOrder < pickupRewardGroups[j].SortOrder
})
sceneBattles, err := utils.ReadJSON[QuestSceneBattleRow]("EntityMQuestSceneBattleTable.json")
sceneBattles, err := utils.ReadTable[EntityMQuestSceneBattle]("m_quest_scene_battle")
if err != nil {
return nil, fmt.Errorf("load quest scene battle table: %w", err)
}
battleGroups, err := utils.ReadJSON[BattleGroupRow]("EntityMBattleGroupTable.json")
battleGroups, err := utils.ReadTable[EntityMBattleGroup]("m_battle_group")
if err != nil {
return nil, fmt.Errorf("load battle group table: %w", err)
}
battles, err := utils.ReadJSON[BattleRow]("EntityMBattleTable.json")
battles, err := utils.ReadTable[EntityMBattle]("m_battle")
if err != nil {
return nil, fmt.Errorf("load battle table: %w", err)
}
npcDecks, err := utils.ReadJSON[BattleNpcDeckRow]("EntityMBattleNpcDeckTable.json")
npcDecks, err := utils.ReadTable[EntityMBattleNpcDeck]("m_battle_npc_deck")
if err != nil {
return nil, fmt.Errorf("load battle npc deck table: %w", err)
}
npcDropCategories, err := utils.ReadJSON[BattleNpcDropCategoryRow]("EntityMBattleNpcDeckCharacterDropCategoryTable.json")
npcDropCategories, err := utils.ReadTable[EntityMBattleNpcDeckCharacterDropCategory]("m_battle_npc_deck_character_drop_category")
if err != nil {
return nil, fmt.Errorf("load battle npc drop category table: %w", err)
}
rentalDecks, err := utils.ReadJSON[RentalDeckRow]("EntityMBattleRentalDeckTable.json")
rentalDecks, err := utils.ReadTable[EntityMBattleRentalDeck]("m_battle_rental_deck")
if err != nil {
return nil, fmt.Errorf("load battle rental deck table: %w", err)
}
tutorialUnlockConds, err := utils.ReadJSON[TutorialUnlockConditionRow]("EntityMTutorialUnlockConditionTable.json")
tutorialUnlockConds, err := utils.ReadTable[EntityMTutorialUnlockCondition]("m_tutorial_unlock_condition")
if err != nil {
return nil, fmt.Errorf("load tutorial unlock condition table: %w", err)
}
@@ -423,7 +243,7 @@ func LoadQuestCatalog(partsCatalog *PartsCatalog) (*QuestCatalog, error) {
return nil, err
}
userLevels, err := utils.ReadJSON[UserLevelRow]("EntityMUserLevelTable.json")
userLevels, err := utils.ReadTable[EntityMUserLevel]("m_user_level")
if err != nil {
return nil, fmt.Errorf("load user level table: %w", err)
}
@@ -450,12 +270,12 @@ func LoadQuestCatalog(partsCatalog *PartsCatalog) (*QuestCatalog, error) {
}
}
costumeById := make(map[int32]CostumeMasterRow, len(costumeMasters))
costumeById := make(map[int32]EntityMCostume, len(costumeMasters))
for _, cm := range costumeMasters {
costumeById[cm.CostumeId] = cm
}
weaponById := make(map[int32]WeaponMasterRow, len(weapons))
weaponById := make(map[int32]EntityMWeapon, len(weapons))
for _, w := range weapons {
weaponById[w.WeaponId] = w
}
@@ -469,19 +289,19 @@ func LoadQuestCatalog(partsCatalog *PartsCatalog) (*QuestCatalog, error) {
abilitySlots[row.WeaponAbilityGroupId] = append(abilitySlots[row.WeaponAbilityGroupId], row.SlotNumber)
}
sceneById := make(map[int32]QuestSceneRow, len(scenes))
sceneById := make(map[int32]EntityMQuestScene, len(scenes))
sceneIdsByQuestId := make(map[int32][]int32)
for _, scene := range scenes {
sceneById[scene.QuestSceneId] = scene
sceneIdsByQuestId[scene.QuestId] = append(sceneIdsByQuestId[scene.QuestId], scene.QuestSceneId)
}
missionById := make(map[int32]QuestMissionRow, len(missions))
missionById := make(map[int32]EntityMQuestMission, len(missions))
for _, mission := range missions {
missionById[mission.QuestMissionId] = mission
}
questById := make(map[int32]QuestRow, len(quests))
questById := make(map[int32]EntityMQuest, len(quests))
for _, quest := range quests {
questById[quest.QuestId] = quest
}
@@ -500,7 +320,7 @@ func LoadQuestCatalog(partsCatalog *PartsCatalog) (*QuestCatalog, error) {
missionIdsByQuestId[questId] = append([]int32(nil), missionIds...)
}
chapterBySequenceId := make(map[int32]MainQuestChapterRow, len(chapters))
chapterBySequenceId := make(map[int32]EntityMMainQuestChapter, len(chapters))
for _, chapter := range chapters {
chapterBySequenceId[chapter.MainQuestSequenceGroupId] = chapter
}
@@ -511,12 +331,12 @@ func LoadQuestCatalog(partsCatalog *PartsCatalog) (*QuestCatalog, error) {
}
}
sortedChapters := make([]MainQuestChapterRow, len(chapters))
sortedChapters := make([]EntityMMainQuestChapter, len(chapters))
copy(sortedChapters, chapters)
sort.Slice(sortedChapters, func(i, j int) bool {
return sortedChapters[i].SortOrder < sortedChapters[j].SortOrder
})
sequencesByGroupId := make(map[int32][]MainQuestSequenceRow)
sequencesByGroupId := make(map[int32][]EntityMMainQuestSequence)
for _, seq := range sequences {
sequencesByGroupId[seq.MainQuestSequenceId] = append(sequencesByGroupId[seq.MainQuestSequenceId], seq)
}
@@ -544,25 +364,25 @@ func LoadQuestCatalog(partsCatalog *PartsCatalog) (*QuestCatalog, error) {
}
}
firstClearRewardsByGroupId := make(map[int32][]QuestFirstClearRewardGroupRow, len(firstClearRewards))
firstClearRewardsByGroupId := make(map[int32][]EntityMQuestFirstClearRewardGroup, len(firstClearRewards))
for _, reward := range firstClearRewards {
firstClearRewardsByGroupId[reward.QuestFirstClearRewardGroupId] = append(
firstClearRewardsByGroupId[reward.QuestFirstClearRewardGroupId], reward)
}
replayFlowRewardsByGroupId := make(map[int32][]QuestReplayFlowRewardGroupRow, len(replayFlowRewards))
replayFlowRewardsByGroupId := make(map[int32][]EntityMQuestReplayFlowRewardGroup, len(replayFlowRewards))
for _, reward := range replayFlowRewards {
replayFlowRewardsByGroupId[reward.QuestReplayFlowRewardGroupId] = append(
replayFlowRewardsByGroupId[reward.QuestReplayFlowRewardGroupId], reward)
}
firstClearRewardSwitchesByQuestId := make(map[int32][]QuestFirstClearRewardSwitchRow, len(firstClearSwitches))
firstClearRewardSwitchesByQuestId := make(map[int32][]EntityMQuestFirstClearRewardSwitch, len(firstClearSwitches))
for _, switchRow := range firstClearSwitches {
firstClearRewardSwitchesByQuestId[switchRow.QuestId] = append(
firstClearRewardSwitchesByQuestId[switchRow.QuestId], switchRow)
}
missionRewardsByMissionId := make(map[int32][]QuestMissionRewardRow, len(missionRewards))
missionRewardsByMissionId := make(map[int32][]EntityMQuestMissionReward, len(missionRewards))
for _, reward := range missionRewards {
missionRewardsByMissionId[reward.QuestMissionRewardId] = append(
missionRewardsByMissionId[reward.QuestMissionRewardId], reward)
@@ -576,18 +396,18 @@ func LoadQuestCatalog(partsCatalog *PartsCatalog) (*QuestCatalog, error) {
}
}
releaseConditionsByGroupId := make(map[int32][]WeaponStoryReleaseConditionRow)
releaseConditionsByGroupId := make(map[int32][]EntityMWeaponStoryReleaseConditionGroup)
for _, c := range releaseConditions {
releaseConditionsByGroupId[c.WeaponStoryReleaseConditionGroupId] = append(
releaseConditionsByGroupId[c.WeaponStoryReleaseConditionGroupId], c)
}
sceneGrantsBySceneId := make(map[int32][]QuestSceneGrantRow)
sceneGrantsBySceneId := make(map[int32][]EntityMUserQuestSceneGrantPossession)
for _, sg := range sceneGrants {
sceneGrantsBySceneId[sg.QuestSceneId] = append(sceneGrantsBySceneId[sg.QuestSceneId], sg)
}
battleDropRewardById := make(map[int32]BattleDropRewardRow, len(battleDropRewards))
battleDropRewardById := make(map[int32]EntityMBattleDropReward, len(battleDropRewards))
for _, bdr := range battleDropRewards {
battleDropRewardById[bdr.BattleDropRewardId] = bdr
}
@@ -609,22 +429,22 @@ func LoadQuestCatalog(partsCatalog *PartsCatalog) (*QuestCatalog, error) {
}
type npcDeckKey struct {
BattleNpcId int32
DeckType model.DeckType
BattleNpcId int64
DeckType int32
BattleNpcDeckNumber int32
}
npcDeckByKey := make(map[npcDeckKey]BattleNpcDeckRow, len(npcDecks))
npcDeckByKey := make(map[npcDeckKey]EntityMBattleNpcDeck, len(npcDecks))
for _, d := range npcDecks {
npcDeckByKey[npcDeckKey{d.BattleNpcId, d.DeckType, d.BattleNpcDeckNumber}] = d
}
battleByIdMap := make(map[int32]BattleRow, len(battles))
battleByIdMap := make(map[int32]EntityMBattle, len(battles))
for _, b := range battles {
battleByIdMap[b.BattleId] = b
}
type dropCatKey struct {
BattleNpcId int32
BattleNpcId int64
Uuid string
}
dropCategoryByKey := make(map[dropCatKey]int32, len(npcDropCategories))
+15 -64
View File
@@ -8,96 +8,47 @@ import (
"lunar-tear/server/internal/utils"
)
type ShopItemRow struct {
ShopItemId int32 `json:"ShopItemId"`
PriceType int32 `json:"PriceType"`
PriceId int32 `json:"PriceId"`
Price int32 `json:"Price"`
ShopItemLimitedStockId int32 `json:"ShopItemLimitedStockId"`
}
type ShopContentRow struct {
ShopItemId int32 `json:"ShopItemId"`
PossessionType int32 `json:"PossessionType"`
PossessionId int32 `json:"PossessionId"`
Count int32 `json:"Count"`
}
type ShopContentEffectRow struct {
ShopItemId int32 `json:"ShopItemId"`
EffectTargetType int32 `json:"EffectTargetType"`
EffectValueType int32 `json:"EffectValueType"`
EffectValue int32 `json:"EffectValue"`
}
type shopItemLimitedStockRow struct {
ShopItemLimitedStockId int32 `json:"ShopItemLimitedStockId"`
MaxCount int32 `json:"MaxCount"`
}
type shopRow struct {
ShopId int32 `json:"ShopId"`
ShopGroupType int32 `json:"ShopGroupType"`
ShopItemCellGroupId int32 `json:"ShopItemCellGroupId"`
}
type shopItemCellGroupRow struct {
ShopItemCellGroupId int32 `json:"ShopItemCellGroupId"`
ShopItemCellId int32 `json:"ShopItemCellId"`
SortOrder int32 `json:"SortOrder"`
}
type shopItemCellRow struct {
ShopItemCellId int32 `json:"ShopItemCellId"`
ShopItemId int32 `json:"ShopItemId"`
}
type ExchangeShopCell struct {
SortOrder int32
ShopItemId int32
}
type ShopCatalog struct {
Items map[int32]ShopItemRow
Contents map[int32][]ShopContentRow
Effects map[int32][]ShopContentEffectRow
Items map[int32]EntityMShopItem
Contents map[int32][]EntityMShopItemContentPossession
Effects map[int32][]EntityMShopItemContentEffect
MaxStaminaMillis map[int32]int32 // level -> max stamina in millis
LimitedStock map[int32]int32 // stock id -> max count
ItemShopPool []int32 // shop item IDs for the replaceable item shop, sorted by cell sort order
ExchangeShopCells map[int32][]ExchangeShopCell // shopId -> sorted cells for exchange shops
}
type userLevelEntry struct {
UserLevel int32 `json:"UserLevel"`
MaxStamina int32 `json:"MaxStamina"`
}
func LoadShopCatalog() (*ShopCatalog, error) {
items, err := utils.ReadJSON[ShopItemRow]("EntityMShopItemTable.json")
items, err := utils.ReadTable[EntityMShopItem]("m_shop_item")
if err != nil {
return nil, fmt.Errorf("load shop item table: %w", err)
}
contents, err := utils.ReadJSON[ShopContentRow]("EntityMShopItemContentPossessionTable.json")
contents, err := utils.ReadTable[EntityMShopItemContentPossession]("m_shop_item_content_possession")
if err != nil {
return nil, fmt.Errorf("load shop content possession table: %w", err)
}
effects, err := utils.ReadJSON[ShopContentEffectRow]("EntityMShopItemContentEffectTable.json")
effects, err := utils.ReadTable[EntityMShopItemContentEffect]("m_shop_item_content_effect")
if err != nil {
return nil, fmt.Errorf("load shop content effect table: %w", err)
}
userLevels, err := utils.ReadJSON[userLevelEntry]("EntityMUserLevelTable.json")
userLevels, err := utils.ReadTable[EntityMUserLevel]("m_user_level")
if err != nil {
return nil, fmt.Errorf("load user level table: %w", err)
}
stockRows, err := utils.ReadJSON[shopItemLimitedStockRow]("EntityMShopItemLimitedStockTable.json")
stockRows, err := utils.ReadTable[EntityMShopItemLimitedStock]("m_shop_item_limited_stock")
if err != nil {
return nil, fmt.Errorf("load shop item limited stock table: %w", err)
}
catalog := &ShopCatalog{
Items: make(map[int32]ShopItemRow, len(items)),
Contents: make(map[int32][]ShopContentRow, len(contents)),
Effects: make(map[int32][]ShopContentEffectRow, len(effects)),
Items: make(map[int32]EntityMShopItem, len(items)),
Contents: make(map[int32][]EntityMShopItemContentPossession, len(contents)),
Effects: make(map[int32][]EntityMShopItemContentEffect, len(effects)),
MaxStaminaMillis: make(map[int32]int32, len(userLevels)),
LimitedStock: make(map[int32]int32, len(stockRows)),
}
@@ -117,15 +68,15 @@ func LoadShopCatalog() (*ShopCatalog, error) {
catalog.LimitedStock[row.ShopItemLimitedStockId] = row.MaxCount
}
shops, err := utils.ReadJSON[shopRow]("EntityMShopTable.json")
shops, err := utils.ReadTable[EntityMShop]("m_shop")
if err != nil {
return nil, fmt.Errorf("load shop table: %w", err)
}
cellGroups, err := utils.ReadJSON[shopItemCellGroupRow]("EntityMShopItemCellGroupTable.json")
cellGroups, err := utils.ReadTable[EntityMShopItemCellGroup]("m_shop_item_cell_group")
if err != nil {
return nil, fmt.Errorf("load shop item cell group table: %w", err)
}
cells, err := utils.ReadJSON[shopItemCellRow]("EntityMShopItemCellTable.json")
cells, err := utils.ReadTable[EntityMShopItemCell]("m_shop_item_cell")
if err != nil {
return nil, fmt.Errorf("load shop item cell table: %w", err)
}
@@ -135,7 +86,7 @@ func LoadShopCatalog() (*ShopCatalog, error) {
cellIdToItemId[c.ShopItemCellId] = c.ShopItemId
}
cellGroupByCGId := make(map[int32][]shopItemCellGroupRow, len(cellGroups))
cellGroupByCGId := make(map[int32][]EntityMShopItemCellGroup, len(cellGroups))
for _, cg := range cellGroups {
cellGroupByCGId[cg.ShopItemCellGroupId] = append(cellGroupByCGId[cg.ShopItemCellGroupId], cg)
}
+1 -7
View File
@@ -5,18 +5,12 @@ import (
"lunar-tear/server/internal/utils"
)
type sideStorySceneRow struct {
SideStoryQuestId int32 `json:"SideStoryQuestId"`
SideStoryQuestSceneId int32 `json:"SideStoryQuestSceneId"`
SortOrder int32 `json:"SortOrder"`
}
type SideStoryCatalog struct {
FirstSceneByQuestId map[int32]int32
}
func LoadSideStoryCatalog() *SideStoryCatalog {
scenes, err := utils.ReadJSON[sideStorySceneRow]("EntityMSideStoryQuestSceneTable.json")
scenes, err := utils.ReadTable[EntityMSideStoryQuestScene]("m_side_story_quest_scene")
if err != nil {
log.Fatalf("load side story quest scene table: %v", err)
}
+35 -152
View File
@@ -9,172 +9,55 @@ import (
"lunar-tear/server/internal/utils"
)
type WeaponMasterRow struct {
WeaponId int32 `json:"WeaponId"`
RarityType int32 `json:"RarityType"`
WeaponType int32 `json:"WeaponType"`
WeaponSpecificEnhanceId int32 `json:"WeaponSpecificEnhanceId"`
WeaponSkillGroupId int32 `json:"WeaponSkillGroupId"`
WeaponAbilityGroupId int32 `json:"WeaponAbilityGroupId"`
WeaponStoryReleaseConditionGroupId int32 `json:"WeaponStoryReleaseConditionGroupId"`
WeaponEvolutionMaterialGroupId int32 `json:"WeaponEvolutionMaterialGroupId"`
}
type WeaponStoryReleaseConditionRow struct {
WeaponStoryReleaseConditionGroupId int32 `json:"WeaponStoryReleaseConditionGroupId"`
StoryIndex int32 `json:"StoryIndex"`
WeaponStoryReleaseConditionType model.WeaponStoryReleaseConditionType `json:"WeaponStoryReleaseConditionType"`
ConditionValue int32 `json:"ConditionValue"`
WeaponStoryReleaseConditionOperationGroupId int32 `json:"WeaponStoryReleaseConditionOperationGroupId"`
}
type WeaponSkillGroupRow struct {
WeaponSkillGroupId int32 `json:"WeaponSkillGroupId"`
SlotNumber int32 `json:"SlotNumber"`
SkillId int32 `json:"SkillId"`
WeaponSkillEnhancementMaterialId int32 `json:"WeaponSkillEnhancementMaterialId"`
}
type WeaponAbilityGroupRow struct {
WeaponAbilityGroupId int32 `json:"WeaponAbilityGroupId"`
SlotNumber int32 `json:"SlotNumber"`
AbilityId int32 `json:"AbilityId"`
WeaponAbilityEnhancementMaterialId int32 `json:"WeaponAbilityEnhancementMaterialId"`
}
type weaponSpecificEnhanceRow struct {
WeaponSpecificEnhanceId int32 `json:"WeaponSpecificEnhanceId"`
BaseEnhancementObtainedExp int32 `json:"BaseEnhancementObtainedExp"`
SellPriceNumericalFunctionId int32 `json:"SellPriceNumericalFunctionId"`
RequiredExpForLevelUpNumericalParameterMapId int32 `json:"RequiredExpForLevelUpNumericalParameterMapId"`
EnhancementCostByWeaponNumericalFunctionId int32 `json:"EnhancementCostByWeaponNumericalFunctionId"`
EnhancementCostByMaterialNumericalFunctionId int32 `json:"EnhancementCostByMaterialNumericalFunctionId"`
MaxLevelNumericalFunctionId int32 `json:"MaxLevelNumericalFunctionId"`
EvolutionCostNumericalFunctionId int32 `json:"EvolutionCostNumericalFunctionId"`
LimitBreakCostByWeaponNumericalFunctionId int32 `json:"LimitBreakCostByWeaponNumericalFunctionId"`
LimitBreakCostByMaterialNumericalFunctionId int32 `json:"LimitBreakCostByMaterialNumericalFunctionId"`
MaxSkillLevelNumericalFunctionId int32 `json:"MaxSkillLevelNumericalFunctionId"`
SkillEnhancementCostNumericalFunctionId int32 `json:"SkillEnhancementCostNumericalFunctionId"`
MaxAbilityLevelNumericalFunctionId int32 `json:"MaxAbilityLevelNumericalFunctionId"`
AbilityEnhancementCostNumericalFunctionId int32 `json:"AbilityEnhancementCostNumericalFunctionId"`
}
type weaponConsumeExchangeRow struct {
WeaponId int32 `json:"WeaponId"`
ConsumableItemId int32 `json:"ConsumableItemId"`
Count int32 `json:"Count"`
}
type WeaponEvolutionGroupRow struct {
WeaponEvolutionGroupId int32 `json:"WeaponEvolutionGroupId"`
EvolutionOrder int32 `json:"EvolutionOrder"`
WeaponId int32 `json:"WeaponId"`
}
type WeaponEvolutionMaterialRow struct {
WeaponEvolutionMaterialGroupId int32 `json:"WeaponEvolutionMaterialGroupId"`
MaterialId int32 `json:"MaterialId"`
Count int32 `json:"Count"`
SortOrder int32 `json:"SortOrder"`
}
type WeaponSkillEnhanceMaterialRow struct {
WeaponSkillEnhancementMaterialId int32 `json:"WeaponSkillEnhancementMaterialId"`
SkillLevel int32 `json:"SkillLevel"`
MaterialId int32 `json:"MaterialId"`
Count int32 `json:"Count"`
SortOrder int32 `json:"SortOrder"`
}
type WeaponAbilityEnhanceMaterialRow struct {
WeaponAbilityEnhancementMaterialId int32 `json:"WeaponAbilityEnhancementMaterialId"`
AbilityLevel int32 `json:"AbilityLevel"`
MaterialId int32 `json:"MaterialId"`
Count int32 `json:"Count"`
SortOrder int32 `json:"SortOrder"`
}
type WeaponAwakenRow struct {
WeaponId int32 `json:"WeaponId"`
WeaponAwakenEffectGroupId int32 `json:"WeaponAwakenEffectGroupId"`
WeaponAwakenMaterialGroupId int32 `json:"WeaponAwakenMaterialGroupId"`
ConsumeGold int32 `json:"ConsumeGold"`
LevelLimitUp int32 `json:"LevelLimitUp"`
}
type WeaponAwakenEffectGroupRow struct {
WeaponAwakenEffectGroupId int32 `json:"WeaponAwakenEffectGroupId"`
WeaponAwakenEffectType int32 `json:"WeaponAwakenEffectType"`
WeaponAwakenEffectId int32 `json:"WeaponAwakenEffectId"`
}
type WeaponAwakenMaterialGroupRow struct {
WeaponAwakenMaterialGroupId int32 `json:"WeaponAwakenMaterialGroupId"`
MaterialId int32 `json:"MaterialId"`
Count int32 `json:"Count"`
SortOrder int32 `json:"SortOrder"`
}
type weaponRarityEnhanceRow struct {
RarityType int32 `json:"RarityType"`
BaseEnhancementObtainedExp int32 `json:"BaseEnhancementObtainedExp"`
SellPriceNumericalFunctionId int32 `json:"SellPriceNumericalFunctionId"`
RequiredExpForLevelUpNumericalParameterMapId int32 `json:"RequiredExpForLevelUpNumericalParameterMapId"`
EnhancementCostByWeaponNumericalFunctionId int32 `json:"EnhancementCostByWeaponNumericalFunctionId"`
EnhancementCostByMaterialNumericalFunctionId int32 `json:"EnhancementCostByMaterialNumericalFunctionId"`
MaxLevelNumericalFunctionId int32 `json:"MaxLevelNumericalFunctionId"`
EvolutionCostNumericalFunctionId int32 `json:"EvolutionCostNumericalFunctionId"`
LimitBreakCostByWeaponNumericalFunctionId int32 `json:"LimitBreakCostByWeaponNumericalFunctionId"`
LimitBreakCostByMaterialNumericalFunctionId int32 `json:"LimitBreakCostByMaterialNumericalFunctionId"`
MaxSkillLevelNumericalFunctionId int32 `json:"MaxSkillLevelNumericalFunctionId"`
SkillEnhancementCostNumericalFunctionId int32 `json:"SkillEnhancementCostNumericalFunctionId"`
MaxAbilityLevelNumericalFunctionId int32 `json:"MaxAbilityLevelNumericalFunctionId"`
AbilityEnhancementCostNumericalFunctionId int32 `json:"AbilityEnhancementCostNumericalFunctionId"`
}
type WeaponCatalog struct {
Weapons map[int32]WeaponMasterRow
Materials map[int32]MaterialRow
Weapons map[int32]EntityMWeapon
Materials map[int32]EntityMMaterial
ExpByEnhanceId map[int32][]int32
GoldCostByEnhanceId map[int32]NumericalFunc
MaxLevelByEnhanceId map[int32]NumericalFunc
SellPriceByEnhanceId map[int32]NumericalFunc
MedalsByWeaponId map[int32]map[int32]int32 // WeaponId -> ConsumableItemId -> Count
EvolutionNextWeaponId map[int32]int32
EvolutionOrder map[int32]int32 // WeaponId -> 0-based position in evolution chain
EvolutionMaterials map[int32][]WeaponEvolutionMaterialRow // WeaponEvolutionMaterialGroupId -> materials
EvolutionOrder map[int32]int32 // WeaponId -> 0-based position in evolution chain
EvolutionMaterials map[int32][]EntityMWeaponEvolutionMaterialGroup // WeaponEvolutionMaterialGroupId -> materials
EvolutionCostByEnhanceId map[int32]NumericalFunc
AbilitySlots map[int32][]int32 // WeaponAbilityGroupId -> slot numbers
SkillGroupsByGroupId map[int32][]WeaponSkillGroupRow
SkillEnhanceMats map[[2]int32][]WeaponSkillEnhanceMaterialRow // key: [enhancementMaterialId, skillLevel]
SkillGroupsByGroupId map[int32][]EntityMWeaponSkillGroup
SkillEnhanceMats map[[2]int32][]EntityMWeaponSkillEnhancementMaterial // key: [enhancementMaterialId, skillLevel]
SkillMaxLevelByEnhanceId map[int32]NumericalFunc
SkillCostByEnhanceId map[int32]NumericalFunc
AbilityGroupsByGroupId map[int32][]WeaponAbilityGroupRow
AbilityEnhanceMats map[[2]int32][]WeaponAbilityEnhanceMaterialRow // key: [enhancementMaterialId, abilityLevel]
AbilityGroupsByGroupId map[int32][]EntityMWeaponAbilityGroup
AbilityEnhanceMats map[[2]int32][]EntityMWeaponAbilityEnhancementMaterial // key: [enhancementMaterialId, abilityLevel]
AbilityMaxLevelByEnhanceId map[int32]NumericalFunc
AbilityCostByEnhanceId map[int32]NumericalFunc
EnhanceCostByWeaponByEnhanceId map[int32]NumericalFunc
LimitBreakCostByWeaponByEnhanceId map[int32]NumericalFunc
LimitBreakCostByMaterialByEnhanceId map[int32]NumericalFunc
BaseExpByEnhanceId map[int32]int32
ReleaseConditionsByGroupId map[int32][]WeaponStoryReleaseConditionRow
ReleaseConditionsByGroupId map[int32][]EntityMWeaponStoryReleaseConditionGroup
AwakenByWeaponId map[int32]WeaponAwakenRow
AwakenMaterialsByGroupId map[int32][]WeaponAwakenMaterialGroupRow
AwakenByWeaponId map[int32]EntityMWeaponAwaken
AwakenMaterialsByGroupId map[int32][]EntityMWeaponAwakenMaterialGroup
}
func LoadWeaponCatalog(matCatalog *MaterialCatalog) (*WeaponCatalog, error) {
weapons, err := utils.ReadJSON[WeaponMasterRow]("EntityMWeaponTable.json")
weapons, err := utils.ReadTable[EntityMWeapon]("m_weapon")
if err != nil {
return nil, fmt.Errorf("load weapon table: %w", err)
}
enhanceRows, err := utils.ReadJSON[weaponSpecificEnhanceRow]("EntityMWeaponSpecificEnhanceTable.json")
enhanceRows, err := utils.ReadTable[EntityMWeaponSpecificEnhance]("m_weapon_specific_enhance")
if err != nil {
return nil, fmt.Errorf("load weapon specific enhance table: %w", err)
}
rarityEnhanceRows, err := utils.ReadJSON[weaponRarityEnhanceRow]("EntityMWeaponRarityTable.json")
rarityEnhanceRows, err := utils.ReadTable[EntityMWeaponRarity]("m_weapon_rarity")
if err != nil {
return nil, fmt.Errorf("load weapon rarity table: %w", err)
}
@@ -189,51 +72,51 @@ func LoadWeaponCatalog(matCatalog *MaterialCatalog) (*WeaponCatalog, error) {
return nil, fmt.Errorf("load function resolver: %w", err)
}
exchangeRows, err := utils.ReadJSON[weaponConsumeExchangeRow]("EntityMWeaponConsumeExchangeConsumableItemGroupTable.json")
exchangeRows, err := utils.ReadTable[EntityMWeaponConsumeExchangeConsumableItemGroup]("m_weapon_consume_exchange_consumable_item_group")
if err != nil {
return nil, fmt.Errorf("load weapon consume exchange table: %w", err)
}
evoGroupRows, err := utils.ReadJSON[WeaponEvolutionGroupRow]("EntityMWeaponEvolutionGroupTable.json")
evoGroupRows, err := utils.ReadTable[EntityMWeaponEvolutionGroup]("m_weapon_evolution_group")
if err != nil {
return nil, fmt.Errorf("load weapon evolution group table: %w", err)
}
evoMatRows, err := utils.ReadJSON[WeaponEvolutionMaterialRow]("EntityMWeaponEvolutionMaterialGroupTable.json")
evoMatRows, err := utils.ReadTable[EntityMWeaponEvolutionMaterialGroup]("m_weapon_evolution_material_group")
if err != nil {
return nil, fmt.Errorf("load weapon evolution material group table: %w", err)
}
abilityGroupRows, err := utils.ReadJSON[WeaponAbilityGroupRow]("EntityMWeaponAbilityGroupTable.json")
abilityGroupRows, err := utils.ReadTable[EntityMWeaponAbilityGroup]("m_weapon_ability_group")
if err != nil {
return nil, fmt.Errorf("load weapon ability group table: %w", err)
}
skillGroupRows, err := utils.ReadJSON[WeaponSkillGroupRow]("EntityMWeaponSkillGroupTable.json")
skillGroupRows, err := utils.ReadTable[EntityMWeaponSkillGroup]("m_weapon_skill_group")
if err != nil {
return nil, fmt.Errorf("load weapon skill group table: %w", err)
}
skillMatRows, err := utils.ReadJSON[WeaponSkillEnhanceMaterialRow]("EntityMWeaponSkillEnhancementMaterialTable.json")
skillMatRows, err := utils.ReadTable[EntityMWeaponSkillEnhancementMaterial]("m_weapon_skill_enhancement_material")
if err != nil {
return nil, fmt.Errorf("load weapon skill enhancement material table: %w", err)
}
abilityMatRows, err := utils.ReadJSON[WeaponAbilityEnhanceMaterialRow]("EntityMWeaponAbilityEnhancementMaterialTable.json")
abilityMatRows, err := utils.ReadTable[EntityMWeaponAbilityEnhancementMaterial]("m_weapon_ability_enhancement_material")
if err != nil {
return nil, fmt.Errorf("load weapon ability enhancement material table: %w", err)
}
releaseConditions, err := utils.ReadJSON[WeaponStoryReleaseConditionRow]("EntityMWeaponStoryReleaseConditionGroupTable.json")
releaseConditions, err := utils.ReadTable[EntityMWeaponStoryReleaseConditionGroup]("m_weapon_story_release_condition_group")
if err != nil {
return nil, fmt.Errorf("load weapon story release condition table: %w", err)
}
awakenRows, err := utils.ReadJSON[WeaponAwakenRow]("EntityMWeaponAwakenTable.json")
awakenRows, err := utils.ReadTable[EntityMWeaponAwaken]("m_weapon_awaken")
if err != nil {
return nil, fmt.Errorf("load weapon awaken table: %w", err)
}
awakenMatRows, err := utils.ReadJSON[WeaponAwakenMaterialGroupRow]("EntityMWeaponAwakenMaterialGroupTable.json")
awakenMatRows, err := utils.ReadTable[EntityMWeaponAwakenMaterialGroup]("m_weapon_awaken_material_group")
if err != nil {
return nil, fmt.Errorf("load weapon awaken material group table: %w", err)
}
catalog := &WeaponCatalog{
Weapons: make(map[int32]WeaponMasterRow, len(weapons)),
Weapons: make(map[int32]EntityMWeapon, len(weapons)),
Materials: matCatalog.ByType[model.MaterialTypeWeaponEnhancement],
ExpByEnhanceId: make(map[int32][]int32, len(enhanceRows)),
GoldCostByEnhanceId: make(map[int32]NumericalFunc, len(enhanceRows)),
@@ -242,25 +125,25 @@ func LoadWeaponCatalog(matCatalog *MaterialCatalog) (*WeaponCatalog, error) {
MedalsByWeaponId: make(map[int32]map[int32]int32),
EvolutionNextWeaponId: make(map[int32]int32),
EvolutionOrder: make(map[int32]int32),
EvolutionMaterials: make(map[int32][]WeaponEvolutionMaterialRow),
EvolutionMaterials: make(map[int32][]EntityMWeaponEvolutionMaterialGroup),
EvolutionCostByEnhanceId: make(map[int32]NumericalFunc, len(enhanceRows)),
AbilitySlots: make(map[int32][]int32),
SkillGroupsByGroupId: make(map[int32][]WeaponSkillGroupRow),
SkillEnhanceMats: make(map[[2]int32][]WeaponSkillEnhanceMaterialRow),
SkillGroupsByGroupId: make(map[int32][]EntityMWeaponSkillGroup),
SkillEnhanceMats: make(map[[2]int32][]EntityMWeaponSkillEnhancementMaterial),
SkillMaxLevelByEnhanceId: make(map[int32]NumericalFunc, len(enhanceRows)),
SkillCostByEnhanceId: make(map[int32]NumericalFunc, len(enhanceRows)),
AbilityGroupsByGroupId: make(map[int32][]WeaponAbilityGroupRow),
AbilityEnhanceMats: make(map[[2]int32][]WeaponAbilityEnhanceMaterialRow),
AbilityGroupsByGroupId: make(map[int32][]EntityMWeaponAbilityGroup),
AbilityEnhanceMats: make(map[[2]int32][]EntityMWeaponAbilityEnhancementMaterial),
AbilityMaxLevelByEnhanceId: make(map[int32]NumericalFunc, len(enhanceRows)),
AbilityCostByEnhanceId: make(map[int32]NumericalFunc, len(enhanceRows)),
EnhanceCostByWeaponByEnhanceId: make(map[int32]NumericalFunc, len(enhanceRows)),
LimitBreakCostByWeaponByEnhanceId: make(map[int32]NumericalFunc, len(enhanceRows)),
LimitBreakCostByMaterialByEnhanceId: make(map[int32]NumericalFunc, len(enhanceRows)),
BaseExpByEnhanceId: make(map[int32]int32, len(enhanceRows)),
ReleaseConditionsByGroupId: make(map[int32][]WeaponStoryReleaseConditionRow),
ReleaseConditionsByGroupId: make(map[int32][]EntityMWeaponStoryReleaseConditionGroup),
AwakenByWeaponId: make(map[int32]WeaponAwakenRow, len(awakenRows)),
AwakenMaterialsByGroupId: make(map[int32][]WeaponAwakenMaterialGroupRow),
AwakenByWeaponId: make(map[int32]EntityMWeaponAwaken, len(awakenRows)),
AwakenMaterialsByGroupId: make(map[int32][]EntityMWeaponAwakenMaterialGroup),
}
for _, w := range weapons {
@@ -338,7 +221,7 @@ func LoadWeaponCatalog(matCatalog *MaterialCatalog) (*WeaponCatalog, error) {
catalog.MedalsByWeaponId[ex.WeaponId][ex.ConsumableItemId] = ex.Count
}
grouped := make(map[int32][]WeaponEvolutionGroupRow)
grouped := make(map[int32][]EntityMWeaponEvolutionGroup)
for _, row := range evoGroupRows {
grouped[row.WeaponEvolutionGroupId] = append(grouped[row.WeaponEvolutionGroupId], row)
}
@@ -399,7 +282,7 @@ func LoadWeaponCatalog(matCatalog *MaterialCatalog) (*WeaponCatalog, error) {
// Rarity-based enhancement fallback: for weapons with WeaponSpecificEnhanceId == 0,
// use EntityMWeaponRarityTable curves via synthetic enhance IDs (-RarityType).
rarityByType := make(map[int32]weaponRarityEnhanceRow, len(rarityEnhanceRows))
rarityByType := make(map[int32]EntityMWeaponRarity, len(rarityEnhanceRows))
for _, r := range rarityEnhanceRows {
rarityByType[r.RarityType] = r
}