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,58 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { applyDropPatches, convertDropRecord, dropListText, dropRecordText, editDropFields, replaceDropSpan, sourceOffset } from "../src/gui/independentDrop";
|
||||
import type { IndependentDropRow, SkillNumber } from "../bindings/pvfine/services/models";
|
||||
function fixture() {
|
||||
const line="0 20 3176 1000000 20 30 40 50 1 2 3 4 5 0 99 -1 1";
|
||||
const normalized="# 😀\n[independent drop]\n"+line+"\n[list]\n3176 20 3030 80\n[/list]\n[replace list]\n[dungeon condition]\n1 20 2\n[/replace list]\n[/independent drop]\n";
|
||||
const start=normalized.indexOf(line);
|
||||
const fields=[...line.matchAll(/-?\d+/g)].map(m=>({value:Number(m[0]),start:start+m.index!,end:start+m.index!+m[0].length,tokenType:0}) as SkillNumber);
|
||||
return {text:normalized.replaceAll("\n","\r\n"),row:{fields,start,end:normalized.indexOf("[/independent drop]"),hasExtensions:true} as IndependentDropRow};
|
||||
}
|
||||
describe("独立掉落源位置编辑",()=>{
|
||||
it("概率只修改目标字段,保留扩展条件、注释、emoji 和 CRLF",()=>{
|
||||
const {text,row}=fixture();
|
||||
expect(editDropFields(text,row,[{column:3,value:752500},{column:8,value:7}])).toBe(text.replace("1000000","752500").replace("1 2 3 4 5 0 99","7 2 3 4 5 0 99"));
|
||||
});
|
||||
it("处理列表增删、零权重和重复 ID",()=>{
|
||||
const content=dropListText([{id:3176,weight:0},{id:3176,weight:2}]);
|
||||
expect(content).toContain("3176\t0");
|
||||
const {text}=fixture();const normalized=text.replaceAll("\r\n","\n");
|
||||
const from=normalized.indexOf("[list]")+6,to=normalized.indexOf("[/list]");
|
||||
const edited=replaceDropSpan(text,from,to,"\n"+content+"\n");
|
||||
expect(edited).toContain("[replace list]\r\n[dungeon condition]");
|
||||
expect(edited).toContain("3176\t2");
|
||||
expect(sourceOffset(text,3)).toBe(3);
|
||||
});
|
||||
it("三种模式生成完整记录",()=>{
|
||||
const {row}=fixture(),values=row.fields!.map(f=>f.value);
|
||||
for(const mode of [0,1,2]){
|
||||
const record=dropRecordText([...values.slice(0,16),mode],[{id:3176,weight:1}],17);
|
||||
expect(record.includes("[list]")).toBe(mode!==0);
|
||||
if(mode===2)expect(record).toContain("\t\t17\n");
|
||||
}
|
||||
});
|
||||
it("转换掉落模式时保留相邻注释和额外 section",()=>{
|
||||
const {text,row}=fixture();
|
||||
const clean=text.replace(/\[replace list\][\s\S]*?\[\/replace list\]\r\n/,"");
|
||||
const normalized=clean.replaceAll("\r\n","\n");
|
||||
const source={...row,hasExtensions:false,listTagStart:normalized.indexOf("[list]"),listStart:normalized.indexOf("[list]")+6,listEnd:normalized.indexOf("[/list]")};
|
||||
const values=row.fields!.map(f=>f.value);values[16]=2;
|
||||
const edited=convertDropRecord(clean,source,values,[],17);
|
||||
expect(edited).toContain("[list]\n\t\t17\n\t[/list]");
|
||||
expect(edited).toContain("# 😀\r\n[independent drop]\r\n");
|
||||
expect(edited.match(/\[list\]/g)).toHaveLength(1);
|
||||
expect(edited).toContain("[/independent drop]\r\n");
|
||||
expect(()=>convertDropRecord(text,row,values,[],17)).toThrow("扩展");
|
||||
});
|
||||
it("拒绝过期、重叠、未知模式、溢出和非法概率",()=>{
|
||||
const {text,row}=fixture();
|
||||
expect(()=>editDropFields(text.replace("1000000","900000"),row,[{column:3,value:1}])).toThrow("草稿已变化");
|
||||
for(const value of [-1,1000001,NaN,1.5])expect(()=>editDropFields(text,row,[{column:3,value}])).toThrow();
|
||||
expect(()=>editDropFields(text,row,[{column:16,value:0}])).toThrow();
|
||||
expect(()=>editDropFields(text,row,[{column:3,value:1},{column:3,value:2}])).toThrow("重叠");
|
||||
expect(()=>applyDropPatches(text,[{token:row.fields![1]!,value:2147483648}])).toThrow();
|
||||
expect(()=>dropListText([{id:1,weight:-1}])).toThrow();
|
||||
expect(()=>sourceOffset(text,99999)).toThrow();
|
||||
expect(()=>dropRecordText([...row.fields!.slice(0,16).map(f=>f.value),5],[],0)).toThrow("未知");
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user