Skip to content

Commit a2df93d

Browse files
committed
Demo分析自动化增强
1 parent 01af5ac commit a2df93d

10 files changed

Lines changed: 902 additions & 1113 deletions

File tree

0 Bytes
Binary file not shown.
0 Bytes
Binary file not shown.

bin/MulNX/CS2OBTool/CS2OBTool.dll

21 KB
Binary file not shown.

bin/MulNX/CS2OBTool/UISystem/Config/MulNXUIConfig.ini

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ Size=663,340
4747
Collapsed=0
4848

4949
[Window][Demo辅助]
50-
Pos=464,428
50+
Pos=183,736
5151
Size=736,716
5252
Collapsed=0
5353
DockId=0x00000004,2
@@ -86,7 +86,7 @@ Collapsed=0
8686
DockId=0x00000002,0
8787

8888
[Window][Demo]
89-
Pos=464,428
89+
Pos=183,736
9090
Size=736,716
9191
Collapsed=0
9292
DockId=0x00000004,0
@@ -196,7 +196,7 @@ Collapsed=0
196196
DockId=0x00000004,1
197197

198198
[Window][Demo Recorder]
199-
Pos=1202,428
199+
Pos=921,736
200200
Size=640,521
201201
Collapsed=0
202202
DockId=0x00000008,0
@@ -207,13 +207,13 @@ Size=358,674
207207
Collapsed=0
208208

209209
[Window][录制任务创建]
210-
Pos=464,428
210+
Pos=183,736
211211
Size=736,716
212212
Collapsed=0
213213
DockId=0x00000004,1
214214

215215
[Window][录制参数调节]
216-
Pos=1202,951
216+
Pos=921,1259
217217
Size=640,193
218218
Collapsed=0
219219
DockId=0x00000009,0
@@ -273,7 +273,7 @@ DockId=0x0000000C,0
273273

274274
[Window][时间轴]
275275
Pos=0,0
276-
Size=1920,37
276+
Size=1920,57
277277
Collapsed=0
278278
DockId=0x00000001,0
279279

@@ -283,16 +283,16 @@ Size=530,226
283283
Collapsed=0
284284

285285
[Docking][Data]
286-
DockNode ID=0x00000003 Pos=464,428 Size=1378,716 Split=X Selected=0x448D10F7
286+
DockNode ID=0x00000003 Pos=183,736 Size=1378,716 Split=X Selected=0x448D10F7
287287
DockNode ID=0x00000004 Parent=0x00000003 SizeRef=838,992 Selected=0xE555D201
288288
DockNode ID=0x00000007 Parent=0x00000003 SizeRef=729,992 Split=Y Selected=0x8538678F
289289
DockNode ID=0x00000008 Parent=0x00000007 SizeRef=729,644 Selected=0x3C0020BC
290290
DockNode ID=0x00000009 Parent=0x00000007 SizeRef=729,238 Selected=0x8538678F
291291
DockNode ID=0x0000000A Pos=820,750 Size=685,394 Split=X
292292
DockNode ID=0x0000000B Parent=0x0000000A SizeRef=1042,407 Selected=0x2D59FDA6
293293
DockNode ID=0x0000000C Parent=0x0000000A SizeRef=606,407 Selected=0x4DB1B67D
294-
DockNode ID=0x0000000D Pos=1458,620 Size=433,378 Selected=0xC12FA4B6
294+
DockNode ID=0x0000000D Pos=1458,620 Size=433,378 Selected=0x7773E0DE
295295
DockSpace ID=0x633F05CB Window=0xFB32D03B Pos=0,0 Size=1920,1080 Split=Y Selected=0xC52A91C6
296-
DockNode ID=0x00000001 Parent=0x633F05CB SizeRef=1920,37 Selected=0x38DB91B6
297-
DockNode ID=0x00000002 Parent=0x633F05CB SizeRef=1920,1041 CentralNode=1
296+
DockNode ID=0x00000001 Parent=0x633F05CB SizeRef=1920,57 Selected=0x38DB91B6
297+
DockNode ID=0x00000002 Parent=0x633F05CB SizeRef=1920,1021 CentralNode=1
298298

