服务端(Go): - GM 塞背包/带属性装备发放:在线角色推送 op14 增量物品行,背包实时刷新,无需回角色选择界面 - GM 改金币/改等级:去掉在线拒绝,落库后推送 op14 钱包/op37 等级状态,在线实时刷新 - 等级端点统一切换到新版 GMSetCharacterLevel(自带在线刷新) - 无限/锁死疲劳模式 + 燃烧疲劳:每房间消耗 2 点、打怪与通关经验双倍 - 燃烧疲劳开关时给所有在线角色推送系统提示(op12 mode 0) - 深渊史诗掉率:GM 全局倍率 + 城镇增益药剂窗口倍率,真实接入掉落结算 启动器(Python/JS): - 标题栏自绘、窗口 1204x717、禁止拖拽改大小、仅最小化/关闭 - GM 工具:疲劳与燃烧、深渊史诗掉率、拍卖行上架(单一定价对齐) - 拍卖行上架前端对齐服务端单一价格语义,修复 400 报错
101 lines
3.1 KiB
Go
101 lines
3.1 KiB
Go
package pvf
|
|
|
|
import "time"
|
|
|
|
// StringTableIndexStats counts actual lazy builds, not cached lookups.
|
|
// Durations and payload counts are cumulative for this archive instance.
|
|
type StringTableIndexStats struct {
|
|
Revision uint64 `json:"revision"`
|
|
State string `json:"state"`
|
|
ActiveBuilds int `json:"activeBuilds"`
|
|
MappingBuilds int `json:"mappingBuilds"`
|
|
MappingCount int `json:"mappingCount"`
|
|
TableBuilds int `json:"tableBuilds"`
|
|
FailedTables int `json:"failedTables"`
|
|
Entries int `json:"entries"`
|
|
Bytes int64 `json:"bytes"`
|
|
MappingDurationMs float64 `json:"mappingDurationMs"`
|
|
TableDurationMs float64 `json:"tableDurationMs"`
|
|
BuildDurationMs float64 `json:"buildDurationMs"`
|
|
}
|
|
|
|
// StringTableIndexEvent reports one mapping or UTF-16 payload index build.
|
|
type StringTableIndexEvent struct {
|
|
ArchivePath string `json:"archivePath"`
|
|
Kind string `json:"kind"`
|
|
Path string `json:"path"`
|
|
State string `json:"state"`
|
|
DurationMs float64 `json:"durationMs"`
|
|
Entries int `json:"entries"`
|
|
Bytes int64 `json:"bytes"`
|
|
Error string `json:"error"`
|
|
Stats StringTableIndexStats `json:"stats"`
|
|
}
|
|
|
|
func (a *Archive) SetStringTableIndexObserver(observer func(StringTableIndexEvent)) {
|
|
a.tables.mu.Lock()
|
|
a.tables.observer = observer
|
|
event := StringTableIndexEvent{
|
|
ArchivePath: a.sourcePath, Kind: "snapshot", Stats: a.stringTableIndexStatsLocked(),
|
|
}
|
|
event.State = event.Stats.State
|
|
a.tables.mu.Unlock()
|
|
if observer != nil {
|
|
observer(event)
|
|
}
|
|
}
|
|
|
|
func (a *Archive) StringTableIndexStats() StringTableIndexStats {
|
|
a.tables.mu.Lock()
|
|
defer a.tables.mu.Unlock()
|
|
return a.stringTableIndexStatsLocked()
|
|
}
|
|
|
|
func (a *Archive) stringTableIndexStatsLocked() StringTableIndexStats {
|
|
stats := a.tables.stats
|
|
stats.State = "idle"
|
|
if stats.ActiveBuilds > 0 {
|
|
stats.State = "building"
|
|
} else if stats.MappingBuilds > 0 || stats.TableBuilds > 0 {
|
|
stats.State = "ready"
|
|
}
|
|
return stats
|
|
}
|
|
|
|
func (a *Archive) reportStringTableIndex(event StringTableIndexEvent) {
|
|
a.tables.mu.Lock()
|
|
stats := &a.tables.stats
|
|
stats.Revision++
|
|
if event.State == "building" {
|
|
stats.ActiveBuilds++
|
|
} else {
|
|
stats.ActiveBuilds--
|
|
if event.Kind == "mapping" {
|
|
stats.MappingBuilds++
|
|
stats.MappingCount = event.Entries
|
|
stats.MappingDurationMs += event.DurationMs
|
|
} else {
|
|
stats.TableBuilds++
|
|
stats.TableDurationMs += event.DurationMs
|
|
stats.Entries += event.Entries
|
|
stats.Bytes += event.Bytes
|
|
if event.State == "error" {
|
|
stats.FailedTables++
|
|
}
|
|
}
|
|
stats.BuildDurationMs = stats.MappingDurationMs + stats.TableDurationMs
|
|
}
|
|
event.ArchivePath = a.sourcePath
|
|
event.Stats = a.stringTableIndexStatsLocked()
|
|
observer := a.tables.observer
|
|
a.tables.mu.Unlock()
|
|
// Observers may inspect the snapshot; never invoke them under tables.mu.
|
|
if observer != nil {
|
|
observer(event)
|
|
}
|
|
}
|
|
|
|
func stringTableElapsedMs(started time.Time) float64 {
|
|
return float64(time.Since(started)) / float64(time.Millisecond)
|
|
}
|