mirror of
https://github.com/Walter-Sparrow/lunar-tear.git
synced 2026-07-02 05:43:41 +03:00
Implement world-map entities
Build and Push Docker images to Docker Hub / build-and-push (push) Has been cancelled
Build and Push Docker images to Docker Hub / build-and-push (push) Has been cancelled
This commit is contained in:
@@ -287,10 +287,12 @@ func ChangedTables(before, after *store.UserState) []string {
|
||||
}
|
||||
|
||||
if !gimmickStateEqual(before.Gimmick, after.Gimmick) {
|
||||
if !mapsEqualStruct(before.Gimmick.Progress, after.Gimmick.Progress) {
|
||||
if !mapsEqualStruct(before.Gimmick.Progress, after.Gimmick.Progress) ||
|
||||
!mapsEqualStruct(before.Gimmick.Sequences, after.Gimmick.Sequences) {
|
||||
add("IUserGimmick")
|
||||
}
|
||||
if !mapsEqualStruct(before.Gimmick.OrnamentProgress, after.Gimmick.OrnamentProgress) {
|
||||
if !mapsEqualStruct(before.Gimmick.OrnamentProgress, after.Gimmick.OrnamentProgress) ||
|
||||
!mapsEqualStruct(before.Gimmick.Sequences, after.Gimmick.Sequences) {
|
||||
add("IUserGimmickOrnamentProgress")
|
||||
}
|
||||
if !mapsEqualStruct(before.Gimmick.Sequences, after.Gimmick.Sequences) {
|
||||
|
||||
@@ -2,11 +2,21 @@ package userdata
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
"lunar-tear/server/internal/masterdata"
|
||||
"lunar-tear/server/internal/store"
|
||||
"lunar-tear/server/internal/utils"
|
||||
)
|
||||
|
||||
var gimmickOrnamentRefs = sync.OnceValue(masterdata.LoadGimmickOrnamentRefs)
|
||||
var gimmickSequenceChains = sync.OnceValue(masterdata.LoadGimmickSequenceChains)
|
||||
var hiddenSequenceSet = sync.OnceValue(masterdata.LoadHiddenGimmickSequenceIDs)
|
||||
var gimmickSequenceRanks = sync.OnceValue(masterdata.LoadGimmickSequenceRanks)
|
||||
var birdGimmicks = sync.OnceValue(masterdata.LoadBirdGimmickIDs)
|
||||
|
||||
const birdDefaultBaseDatetime int64 = 1577836800000 // 2020-01-01 00:00:00 UTC in ms
|
||||
|
||||
func init() {
|
||||
register("IUserGimmick", func(user store.UserState) string {
|
||||
s, _ := utils.EncodeJSONMaps(sortedGimmickRecords(user)...)
|
||||
@@ -26,9 +36,65 @@ func init() {
|
||||
})
|
||||
}
|
||||
|
||||
func projectActiveChainOrnaments(
|
||||
user store.UserState,
|
||||
addKey func(seqKey store.GimmickSequenceKey, seqId int32, ref masterdata.GimmickOrnamentRef),
|
||||
sizeFn func() int,
|
||||
cap int,
|
||||
) {
|
||||
refs := gimmickOrnamentRefs()
|
||||
chains := gimmickSequenceChains()
|
||||
hiddenSeq := hiddenSequenceSet()
|
||||
|
||||
walkChain := func(seqKey store.GimmickSequenceKey) {
|
||||
chain := chains[seqKey.GimmickSequenceId]
|
||||
if len(chain) == 0 {
|
||||
chain = []int32{seqKey.GimmickSequenceId}
|
||||
}
|
||||
for _, seqId := range chain {
|
||||
for _, ref := range refs[seqId] {
|
||||
addKey(seqKey, seqId, ref)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var nonHidden []store.GimmickSequenceKey
|
||||
for seqKey := range user.Gimmick.Sequences {
|
||||
if hiddenSeq[seqKey.GimmickSequenceId] {
|
||||
walkChain(seqKey)
|
||||
} else {
|
||||
nonHidden = append(nonHidden, seqKey)
|
||||
}
|
||||
}
|
||||
for _, seqKey := range nonHidden {
|
||||
if sizeFn() >= cap {
|
||||
break
|
||||
}
|
||||
walkChain(seqKey)
|
||||
}
|
||||
}
|
||||
|
||||
func sortedGimmickRecords(user store.UserState) []map[string]any {
|
||||
keys := make([]store.GimmickKey, 0, len(user.Gimmick.Progress))
|
||||
|
||||
keySet := make(map[store.GimmickKey]struct{})
|
||||
// Real progress rows (genuine user data) — always kept.
|
||||
for key := range user.Gimmick.Progress {
|
||||
keySet[key] = struct{}{}
|
||||
}
|
||||
projectActiveChainOrnaments(user,
|
||||
func(seqKey store.GimmickSequenceKey, seqId int32, ref masterdata.GimmickOrnamentRef) {
|
||||
keySet[store.GimmickKey{
|
||||
GimmickSequenceScheduleId: seqKey.GimmickSequenceScheduleId,
|
||||
GimmickSequenceId: seqId,
|
||||
GimmickId: ref.GimmickId,
|
||||
}] = struct{}{}
|
||||
},
|
||||
func() int { return len(keySet) },
|
||||
masterdata.MaxUserGimmickRows,
|
||||
)
|
||||
|
||||
keys := make([]store.GimmickKey, 0, len(keySet))
|
||||
for key := range keySet {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Slice(keys, func(i, j int) bool {
|
||||
@@ -37,57 +103,103 @@ func sortedGimmickRecords(user store.UserState) []map[string]any {
|
||||
|
||||
records := make([]map[string]any, 0, len(keys))
|
||||
for _, key := range keys {
|
||||
row := user.Gimmick.Progress[key]
|
||||
isGimmickCleared := false
|
||||
startDatetime := user.GameStartDatetime
|
||||
latestVersion := user.GameStartDatetime
|
||||
if row, ok := user.Gimmick.Progress[key]; ok {
|
||||
isGimmickCleared = row.IsGimmickCleared
|
||||
startDatetime = row.StartDatetime
|
||||
latestVersion = row.LatestVersion
|
||||
}
|
||||
records = append(records, map[string]any{
|
||||
"userId": user.UserId,
|
||||
"gimmickSequenceScheduleId": row.Key.GimmickSequenceScheduleId,
|
||||
"gimmickSequenceId": row.Key.GimmickSequenceId,
|
||||
"gimmickId": row.Key.GimmickId,
|
||||
"isGimmickCleared": row.IsGimmickCleared,
|
||||
"startDatetime": row.StartDatetime,
|
||||
"latestVersion": row.LatestVersion,
|
||||
"gimmickSequenceScheduleId": key.GimmickSequenceScheduleId,
|
||||
"gimmickSequenceId": key.GimmickSequenceId,
|
||||
"gimmickId": key.GimmickId,
|
||||
"isGimmickCleared": isGimmickCleared,
|
||||
"startDatetime": startDatetime,
|
||||
"latestVersion": latestVersion,
|
||||
})
|
||||
}
|
||||
return records
|
||||
}
|
||||
|
||||
func sortedGimmickOrnamentProgressRecords(user store.UserState) []map[string]any {
|
||||
keys := make([]store.GimmickOrnamentKey, 0, len(user.Gimmick.OrnamentProgress))
|
||||
|
||||
keySet := make(map[store.GimmickOrnamentKey]struct{})
|
||||
// Real progress rows (genuine user data) — always kept.
|
||||
for key := range user.Gimmick.OrnamentProgress {
|
||||
keySet[key] = struct{}{}
|
||||
}
|
||||
projectActiveChainOrnaments(user,
|
||||
func(seqKey store.GimmickSequenceKey, seqId int32, ref masterdata.GimmickOrnamentRef) {
|
||||
keySet[store.GimmickOrnamentKey{
|
||||
GimmickSequenceScheduleId: seqKey.GimmickSequenceScheduleId,
|
||||
GimmickSequenceId: seqId,
|
||||
GimmickId: ref.GimmickId,
|
||||
GimmickOrnamentIndex: ref.OrnamentIndex,
|
||||
}] = struct{}{}
|
||||
},
|
||||
func() int { return len(keySet) },
|
||||
masterdata.MaxUserGimmickRows,
|
||||
)
|
||||
|
||||
keys := make([]store.GimmickOrnamentKey, 0, len(keySet))
|
||||
for key := range keySet {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Slice(keys, func(i, j int) bool {
|
||||
return compareGimmickOrnamentKey(keys[i], keys[j]) < 0
|
||||
})
|
||||
|
||||
birdG := birdGimmicks()
|
||||
records := make([]map[string]any, 0, len(keys))
|
||||
for _, key := range keys {
|
||||
row := user.Gimmick.OrnamentProgress[key]
|
||||
progressValueBit := int32(0)
|
||||
baseDatetime := user.GameStartDatetime
|
||||
latestVersion := user.GameStartDatetime
|
||||
if row, ok := user.Gimmick.OrnamentProgress[key]; ok {
|
||||
progressValueBit = row.ProgressValueBit
|
||||
baseDatetime = row.BaseDatetime
|
||||
latestVersion = row.LatestVersion
|
||||
} else if birdG[key.GimmickId] {
|
||||
baseDatetime = birdDefaultBaseDatetime
|
||||
}
|
||||
records = append(records, map[string]any{
|
||||
"userId": user.UserId,
|
||||
"gimmickSequenceScheduleId": row.Key.GimmickSequenceScheduleId,
|
||||
"gimmickSequenceId": row.Key.GimmickSequenceId,
|
||||
"gimmickId": row.Key.GimmickId,
|
||||
"gimmickOrnamentIndex": row.Key.GimmickOrnamentIndex,
|
||||
"progressValueBit": row.ProgressValueBit,
|
||||
"baseDatetime": row.BaseDatetime,
|
||||
"latestVersion": row.LatestVersion,
|
||||
"gimmickSequenceScheduleId": key.GimmickSequenceScheduleId,
|
||||
"gimmickSequenceId": key.GimmickSequenceId,
|
||||
"gimmickId": key.GimmickId,
|
||||
"gimmickOrnamentIndex": key.GimmickOrnamentIndex,
|
||||
"progressValueBit": progressValueBit,
|
||||
"baseDatetime": baseDatetime,
|
||||
"latestVersion": latestVersion,
|
||||
})
|
||||
}
|
||||
return records
|
||||
}
|
||||
|
||||
func sortedGimmickSequenceRecords(user store.UserState) []map[string]any {
|
||||
|
||||
ranks := gimmickSequenceRanks()
|
||||
|
||||
keys := make([]store.GimmickSequenceKey, 0, len(user.Gimmick.Sequences))
|
||||
for key := range user.Gimmick.Sequences {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Slice(keys, func(i, j int) bool {
|
||||
ri, rj := ranks[keys[i].GimmickSequenceId], ranks[keys[j].GimmickSequenceId]
|
||||
if ri != rj {
|
||||
return ri < rj
|
||||
}
|
||||
if keys[i].GimmickSequenceScheduleId != keys[j].GimmickSequenceScheduleId {
|
||||
return keys[i].GimmickSequenceScheduleId < keys[j].GimmickSequenceScheduleId
|
||||
}
|
||||
return keys[i].GimmickSequenceId < keys[j].GimmickSequenceId
|
||||
})
|
||||
if len(keys) > masterdata.MaxUserGimmickRows {
|
||||
keys = keys[:masterdata.MaxUserGimmickRows]
|
||||
}
|
||||
|
||||
records := make([]map[string]any, 0, len(keys))
|
||||
for _, key := range keys {
|
||||
|
||||
@@ -33,8 +33,26 @@ func sortedQuestRecords(user store.UserState) []map[string]any {
|
||||
}
|
||||
|
||||
func sortedQuestMissionRecords(user store.UserState) []map[string]any {
|
||||
keys := make([]store.QuestMissionKey, 0, len(user.QuestMissions))
|
||||
for key := range user.QuestMissions {
|
||||
questMissions := make(map[store.QuestMissionKey]store.UserQuestMissionState, len(user.QuestMissions))
|
||||
for key, qm := range user.QuestMissions {
|
||||
questMissions[key] = qm
|
||||
}
|
||||
// Force-clear hidden-story quest-missions so their report gimmicks unlock.
|
||||
for _, key := range hiddenStoryRequirements().QuestMissions {
|
||||
if existing, ok := questMissions[key]; ok && existing.IsClear {
|
||||
continue
|
||||
}
|
||||
questMissions[key] = store.UserQuestMissionState{
|
||||
QuestId: key.QuestId,
|
||||
QuestMissionId: key.QuestMissionId,
|
||||
IsClear: true,
|
||||
LatestClearDatetime: user.GameStartDatetime,
|
||||
LatestVersion: user.GameStartDatetime,
|
||||
}
|
||||
}
|
||||
|
||||
keys := make([]store.QuestMissionKey, 0, len(questMissions))
|
||||
for key := range questMissions {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Slice(keys, func(i, j int) bool {
|
||||
@@ -45,7 +63,7 @@ func sortedQuestMissionRecords(user store.UserState) []map[string]any {
|
||||
})
|
||||
records := make([]map[string]any, 0, len(keys))
|
||||
for _, key := range keys {
|
||||
row := user.QuestMissions[key]
|
||||
row := questMissions[key]
|
||||
records = append(records, map[string]any{
|
||||
"userId": user.UserId,
|
||||
"questId": row.QuestId,
|
||||
|
||||
@@ -2,8 +2,11 @@ package userdata
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
"lunar-tear/server/internal/gametime"
|
||||
"lunar-tear/server/internal/masterdata"
|
||||
"lunar-tear/server/internal/model"
|
||||
"lunar-tear/server/internal/store"
|
||||
"lunar-tear/server/internal/utils"
|
||||
)
|
||||
@@ -192,16 +195,35 @@ func sortedTutorialRecords(user store.UserState) []map[string]any {
|
||||
return records
|
||||
}
|
||||
|
||||
var hiddenStoryRequirements = sync.OnceValue(masterdata.LoadHiddenStoryRequirements)
|
||||
|
||||
func sortedMissionRecords(user store.UserState) []map[string]any {
|
||||
ids := make([]int, 0, len(user.Missions))
|
||||
for id := range user.Missions {
|
||||
missions := make(map[int32]store.UserMissionState, len(user.Missions))
|
||||
for id, m := range user.Missions {
|
||||
missions[id] = m
|
||||
}
|
||||
for _, missionId := range hiddenStoryRequirements().MissionIds {
|
||||
if existing, ok := missions[missionId]; ok && existing.MissionProgressStatusType >= int32(model.MissionProgressStatusTypeClear) {
|
||||
continue
|
||||
}
|
||||
missions[missionId] = store.UserMissionState{
|
||||
MissionId: missionId,
|
||||
StartDatetime: user.GameStartDatetime,
|
||||
MissionProgressStatusType: int32(model.MissionProgressStatusTypeClear),
|
||||
ClearDatetime: user.GameStartDatetime,
|
||||
LatestVersion: user.GameStartDatetime,
|
||||
}
|
||||
}
|
||||
|
||||
ids := make([]int, 0, len(missions))
|
||||
for id := range missions {
|
||||
ids = append(ids, int(id))
|
||||
}
|
||||
sort.Ints(ids)
|
||||
|
||||
records := make([]map[string]any, 0, len(ids))
|
||||
for _, id := range ids {
|
||||
row := user.Missions[int32(id)]
|
||||
row := missions[int32(id)]
|
||||
records = append(records, map[string]any{
|
||||
"userId": user.UserId,
|
||||
"missionId": row.MissionId,
|
||||
|
||||
Reference in New Issue
Block a user