bin/MulNX/Log/Log_CS2Injector.txt

Lines changed: 100 additions & 100 deletions
Large diffs are not rendered by default.

bin/MulNX/Log/Log_CS2OBTool.txt

Lines changed: 625 additions & 923 deletions
Large diffs are not rendered by default.

source/MulNXExtensions/CS2/Feature/DemoSystem/DemoAnalyzer/DemoAnalyzer.cpp

Lines changed: 73 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -19,73 +19,96 @@ bool DemoAnalyzer::Init() {
1919
void DemoAnalyzer::ProcessMsg(MulNX::Message& msg) {
2020
switch (msg.type) {
2121
case "Demo/Analyze"_hash: {
22-
std::string demoPath = msg.asp.get<MulNX::NetExt>()->str1;
23-
this->LogInfo("Received demo path: " + demoPath);
24-
this->AnalyzeDemoWithCSDA(std::move(demoPath)).resume();
22+
std::string str = msg.asp.get<MulNX::NetExt>()->str1;
23+
std::filesystem::path demoPath(str);
24+
// 确保为绝对路径(正常情况下已经是)
25+
if (!demoPath.is_absolute()) {
26+
this->LogWarning("收到非绝对路径: " + str);
27+
demoPath = std::filesystem::absolute(demoPath);
28+
}
29+
this->LogInfo("Received demo path: " + demoPath.string());
30+
this->HandleAnalyzeRequest(std::move(demoPath));
2531
break;
2632
}
2733
default:
2834
break;
2935
}
3036
}
3137

32-
MulNX::CoTask DemoAnalyzer::AnalyzeDemoWithCSDA(std::filesystem::path&& pthDemo) {
33-
// ---------- 调用 csda.exe ----------
34-
// 1. 构建命令行字符串,注意路径带引号,以防空格
35-
std::ostringstream cmdLine;
36-
cmdLine << "\"" << this->csdaPath.string() << "\" "
37-
<< "-demo-path=" << pthDemo << " "
38-
<< "-output=\"" << this->dirData.string() << "\" "
39-
<< "-format=json"; // 可根据需要加 -positions 等
40-
41-
std::string cmdStr = cmdLine.str();
42-
this->LogInfo("Executing: " + cmdStr);
43-
44-
// 准备 STARTUPINFO 和 PROCESS_INFORMATION
45-
STARTUPINFOW si;
46-
PROCESS_INFORMATION pi;
47-
ZeroMemory(&si, sizeof(si));
48-
si.cb = sizeof(si);
49-
ZeroMemory(&pi, sizeof(pi));
50-
51-
// 注意:需要将 cmdStr 复制到可修改的缓冲区,因为 CreateProcess 可能会修改它
38+
void DemoAnalyzer::HandleAnalyzeRequest(std::filesystem::path demoPath) {
39+
std::string stem = demoPath.stem().string();
40+
std::filesystem::path jsonPath = this->dirData / (stem + ".json");
41+
42+
// 1. JSON 已存在 → 直接发送加载消息
43+
if (std::filesystem::exists(jsonPath)) {
44+
this->LogInfo("分析结果已存在,直接加载: " + demoPath.string());
45+
auto [msg, rp] = MulNX::Message::Create<MulNX::NetExt>("Demo/JSON/Load"_hash);
46+
rp->str1 = stem;
47+
this->PublishAsync(std::move(msg));
48+
return;
49+
}
50+
51+
// 2. 检查是否正在分析
52+
{
53+
std::unique_lock lock(this->smutex);
54+
if (this->analyzingSet.find(demoPath) != this->analyzingSet.end()) {
55+
this->LogWarning("该 Demo 正在分析中: " + demoPath.string());
56+
return;
57+
}
58+
else {
59+
this->analyzingSet.insert(demoPath);
60+
}
61+
}
62+
63+
this->LogInfo("开始分析: " + demoPath.string());
64+
this->AnalyzeDemoWithCSDA(std::move(demoPath)).resume();
65+
}
66+
67+
MulNX::CoTask DemoAnalyzer::AnalyzeDemoWithCSDA(std::filesystem::path demoPath) {
68+
std::string stem = demoPath.stem().string();
69+
70+
// RAII:分析结束时从队列移除
71+
auto cleanup = scope_exit([this, demoPath] {
72+
std::unique_lock lock(this->smutex);
73+
analyzingSet.erase(demoPath);
74+
});
75+
76+
// 构造 csda 命令行,确保路径包含引号以处理空格
77+
std::string cmdStr = "\"" + this->csdaPath.string() + "\" "
78+
+ "-demo-path=\"" + demoPath.string() + "\" "
79+
+ "-output=\"" + this->dirData.string() + "\" "
80+
+ "-format=json";
81+
82+
this->LogInfo("执行: " + cmdStr);
83+
84+
STARTUPINFOW si{ sizeof(si) };
85+
PROCESS_INFORMATION pi{};
5286
auto cmdBuffer = MulNX::CharUtility::U8ToW(cmdStr);
5387

54-
// 创建进程
55-
BOOL success = CreateProcessW(
56-
nullptr, // 应用程序名
57-
cmdBuffer.data(), // 命令行(注意是可修改的)
58-
nullptr,
59-
nullptr,
60-
FALSE,
61-
CREATE_NO_WINDOW,
62-
nullptr,
63-
nullptr,
64-
&si,
65-
&pi
66-
);
67-
68-
if (!success) {
69-
DWORD err = GetLastError();
70-
this->LogError("Failed to create process, error code: " + std::to_string(err));
71-
co_return;
88+
if (!CreateProcessW(nullptr, cmdBuffer.data(), nullptr, nullptr,
89+
FALSE, CREATE_NO_WINDOW, nullptr, nullptr, &si, &pi)) {
90+
this->LogError("创建进程失败,错误码: " + std::to_string(GetLastError()));
91+
co_return; // cleanup 自动执行,不发送消息
7292
}
7393

74-
co_await this->WaitUntil([hProcess = pi.hProcess] {
75-
return WaitForSingleObject(hProcess, 0) == WAIT_OBJECT_0;
94+
co_await this->WaitUntil([h = pi.hProcess] {
95+
return WaitForSingleObject(h, 0) == WAIT_OBJECT_0;
7696
});
7797

78-
// 获取退出码并检查
7998
DWORD exitCode = 0;
8099
GetExitCodeProcess(pi.hProcess, &exitCode);
100+
CloseHandle(pi.hProcess);
101+
CloseHandle(pi.hThread);
102+
81103
if (exitCode != 0) {
82-
this->LogError("csda.exe exited with code: " + std::to_string(exitCode));
104+
this->LogError("csda.exe 退出码: " + std::to_string(exitCode));
83105
}
84106
else {
85-
this->LogInfo("Demo analysis completed successfully.");
107+
this->LogInfo("Demo 分析成功完成。");
108+
// 仅成功时发送加载消息
109+
auto [msg, rp] = MulNX::Message::Create<MulNX::NetExt>("Demo/JSON/Load"_hash);
110+
rp->str1 = stem;
111+
this->PublishAsync(std::move(msg));
86112
}
87-
88-
// 清理句柄
89-
CloseHandle(pi.hProcess);
90-
CloseHandle(pi.hThread);
113+
// cleanup 析构,移除队列
91114
}

source/MulNXExtensions/CS2/Feature/DemoSystem/DemoAnalyzer/DemoAnalyzer.hpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
22
#include <Intro/CSModuleBase.hpp>
33

44
class DemoAnalyzer final : public CSModuleBase {
5-
std::filesystem::path csdaPath{};
6-
std::filesystem::path dirData{};
7-
MulNX::CoTask AnalyzeDemoWithCSDA(std::filesystem::path&& pthDemo);
8-
public:
9-
bool Init()override;
10-
void ProcessMsg(MulNX::Message& msg)override;
5+
std::filesystem::path csdaPath;
6+
std::filesystem::path dirData;
7+
std::set<std::filesystem::path> analyzingSet; // 正在分析的 demo 绝对路径
8+
9+
void HandleAnalyzeRequest(std::filesystem::path demoPath);
10+
MulNX::CoTask AnalyzeDemoWithCSDA(std::filesystem::path demoPath);
11+
12+
bool Init() override;
13+
void ProcessMsg(MulNX::Message& msg) override;
1114
};

source/MulNXExtensions/CS2/Feature/DemoSystem/HookDemo/HookDemo.cpp

Lines changed: 82 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,30 +11,91 @@ bool HookDemo::Init() {
1111
return true;
1212
}
1313
void HookDemo::HookPlayDemo(CCmd* pCmd) {
14-
auto pf = pCmd->m_pCommandCallback;
15-
this->hkPlaydemo = MulNX::Hook::Create((uint8_t*)pCmd->m_pCommandCallback, [this](MulNX::Hook* hk, RegContext* ctx) {
16-
auto cmd = (CCommand*)ctx->rdx;
17-
hk->CallMaybeOrigin(0, ctx);
18-
std::string_view raw(cmd->pRawString);
19-
raw = raw.substr(raw.find(' ') + 1);
20-
this->LogInfo(std::format("播放Demo: {}", raw));
21-
return MulNX::Hook::Then::Return;
22-
}).value();
23-
this->hkPlaydemo->Attach();
24-
this->LogSucc(I18n("hook.attached", "PlayDemo"));
14+
this->hkPlaydemo = this->CreateHook(
15+
"PlayDemo", (uint8_t*)pCmd->m_pCommandCallback,
16+
[this](MulNX::Hook* hk, RegContext* ctx) {
17+
auto cmd = (CCommand*)ctx->rdx;
18+
hk->CallMaybeOrigin(0, ctx);
19+
std::string_view raw(cmd->pRawString);
20+
raw = raw.substr(raw.find(' ') + 1);
21+
this->BeforePlay(raw);
22+
return MulNX::Hook::Then::Return;
23+
}
24+
).value();
25+
this->hkPlaydemo.Attach();
2526
}
2627
void HookDemo::HookDemoGotoTick(CCmd* pCmd) {
2728
auto pf = pCmd->m_pCommandCallback;
28-
this->hkDemoGotoTick = MulNX::Hook::Create((uint8_t*)pCmd->m_pCommandCallback, [this](MulNX::Hook* hk, RegContext* ctx) {
29-
auto cmd = (CCommand*)ctx->rdx;
30-
hk->CallMaybeOrigin(0, ctx);
31-
auto msg = MulNX::Message("Demo/GotoTick/Complete"_hash);
32-
auto&& [jumpTick] = msg.Access<int>();
33-
sscanf_s(cmd->pRawString, "demo_gototick %d", &jumpTick);
34-
this->LogInfo(std::format("跳转到tick: {}", jumpTick));
35-
this->PublishAsync(std::move(msg));
36-
return MulNX::Hook::Then::Return;
29+
this->hkDemoGotoTick = this->CreateHook(
30+
"DemoGotoTick", (uint8_t*)pCmd->m_pCommandCallback,
31+
[this](MulNX::Hook* hk, RegContext* ctx) {
32+
auto cmd = (CCommand*)ctx->rdx;
33+
hk->CallMaybeOrigin(0, ctx);
34+
auto msg = MulNX::Message("Demo/GotoTick/Complete"_hash);
35+
auto&& [jumpTick] = msg.Access<int>();
36+
sscanf_s(cmd->pRawString, "demo_gototick %d", &jumpTick);
37+
this->LogInfo(std::format("跳转到tick: {}", jumpTick));
38+
this->PublishAsync(std::move(msg));
39+
return MulNX::Hook::Then::Return;
3740
}).value();
3841
this->hkDemoGotoTick->Attach();
39-
this->LogSucc(I18n("hook.attached", "DemoGotoTick"));
42+
}
43+
void HookDemo::BeforePlay(std::string_view rawArg) {
44+
// 1. 去除首尾空白
45+
std::string rawPath(rawArg);
46+
size_t start = rawPath.find_first_not_of(" \t");
47+
if (start == std::string::npos) {
48+
this->LogError("解析Demo名失败");
49+
return;
50+
}
51+
size_t end = rawPath.find_last_not_of(" \t");
52+
rawPath = rawPath.substr(start, end - start + 1);
53+
54+
// 2. 去除可能存在的成对引号
55+
if (rawPath.size() >= 2) {
56+
if ((rawPath.front() == '"' && rawPath.back() == '"') ||
57+
(rawPath.front() == '\'' && rawPath.back() == '\'')) {
58+
rawPath = rawPath.substr(1, rawPath.size() - 2);
59+
}
60+
}
61+
62+
auto& dirDemos = this->CS2Paths->demo;
63+
std::filesystem::path demoPath(rawPath);
64+
if (!demoPath.is_absolute()) {
65+
demoPath = dirDemos / demoPath;
66+
}
67+
68+
// 3. 检查文件是否存在,若不存在且缺少 .dem 后缀则自动补全
69+
bool fileFound = false;
70+
if (std::filesystem::exists(demoPath) && std::filesystem::is_regular_file(demoPath)) {
71+
fileFound = true; // 原路径直接有效
72+
}
73+
else if (demoPath.extension() != ".dem") {
74+
// 尝试追加 .dem
75+
std::filesystem::path tryPath = demoPath;
76+
tryPath += ".dem";
77+
if (std::filesystem::exists(tryPath) && std::filesystem::is_regular_file(tryPath)) {
78+
demoPath = tryPath;
79+
fileFound = true;
80+
this->LogWarning(std::format("已自动补充 .dem 后缀: {}", demoPath.string()));
81+
}
82+
}
83+
84+
if (!fileFound) {
85+
this->LogError(std::format("找不到Demo文件: {}", demoPath.string()));
86+
return;
87+
}
88+
89+
// 4. 最终确定,输出播放日志
90+
this->LogInfo(std::format("播放Demo: {}", demoPath.string()));
91+
92+
// 发送分析请求(包含完整路径)
93+
auto [msg, rp] = MulNX::Message::Create<MulNX::NetExt>("Demo/Analyze"_hash);
94+
rp->str1 = demoPath.string();
95+
this->PublishAsync(std::move(msg));
96+
97+
// 发送设置当前操作的 Demo(使用不带扩展名的文件名)
98+
auto [msg2, rp2] = MulNX::Message::Create<MulNX::NetExt>("Demo/SetOperating"_hash);
99+
rp2->str1 = demoPath.stem().string(); // 例如 "111"
100+
this->PublishAsync(std::move(msg2));
40101
}

source/MulNXExtensions/CS2/Feature/DemoSystem/HookDemo/HookDemo.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
#include <Intro/HookConsole/HookConsole.hpp>
44

55
class HookDemo final :public CSModuleBase {
6-
std::unique_ptr<MulNX::Hook>hkPlaydemo = nullptr;
7-
std::unique_ptr<MulNX::Hook>hkDemoGotoTick = nullptr;
6+
WrapHook hkPlaydemo{};
7+
WrapHook hkDemoGotoTick{};
88
void HookPlayDemo(CCmd* cmd);
99
void HookDemoGotoTick(CCmd* cmd);
10-
public:
10+
void BeforePlay(std::string_view rawArg);
1111
bool Init()override;
1212
};

0 commit comments

Comments
 (0)