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,178 @@
|
||||
package dnfrobot
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
BatchActionStart = "start"
|
||||
BatchActionStop = "stop"
|
||||
BatchActionMove = "move"
|
||||
BatchActionChat = "chat"
|
||||
BatchActionStoreOpen = "store_open"
|
||||
BatchActionStoreClose = "store_close"
|
||||
)
|
||||
|
||||
type BatchRequest struct {
|
||||
Action string `json:"action"`
|
||||
IDs []string `json:"ids,omitempty"`
|
||||
Village uint8 `json:"village,omitempty"`
|
||||
Area uint8 `json:"area,omitempty"`
|
||||
X uint16 `json:"x,omitempty"`
|
||||
Y uint16 `json:"y,omitempty"`
|
||||
MoveType uint8 `json:"move_type,omitempty"`
|
||||
ChatMode uint8 `json:"chat_mode,omitempty"`
|
||||
Message string `json:"message,omitempty"`
|
||||
StoreTitle string `json:"store_title,omitempty"`
|
||||
StoreRows int `json:"store_rows,omitempty"`
|
||||
StorePrice uint32 `json:"store_price,omitempty"`
|
||||
}
|
||||
|
||||
type BatchActionResult struct {
|
||||
ID string `json:"id"`
|
||||
OK bool `json:"ok"`
|
||||
Error string `json:"error,omitempty"`
|
||||
Snapshot RuntimeSnapshot `json:"snapshot"`
|
||||
}
|
||||
|
||||
type BatchResult struct {
|
||||
Action string `json:"action"`
|
||||
Requested int `json:"requested"`
|
||||
Succeeded int `json:"succeeded"`
|
||||
Failed int `json:"failed"`
|
||||
Results []BatchActionResult `json:"results"`
|
||||
}
|
||||
|
||||
type ManagerStatus struct {
|
||||
Configured int `json:"configured"`
|
||||
Running int `json:"running"`
|
||||
Connecting int `json:"connecting"`
|
||||
TownReady int `json:"town_ready"`
|
||||
StoreReady int `json:"store_ready"`
|
||||
Pending int `json:"pending"`
|
||||
Errors int `json:"errors"`
|
||||
Reconnects int `json:"reconnects"`
|
||||
TargetOnline int `json:"target_online"`
|
||||
SchedulerManaged int `json:"scheduler_managed"`
|
||||
}
|
||||
|
||||
func (m *Manager) Status() ManagerStatus {
|
||||
status := ManagerStatus{TargetOnline: m.Automation().TargetOnline}
|
||||
for _, snapshot := range m.List() {
|
||||
status.Configured++
|
||||
status.Reconnects += snapshot.Reconnects
|
||||
if snapshot.Running {
|
||||
status.Running++
|
||||
}
|
||||
if snapshot.SchedulerManaged {
|
||||
status.SchedulerManaged++
|
||||
}
|
||||
switch snapshot.State {
|
||||
case StateConnecting, StateBinding, StateSelecting:
|
||||
status.Connecting++
|
||||
case StateTownReady:
|
||||
status.TownReady++
|
||||
case StateStoreReady:
|
||||
status.StoreReady++
|
||||
case StateStoreOpening, StateStoreClosing:
|
||||
status.Pending++
|
||||
case StateError:
|
||||
status.Errors++
|
||||
}
|
||||
if snapshot.LastError != "" && snapshot.State != StateError {
|
||||
status.Errors++
|
||||
}
|
||||
}
|
||||
return status
|
||||
}
|
||||
|
||||
func (m *Manager) Batch(ctx context.Context, request BatchRequest) (BatchResult, error) {
|
||||
if m == nil {
|
||||
return BatchResult{}, ErrManagerStopped
|
||||
}
|
||||
action := strings.ToLower(strings.TrimSpace(request.Action))
|
||||
switch action {
|
||||
case BatchActionStart, BatchActionStop, BatchActionMove, BatchActionChat, BatchActionStoreOpen, BatchActionStoreClose:
|
||||
default:
|
||||
return BatchResult{}, errors.New("invalid dnf robot batch action")
|
||||
}
|
||||
ids := m.batchProfileIDs(request.IDs)
|
||||
if len(ids) == 0 {
|
||||
return BatchResult{}, ErrProfileNotFound
|
||||
}
|
||||
operation := m.BeginOperation("batch", action)
|
||||
result := BatchResult{Action: action, Requested: len(ids), Results: make([]BatchActionResult, 0, len(ids))}
|
||||
for _, id := range ids {
|
||||
var (
|
||||
snapshot RuntimeSnapshot
|
||||
err error
|
||||
)
|
||||
switch action {
|
||||
case BatchActionStart:
|
||||
snapshot, err = m.StartProfile(id)
|
||||
case BatchActionStop:
|
||||
snapshot, err = m.StopProfile(id)
|
||||
case BatchActionMove:
|
||||
err = m.Move(id, request.Village, request.Area, request.X, request.Y, request.MoveType)
|
||||
snapshot = m.snapshotByID(id)
|
||||
case BatchActionChat:
|
||||
err = m.Chat(id, request.ChatMode, request.Message)
|
||||
snapshot = m.snapshotByID(id)
|
||||
case BatchActionStoreOpen:
|
||||
err = m.OpenPrivateStore(ctx, id, request.StoreTitle, request.StoreRows, request.StorePrice)
|
||||
snapshot = m.snapshotByID(id)
|
||||
case BatchActionStoreClose:
|
||||
err = m.ClosePrivateStore(id)
|
||||
snapshot = m.snapshotByID(id)
|
||||
}
|
||||
row := BatchActionResult{ID: id, OK: err == nil, Snapshot: snapshot}
|
||||
if err != nil {
|
||||
row.Error = err.Error()
|
||||
result.Failed++
|
||||
} else {
|
||||
result.Succeeded++
|
||||
}
|
||||
result.Results = append(result.Results, row)
|
||||
}
|
||||
m.CompleteOperation(operation.ID, fmt.Sprintf("requested=%d succeeded=%d failed=%d", result.Requested, result.Succeeded, result.Failed), nil)
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (m *Manager) batchProfileIDs(requested []string) []string {
|
||||
if len(requested) == 0 {
|
||||
m.mu.RLock()
|
||||
ids := make([]string, 0, len(m.config.Profiles))
|
||||
for _, profile := range m.config.Profiles {
|
||||
ids = append(ids, profile.ID)
|
||||
}
|
||||
m.mu.RUnlock()
|
||||
return ids
|
||||
}
|
||||
seen := make(map[string]struct{}, len(requested))
|
||||
ids := make([]string, 0, len(requested))
|
||||
for _, id := range requested {
|
||||
id = strings.TrimSpace(id)
|
||||
key := profileKey(id)
|
||||
if key == "" {
|
||||
continue
|
||||
}
|
||||
if _, exists := seen[key]; exists {
|
||||
continue
|
||||
}
|
||||
seen[key] = struct{}{}
|
||||
ids = append(ids, id)
|
||||
}
|
||||
return ids
|
||||
}
|
||||
|
||||
func (m *Manager) snapshotByID(id string) RuntimeSnapshot {
|
||||
for _, snapshot := range m.List() {
|
||||
if profileKey(snapshot.Profile.ID) == profileKey(id) {
|
||||
return snapshot
|
||||
}
|
||||
}
|
||||
return RuntimeSnapshot{}
|
||||
}
|
||||
Reference in new issue
Block a user