DNF90 服务端与启动器完整源码(含 GM 工具功能增强)
服务端(Go): - GM 塞背包/带属性装备发放:在线角色推送 op14 增量物品行,背包实时刷新,无需回角色选择界面 - GM 改金币/改等级:去掉在线拒绝,落库后推送 op14 钱包/op37 等级状态,在线实时刷新 - 等级端点统一切换到新版 GMSetCharacterLevel(自带在线刷新) - 无限/锁死疲劳模式 + 燃烧疲劳:每房间消耗 2 点、打怪与通关经验双倍 - 燃烧疲劳开关时给所有在线角色推送系统提示(op12 mode 0) - 深渊史诗掉率:GM 全局倍率 + 城镇增益药剂窗口倍率,真实接入掉落结算 启动器(Python/JS): - 标题栏自绘、窗口 1204x717、禁止拖拽改大小、仅最小化/关闭 - GM 工具:疲劳与燃烧、深渊史诗掉率、拍卖行上架(单一定价对齐) - 拍卖行上架前端对齐服务端单一价格语义,修复 400 报错
This commit is contained in:
commit
645b64fe21
4388 files changed
+1405457
No files matched your search
@@ -0,0 +1,156 @@
|
||||
package logic
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"longheng.io/server/internal/modules/samples/world"
|
||||
appkit "longheng.io/server/internal/platform/app"
|
||||
"longheng.io/server/internal/platform/dispatch"
|
||||
"longheng.io/server/internal/platform/integrity"
|
||||
modulemgr "longheng.io/server/internal/platform/module"
|
||||
"longheng.io/server/internal/platform/notification"
|
||||
"longheng.io/server/internal/platform/readmodel"
|
||||
"longheng.io/server/internal/platform/runtimeguard"
|
||||
"longheng.io/server/internal/platform/scripthost"
|
||||
"longheng.io/server/internal/platform/secrets"
|
||||
"longheng.io/server/internal/reference/player"
|
||||
"longheng.io/server/internal/runtime/leaderboard"
|
||||
"longheng.io/server/internal/runtime/moderation"
|
||||
"longheng.io/server/internal/runtime/notice"
|
||||
"longheng.io/server/internal/runtime/redeem"
|
||||
logichandlers "longheng.io/server/internal/services/logic/handlers"
|
||||
)
|
||||
|
||||
// ErrManifestMemStore 表示默认 manifest 在分布式环境仍使用单节点内存后端。
|
||||
var ErrManifestMemStore = errors.New("logic default manifest uses single-node runtime backend")
|
||||
|
||||
// GameManifestProvider 根据框架环境构建游戏 manifest。
|
||||
type GameManifestProvider func(*appkit.Env) (GameManifest, error)
|
||||
|
||||
// ExtensionPoints 是项目侧接入平台扩展包的 wiring 表面。
|
||||
// 它刻意放在 GameManifest 中,让项目能挂接具体 provider,
|
||||
// 同时避免 platform 包反向 import services 或游戏专属 runtime 代码。
|
||||
type ExtensionPoints struct {
|
||||
ScriptHost scripthost.Host
|
||||
ScriptRuntime scripthost.Runtime
|
||||
Secrets secrets.Provider
|
||||
Push notification.PushProvider
|
||||
Mail notification.MailProvider
|
||||
Integrity integrity.ActionValidator
|
||||
ReplayDigest integrity.ReplayDigestProvider
|
||||
RiskScoreProvider integrity.RiskScoreProvider
|
||||
}
|
||||
|
||||
// GameManifest 描述 logic/playerd 要装配的模块、运行时和 handler。
|
||||
type GameManifest struct {
|
||||
Modules []modulemgr.Module
|
||||
Players *player.Module
|
||||
World *world.Module
|
||||
Accounts *AccountManager
|
||||
Leaderboards leaderboard.Runtime
|
||||
Sanctions moderation.SanctionStore
|
||||
Notices notice.Service
|
||||
Redeems redeem.Service
|
||||
AdminRoutes []AdminRouteRegistrar
|
||||
RegisterHandlers func(*dispatch.Mux) error
|
||||
RegisterReadModels func(*readmodel.AdminRegistry)
|
||||
Extensions ExtensionPoints
|
||||
}
|
||||
|
||||
// BlankManifest 返回不装配业务模块的 GameManifest。
|
||||
// 新项目应以它为起点,通过 Modules / Players / RegisterHandlers 注册自己的
|
||||
// player、world 和 runtime 类型。
|
||||
func BlankManifest(_ *appkit.Env) (GameManifest, error) {
|
||||
return GameManifest{}, nil
|
||||
}
|
||||
|
||||
// DemoGameManifest 装配内置示例模块用于本地演示。
|
||||
// 即使本地配置为了 route metadata smoke 保持 topology 开启,示例 runtime 也按单节点处理。
|
||||
func DemoGameManifest(env *appkit.Env) (GameManifest, error) {
|
||||
if env == nil {
|
||||
env = &appkit.Env{}
|
||||
}
|
||||
demoEnv := *env
|
||||
demoEnv.Config.Topology.Enabled = false
|
||||
return DefaultGameManifest(&demoEnv)
|
||||
}
|
||||
|
||||
// DefaultPlayerDManifest 是 playerd 的参考 manifest。
|
||||
// 它只装配示例 Player/Profile 模块,不继承仅属于 logic 的 world、leaderboard、notice 或 redeem 示例 runtime。
|
||||
func DefaultPlayerDManifest(env *appkit.Env) (GameManifest, error) {
|
||||
profileStore, summaryStore := newPlayerStores(env.Config.ProfileStore, env)
|
||||
playerModule, err := player.NewWithStoresChecked(env.Logger, profileStore, summaryStore)
|
||||
if err != nil {
|
||||
return GameManifest{}, err
|
||||
}
|
||||
if env.EventLog != nil {
|
||||
playerModule.UseEventLog(env.EventLog, env.Config.EventLog.Strict)
|
||||
}
|
||||
return GameManifest{
|
||||
Modules: []modulemgr.Module{
|
||||
playerModule,
|
||||
},
|
||||
Players: playerModule,
|
||||
RegisterHandlers: func(mux *dispatch.Mux) error {
|
||||
return logichandlers.RegisterAll(mux, logichandlers.Default(logichandlers.Context{Players: playerModule})...)
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DefaultGameManifest 创建内置演示用 logic manifest。
|
||||
func DefaultGameManifest(env *appkit.Env) (GameManifest, error) {
|
||||
profileStore, summaryStore := newPlayerStores(env.Config.ProfileStore, env)
|
||||
playerModule, err := player.NewWithStoresChecked(env.Logger, profileStore, summaryStore)
|
||||
if err != nil {
|
||||
return GameManifest{}, err
|
||||
}
|
||||
if env.EventLog != nil {
|
||||
playerModule.UseEventLog(env.EventLog, env.Config.EventLog.Strict)
|
||||
}
|
||||
worldModule := world.New(env.Logger)
|
||||
leaderboards := leaderboard.New(leaderboard.Options{Name: env.Config.Service.Name + "-leaderboards"})
|
||||
sanctions := moderation.NewMemorySanctionStore()
|
||||
profile := runtimeguard.ProfileFromEnvironment(env.Config.Service.Environment, env.Config.Topology.Enabled)
|
||||
notices := notice.Service{
|
||||
Store: notice.NewMemoryStore(),
|
||||
EventLog: env.EventLog,
|
||||
}
|
||||
if env.Bus != nil {
|
||||
publishers := []notice.LivePublisher{notice.NewBusPublisher(env.Bus)}
|
||||
if env.OnlinePush != nil {
|
||||
publishers = append(publishers, notice.NewOnlinePushPublisher(env.OnlinePush))
|
||||
} else {
|
||||
publishers = append(publishers, notice.NewGatewayPushPublisher(env.Bus))
|
||||
}
|
||||
notices.Publisher = notice.NewAsyncLivePublisher(notice.NewFanoutPublisher(publishers...))
|
||||
}
|
||||
redeems := redeem.Service{
|
||||
Store: redeem.NewMemoryStore(),
|
||||
EventLog: env.EventLog,
|
||||
}
|
||||
manifest := GameManifest{
|
||||
Modules: []modulemgr.Module{
|
||||
playerModule,
|
||||
worldModule,
|
||||
},
|
||||
Players: playerModule,
|
||||
World: worldModule,
|
||||
Leaderboards: leaderboards,
|
||||
Sanctions: sanctions,
|
||||
Notices: notices,
|
||||
Redeems: redeems,
|
||||
AdminRoutes: []AdminRouteRegistrar{
|
||||
NoticeAdminRouteRegistrar(notices),
|
||||
RedeemAdminRouteRegistrar(redeems),
|
||||
},
|
||||
RegisterHandlers: func(mux *dispatch.Mux) error {
|
||||
return logichandlers.RegisterAll(mux, logichandlers.Default(logichandlers.Context{Players: playerModule})...)
|
||||
},
|
||||
}
|
||||
if profile.Distributed {
|
||||
return manifest, fmt.Errorf("%w: notice and redeem default stores are memory-only; provide a project manifest with durable stores",
|
||||
ErrManifestMemStore)
|
||||
}
|
||||
return manifest, nil
|
||||
}
|
||||
Reference in new issue
Block a user