mirror of
https://github.com/HolographicHat/Yae.git
synced 2025-12-09 16:08:14 +08:00
Compare commits
74 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4e94d67d0b | ||
|
|
7dafd95099 | ||
|
|
76c20407ea | ||
|
|
b79b82ec10 | ||
|
|
07fe60a092 | ||
|
|
7fa2fbac25 | ||
|
|
28ffa6fb1a | ||
|
|
4c2cb28313 | ||
|
|
2f1a5ad99e | ||
|
|
9b0c384d4b | ||
|
|
b2111db4eb | ||
|
|
2442264224 | ||
|
|
b596cad02e | ||
|
|
30a0189f5e | ||
|
|
f47fd234b4 | ||
|
|
7d306a60c9 | ||
|
|
10dd03335f | ||
|
|
41863c32f7 | ||
|
|
4c3e9d8e50 | ||
|
|
9d60cda4c7 | ||
|
|
e0c836e55d | ||
|
|
02b4d9df0b | ||
|
|
d5a20b44d5 | ||
|
|
31e23de4d6 | ||
|
|
fb8c941b57 | ||
|
|
468b4b91ea | ||
|
|
0ace6b951f | ||
|
|
74473a3811 | ||
|
|
34afe3b7a4 | ||
|
|
f1e8c09262 | ||
|
|
6a1fbe8fff | ||
|
|
e33ee57afc | ||
|
|
54763cbc80 | ||
|
|
1dcaf7ed8f | ||
|
|
bbe7c2cd03 | ||
|
|
e847d4c80e | ||
|
|
f753acfc78 | ||
|
|
08ccdb203e | ||
|
|
180ab8bab7 | ||
|
|
1adc6c4c0f | ||
|
|
82ab5a316c | ||
|
|
75c2f57cfa | ||
|
|
ef6a72312c | ||
|
|
3917f3e6c7 | ||
|
|
12348a3941 | ||
|
|
8aed3fd095 | ||
|
|
4110fc2d6d | ||
|
|
0de747e344 | ||
|
|
b76e8e3cd2 | ||
|
|
c12d376e21 | ||
|
|
d285b1c999 | ||
|
|
89ab4408d6 | ||
|
|
bf01214971 | ||
|
|
1900937a50 | ||
|
|
98a03a0910 | ||
|
|
82ba6120e4 | ||
|
|
6cb07d274a | ||
|
|
4acaa516bb | ||
|
|
b5caba2f7a | ||
|
|
ebb11bde9c | ||
|
|
4417feab53 | ||
|
|
28080dbafd | ||
|
|
a8b6419157 | ||
|
|
7f8296c3dc | ||
|
|
37382b28e0 | ||
|
|
a46e49722f | ||
|
|
700cbbb86d | ||
|
|
6a23153f70 | ||
|
|
75e3cd848f | ||
|
|
96912d3da7 | ||
|
|
02b034cc48 | ||
|
|
00898d11cb | ||
|
|
7cf03ad905 | ||
|
|
7d9e5bc218 |
21
.gitattributes
vendored
Normal file
21
.gitattributes
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
lib/src/il2cpp-types.h linguist-generated=true
|
||||
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
|
||||
*.cs text diff=csharp
|
||||
*.cshtml text diff=html
|
||||
*.csx text diff=csharp
|
||||
*.sln text eol=crlf merge=union
|
||||
*.csproj text merge=union
|
||||
|
||||
# Sources
|
||||
*.c text diff=cpp
|
||||
*.cc text diff=cpp
|
||||
*.cxx text diff=cpp
|
||||
*.cpp text diff=cpp
|
||||
*.c++ text diff=cpp
|
||||
*.hpp text diff=cpp
|
||||
*.h text diff=cpp
|
||||
*.h++ text diff=cpp
|
||||
*.hh text diff=cpp
|
||||
22
.gitignore
vendored
22
.gitignore
vendored
@@ -1,11 +1,13 @@
|
||||
cache
|
||||
cert
|
||||
config.json
|
||||
out.*
|
||||
node_modules
|
||||
bin/
|
||||
obj/
|
||||
/packages/
|
||||
riderModule.iml
|
||||
/_ReSharper.Caches/
|
||||
.idea
|
||||
app*.exe
|
||||
export*.json
|
||||
secret.js
|
||||
package-lock.json
|
||||
native.node
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
.vs/
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,3 +0,0 @@
|
||||
[submodule "native/src/wmi"]
|
||||
path = native/src/wmi
|
||||
url = https://github.com/HolographicHat/wmi
|
||||
2
LICENSE
2
LICENSE
@@ -1,4 +1,4 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
|
||||
41
README.md
41
README.md
@@ -1,37 +1,30 @@
|
||||
# 原神成就导出工具
|
||||
<div align="center">
|
||||
|
||||
   
|
||||
# YaeAchievement
|
||||
|
||||
- 支持导出所有成就
|
||||
- 支持官服,B服与国际服
|
||||
- 支持导出至[椰羊](https://cocogoat.work/achievement)、[SnapGenshin](https://github.com/DGP-Studio/Snap.Genshin)、[Paimon.moe](https://paimon.moe/achievement/)、[Seelie.me](https://seelie.me/achievements)和表格文件(csv)
|
||||
    
|
||||
|
||||
</div>
|
||||
|
||||
- 支持导出所有类别的成就
|
||||
- 支持官服,渠道服与国际服
|
||||
- 支持导出至[椰羊](https://cocogoat.work/achievement)、[SnapGenshin](https://github.com/DGP-Studio/Snap.Genshin)、[Paimon.moe](https://paimon.moe/achievement/)、[Seelie.me](https://seelie.me/achievements)、[寻空](https://github.com/xunkong/xunkong)和表格文件(csv)
|
||||
- 没有窗口大小、游戏语言等要求
|
||||
|
||||
## 使用说明
|
||||
**打开程序前需要关闭正在运行的原神主程序**
|
||||
第一次打开需要先设置原神主程序(YuanShen.exe/GenshinImpact.exe)所在路径
|
||||

|
||||
### Windows7
|
||||
系统变量添加名为```NODE_SKIP_PLATFORM_CHECK```的变量并将值设为```1```
|
||||

|
||||
设置完毕后,等待原神自动启动并退出
|
||||
|
||||
## 下载地址
|
||||
[releases/latest](https://github.com/HolographicHat/genshin-achievement-export/releases/latest)
|
||||
[releases/latest](https://github.com/HolographicHat/YaeAchievement/releases/latest)
|
||||
|
||||
## 问题反馈
|
||||
[issues](https://github.com/HolographicHat/genshin-achievement-export/issues)或[QQ群: 913777414](https://qm.qq.com/cgi-bin/qm/qr?k=9UGz-chQVTjZa4b82RA_A41vIcBVNpms&jump_from=webapi)
|
||||
[issues](https://github.com/HolographicHat/YaeAchievement/issues)或[QQ群: 913777414](https://qm.qq.com/cgi-bin/qm/qr?k=9UGz-chQVTjZa4b82RA_A41vIcBVNpms&jump_from=webapi)
|
||||
|
||||
## 常见问题
|
||||
0. Q: 打不开
|
||||
A: 安装 [.NET Runtime](https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/runtime-6.0.7-windows-x64-installer)
|
||||
|
||||
## 常见问题
|
||||
0. Q: 程序异常退出或被强行终止后,程序报错:网络错误(22-1) 或 原神启动时报错: 无法连接网络(4201)
|
||||
A: 用文本编辑器打开```C:\Windows\System32\drivers\etc\hosts```,删除```127.0.0.1 dispatch**global.yuanshen.com```后保存,重启原神
|
||||
|
||||
1. Q: 原神启动时报错: 数据异常(31-4302)
|
||||
A: 不要把软件和原神主程序放一起
|
||||
|
||||
2. Q: 为什么需要管理员权限
|
||||
A: 临时修改Hosts和启动原神
|
||||
|
||||
3. Q: 报毒?
|
||||
A: 执行命令或修改hosts引发,相关代码可在./utils.js,./appcenter.js下找到
|
||||
|
||||
4. Q: 原神进门后没有自动退出,程序输出停留在“加载完成”
|
||||
A: 关闭代理后重试
|
||||
|
||||
21
YaeAchievement.csproj
Normal file
21
YaeAchievement.csproj
Normal file
@@ -0,0 +1,21 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<ApplicationManifest>res\app.manifest</ApplicationManifest>
|
||||
<AssemblyVersion>2.0.0</AssemblyVersion>
|
||||
<FileVersion>2.0.0</FileVersion>
|
||||
<ApplicationIcon>icon.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Google.Protobuf" Version="3.21.2" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.2-beta1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
16
YaeAchievement.sln
Normal file
16
YaeAchievement.sln
Normal file
@@ -0,0 +1,16 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YaeAchievement", "YaeAchievement.csproj", "{FA5FA5E1-3B38-4AF9-8CBA-A7E9193D660C}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{FA5FA5E1-3B38-4AF9-8CBA-A7E9193D660C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FA5FA5E1-3B38-4AF9-8CBA-A7E9193D660C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FA5FA5E1-3B38-4AF9-8CBA-A7E9193D660C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FA5FA5E1-3B38-4AF9-8CBA-A7E9193D660C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
File diff suppressed because it is too large
Load Diff
176
app.js
176
app.js
@@ -1,176 +0,0 @@
|
||||
const proxy = require("udp-proxy")
|
||||
const cp = require("child_process")
|
||||
const rs = require("./regionServer")
|
||||
const appcenter = require("./appcenter")
|
||||
const {
|
||||
initConfig, splitPacket, upload, decodeProto, log, setupHost, KPacket, debug, checkUpdate,
|
||||
brotliCompressSync, brotliDecompressSync, checkGameIsRunning, checkPortIsUsing
|
||||
} = require("./utils")
|
||||
const { exportData } = require("./export")
|
||||
const { enablePrivilege, pause } = require("./native")
|
||||
|
||||
const onExit = () => {
|
||||
setupHost(true)
|
||||
console.log("按任意键退出")
|
||||
pause()
|
||||
};
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
process.on("SIGHUP", () => setupHost(true))
|
||||
process.on("unhandledRejection", (reason, promise) => {
|
||||
console.log("Unhandled Rejection at: ", promise, "\n0Reason:", reason)
|
||||
})
|
||||
process.on("uncaughtException", (err, origin) => {
|
||||
appcenter.uploadError(err, true)
|
||||
console.log(err)
|
||||
console.log(`Origin: ${origin}`)
|
||||
process.exit(1)
|
||||
})
|
||||
process.on("exit", onExit)
|
||||
process.on("SIGINT", onExit)
|
||||
try {
|
||||
enablePrivilege()
|
||||
} catch (e) {
|
||||
console.log("请使用管理员身份运行此程序")
|
||||
process.exit(-1)
|
||||
}
|
||||
appcenter.startup()
|
||||
let conf = await initConfig()
|
||||
checkPortIsUsing()
|
||||
checkGameIsRunning()
|
||||
log("检查更新")
|
||||
await checkUpdate()
|
||||
let gameProcess
|
||||
let unexpectedExit = true
|
||||
rs.create(conf,() => {
|
||||
setupHost()
|
||||
gameProcess = cp.execFile(conf.executable, { cwd: conf.path },err => {
|
||||
if (err !== null && !err.killed) {
|
||||
throw err
|
||||
}
|
||||
})
|
||||
log("启动原神")
|
||||
gameProcess.on("exit", () => {
|
||||
if (unexpectedExit) {
|
||||
console.log("游戏进程异常退出")
|
||||
process.exit(0)
|
||||
}
|
||||
})
|
||||
},(ip, port, hServer) => {
|
||||
let login = false
|
||||
let cache = new Map()
|
||||
let lastRecvTimestamp = 0
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
const options = {
|
||||
address: ip,
|
||||
port: port,
|
||||
localaddress: "127.0.0.1",
|
||||
localport: 45678,
|
||||
middleware: {
|
||||
message: (msg, sender, next) => {
|
||||
const buf = Buffer.from(msg)
|
||||
if (!(login && buf.readUInt8(8) === 0x51)) {
|
||||
next(msg, sender)
|
||||
}
|
||||
},
|
||||
proxyMsg: (msg, sender, peer, next) => {
|
||||
try { next(msg, sender, peer) } catch (e) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
let monitor;
|
||||
let stopped = false
|
||||
const createMonitor = () => {
|
||||
monitor = setInterval(async () => {
|
||||
if (login && lastRecvTimestamp + 2 < parseInt(Date.now() / 1000) && !stopped) {
|
||||
stopped = true
|
||||
unexpectedExit = false
|
||||
server.close(() => {})
|
||||
hServer.close()
|
||||
gameProcess.kill()
|
||||
clearInterval(monitor)
|
||||
setupHost(true)
|
||||
log("正在处理数据,请稍后...")
|
||||
let packets = Array.from(cache.values())
|
||||
cache.clear()
|
||||
packets.sort((a, b) => a.frg - b.frg)
|
||||
.sort((a, b) => a.sn - b.sn)
|
||||
.filter(i => i.data.byteLength !== 0)
|
||||
.forEach(i => {
|
||||
const psn = i.sn + i.frg
|
||||
cache.has(psn) ? (() => {
|
||||
const arr = cache.get(psn)
|
||||
arr.push(i.data)
|
||||
cache.set(psn, arr)
|
||||
})() : cache.set(psn, [i.data])
|
||||
})
|
||||
packets = Array.from(cache.values())
|
||||
.map(arr => {
|
||||
const data = Buffer.concat(arr)
|
||||
const len = Buffer.alloc(4)
|
||||
len.writeUInt32LE(data.length)
|
||||
return Buffer.concat([len, data])
|
||||
})
|
||||
const merged = Buffer.concat(packets)
|
||||
const compressed = brotliCompressSync(merged)
|
||||
const response = await upload(compressed)
|
||||
const data = brotliDecompressSync(response.data)
|
||||
if (response.status !== 200) {
|
||||
log(`发生错误: ${data}`)
|
||||
log(`请求ID: ${response.headers["x-api-requestid"]}`)
|
||||
log("请联系开发者以获取帮助")
|
||||
} else {
|
||||
const proto = await decodeProto(data,"AllAchievement")
|
||||
await exportData(proto)
|
||||
}
|
||||
process.exit(0)
|
||||
}
|
||||
},1000)
|
||||
}
|
||||
const server = proxy.createServer(options)
|
||||
server.on("message", (msg, _) => {
|
||||
if (msg.byteLength > 500) {
|
||||
login = true
|
||||
}
|
||||
})
|
||||
server.on("error", err => console.log(`Proxy error: ${err.message}` + err.message))
|
||||
server.on("proxyError", err => console.log(`Proxy error: ${err.message}` + err.message))
|
||||
server.on("proxyMsg", (msg, _) => {
|
||||
lastRecvTimestamp = parseInt(Date.now() / 1000)
|
||||
let buf = Buffer.from(msg)
|
||||
if (buf.byteLength <= 20) {
|
||||
switch(buf.readUInt32BE(0)) {
|
||||
case 325:
|
||||
createMonitor()
|
||||
debug("服务端握手应答")
|
||||
break
|
||||
case 404:
|
||||
lastRecvTimestamp = parseInt(Date.now() / 1000) - 2333
|
||||
break
|
||||
default:
|
||||
console.log(`Unhandled: ${buf.toString("hex")}`)
|
||||
process.exit(2)
|
||||
break
|
||||
}
|
||||
return
|
||||
}
|
||||
splitPacket(buf).forEach(sb => {
|
||||
if (sb.readUInt8(8) === 0x51) {
|
||||
const p = new KPacket(sb)
|
||||
if (!cache.has(p.hash)) cache.set(p.hash, p)
|
||||
}
|
||||
})
|
||||
})
|
||||
return server
|
||||
}).then(() => log("加载完毕"))
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
if (e instanceof Error) {
|
||||
appcenter.uploadError(e, true)
|
||||
} else {
|
||||
appcenter.uploadError(Error(e), true)
|
||||
}
|
||||
process.exit(1)
|
||||
}
|
||||
})()
|
||||
116
appcenter.js
116
appcenter.js
@@ -1,116 +0,0 @@
|
||||
const axios = require("axios")
|
||||
const crypto = require("crypto")
|
||||
const { version } = require("./version")
|
||||
const { getDeviceID, getDeviceInfo } = require("./native")
|
||||
|
||||
const getTimestamp = (d = new Date()) => {
|
||||
const p = i => i.toString().padStart(2, "0")
|
||||
return `${d.getUTCFullYear()}-${p(d.getUTCMonth() + 1)}-${p(d.getUTCDate())}T${p(d.getUTCHours())}:${p(d.getUTCMinutes())}:${p(d.getUTCSeconds())}.${p(d.getUTCMilliseconds())}Z`
|
||||
}
|
||||
|
||||
const queue = []
|
||||
const session = crypto.randomUUID()
|
||||
const key = "648b83bf-d439-49bd-97f4-e1e506bdfe39"
|
||||
|
||||
const install = (() => {
|
||||
const id = getDeviceID()
|
||||
return id === undefined ? crypto.randomUUID() : id
|
||||
})()
|
||||
|
||||
const device = (() => {
|
||||
const info = getDeviceInfo()
|
||||
info.appBuild = version.code
|
||||
info.appVersion = version.name
|
||||
info.sdkName = "appcenter.wpf.netcore"
|
||||
info.sdkVersion = "4.5.0"
|
||||
info.osName = "WINDOWS"
|
||||
info.appNamespace = "default"
|
||||
return info
|
||||
})()
|
||||
|
||||
const upload = () => {
|
||||
if (queue.length > 0) {
|
||||
const logs = []
|
||||
for (let i = 0; i <= queue.length; i++) {
|
||||
logs.push(queue.pop())
|
||||
}
|
||||
const data = JSON.stringify({"logs": logs})
|
||||
axios.post("https://in.appcenter.ms/logs?api-version=1.0.0", data,{
|
||||
headers: {
|
||||
"App-Secret": key,
|
||||
"Install-ID": install
|
||||
}
|
||||
}).catch(_ => {}).then()
|
||||
}
|
||||
}
|
||||
|
||||
const uploadError = (err, fatal) => {
|
||||
const eid = crypto.randomUUID()
|
||||
const reportJson = process.report.getReport(err)
|
||||
const reportAttachment = {
|
||||
type: "errorAttachment",
|
||||
device: device,
|
||||
timestamp: getTimestamp(),
|
||||
id: crypto.randomUUID(),
|
||||
sid: session,
|
||||
errorId: eid,
|
||||
contentType: "application/json",
|
||||
fileName: "report.json",
|
||||
data: Buffer.from(JSON.stringify(reportJson, null, 2), "utf-8").toString("base64")
|
||||
}
|
||||
// noinspection JSUnresolvedVariable
|
||||
const errorContent = {
|
||||
type: "managedError",
|
||||
id: eid,
|
||||
sid: session,
|
||||
architecture: "AMD64",
|
||||
userId: install,
|
||||
fatal: fatal,
|
||||
processId: process.pid,
|
||||
processName: process.argv0.replaceAll("\\", "/").split("/").pop(),
|
||||
timestamp: getTimestamp(),
|
||||
appLaunchTimestamp: getTimestamp(new Date(Date.now() - process.uptime())),
|
||||
exception: {
|
||||
"type": err.name,
|
||||
"message": err.message,
|
||||
"stackTrace": err.stack
|
||||
},
|
||||
device: device
|
||||
}
|
||||
queue.push(errorContent, reportAttachment)
|
||||
upload()
|
||||
}
|
||||
|
||||
const uploadEvent = (name, prop) => {
|
||||
const content = {
|
||||
type: "event",
|
||||
id: crypto.randomUUID(),
|
||||
sid: session,
|
||||
name: name,
|
||||
properties: prop,
|
||||
timestamp: getTimestamp(),
|
||||
device: device
|
||||
}
|
||||
queue.push(content)
|
||||
}
|
||||
|
||||
const startup = () => {
|
||||
queue.push({
|
||||
type: "startService",
|
||||
services: [ "Analytics","Crashes" ],
|
||||
timestamp: getTimestamp(),
|
||||
device: device
|
||||
})
|
||||
queue.push({
|
||||
type: "startSession",
|
||||
sid: session,
|
||||
timestamp: getTimestamp(),
|
||||
device: device
|
||||
})
|
||||
upload()
|
||||
setInterval(() => upload(), 5000)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
startup, upload, uploadError, uploadEvent
|
||||
}
|
||||
149
export.js
149
export.js
@@ -1,149 +0,0 @@
|
||||
const fs = require("fs")
|
||||
const axios = require("axios")
|
||||
const readline = require("readline")
|
||||
const { loadCache, log } = require("./utils")
|
||||
const { openUrl, copyToClipboard } = require("./native")
|
||||
|
||||
const exportToSeelie = proto => {
|
||||
const out = { achievements: {} }
|
||||
proto.list.filter(a => a.status === 3 || a.status === 2).forEach(({id}) => {
|
||||
out.achievements[id] = { done: true }
|
||||
})
|
||||
const fp = `./export-${Date.now()}-seelie.json`
|
||||
fs.writeFileSync(fp, JSON.stringify(out))
|
||||
log(`导出为文件: ${fp}`)
|
||||
}
|
||||
|
||||
const exportToPaimon = async proto => {
|
||||
const out = { achievement: {} }
|
||||
const data = await loadCache()
|
||||
proto.list.filter(a => a.status === 3 || a.status === 2).forEach(({id}) => {
|
||||
const gid = data["a"][id]
|
||||
if (out.achievement[gid] === undefined) {
|
||||
out.achievement[gid] = {}
|
||||
}
|
||||
out.achievement[gid][id] = true
|
||||
})
|
||||
const fp = `./export-${Date.now()}-paimon.json`
|
||||
fs.writeFileSync(fp, JSON.stringify(out))
|
||||
log(`导出为文件: ${fp}`)
|
||||
}
|
||||
|
||||
const exportToSnapGenshin = async proto => {
|
||||
const out = []
|
||||
proto.list.filter(a => a.status === 3 || a.status === 2).forEach(({id, finishTimestamp}) => {
|
||||
out.push({
|
||||
id: id,
|
||||
ts: finishTimestamp
|
||||
})
|
||||
})
|
||||
const json = JSON.stringify(out, null, 2)
|
||||
copyToClipboard(json)
|
||||
log("导出内容已复制到剪贴板")
|
||||
}
|
||||
|
||||
const exportToCocogoat = async proto => {
|
||||
const out = {
|
||||
achievements: []
|
||||
}
|
||||
const data = await loadCache()
|
||||
const p = i => i.toString().padStart(2, "0")
|
||||
const getDate = ts => {
|
||||
const d = new Date(parseInt(`${ts}000`))
|
||||
return `${d.getFullYear()}/${p(d.getMonth()+1)}/${p(d.getDate())}`
|
||||
}
|
||||
proto.list.filter(a => a.status === 3 || a.status === 2).forEach(({current, finishTimestamp, id, require}) => {
|
||||
const curAch = data["a"][id]
|
||||
out.achievements.push({
|
||||
id: id,
|
||||
status: current === undefined || current === 0 || curAch["p"] === undefined ? `${require}/${require}` : `${current}/${require}`,
|
||||
categoryId: curAch["g"],
|
||||
date: getDate(finishTimestamp)
|
||||
})
|
||||
})
|
||||
const response = await axios.post(`https://77.cocogoat.work/v1/memo?source=${encodeURI("全部成就")}`, out).catch(_ => {
|
||||
console.log("网络错误,请检查网络后重试 (26-1)")
|
||||
process.exit(261)
|
||||
})
|
||||
if (response.status !== 201) {
|
||||
console.log(`API StatusCode 错误,请联系开发者以获取帮助 (26-2-${response.status})`)
|
||||
process.exit(262)
|
||||
}
|
||||
const retcode = openUrl(`https://cocogoat.work/achievement?memo=${response.data.key}`)
|
||||
if (retcode > 32) {
|
||||
log("在浏览器内进行下一步操作")
|
||||
} else {
|
||||
log(`导出失败,请联系开发者以获取帮助 (26-3-${retcode})`)
|
||||
}
|
||||
}
|
||||
|
||||
const exportToCsv = async proto => {
|
||||
const data = await loadCache()
|
||||
const outputLines = ["ID,状态,特辑,名称,描述,当前进度,目标进度,完成时间"]
|
||||
const getStatusText = i => {
|
||||
switch (i) {
|
||||
case 1: return "未完成"
|
||||
case 2: return "已完成,未领取奖励"
|
||||
case 3: return "已完成"
|
||||
default: return "未知"
|
||||
}
|
||||
}
|
||||
const getTime = ts => {
|
||||
const d = new Date(parseInt(`${ts}000`))
|
||||
const p = i => i.toString().padStart(2, "0")
|
||||
return `${d.getFullYear()}/${p(d.getMonth() + 1)}/${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}`
|
||||
}
|
||||
const bl = [84517]
|
||||
proto.list.forEach(({current, finishTimestamp, id, status, require}) => {
|
||||
if (!bl.includes(id)) {
|
||||
const curAch = data["a"][id] === undefined ? (() => {
|
||||
console.log(`Error get id ${id} in excel`)
|
||||
return {
|
||||
g: "未知",
|
||||
n: "未知",
|
||||
d: "未知"
|
||||
}
|
||||
})() : data["a"][id]
|
||||
outputLines.push(`${id},${getStatusText(status)},${data["g"][curAch.g]},${curAch.n},${curAch.d},${status !== 1 ? current === 0 ? require : current : current},${require},${status === 1 ? "" : getTime(finishTimestamp)}`)
|
||||
}
|
||||
})
|
||||
const fp = `./export-${Date.now()}.csv`
|
||||
fs.writeFileSync(fp, `\uFEFF${outputLines.join("\n")}`)
|
||||
log(`导出为文件: ${fp}`)
|
||||
}
|
||||
|
||||
const exportData = async proto => {
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout
|
||||
})
|
||||
const question = (query) => new Promise(resolve => {
|
||||
rl.question(query, resolve)
|
||||
})
|
||||
const chosen = await question("导出至: \n[0] 椰羊 (https://cocogoat.work/achievement)\n[1] SnapGenshin\n[2] Paimon.moe\n[3] Seelie.me\n[4] 表格文件 (默认)\n输入一个数字(0-4): ")
|
||||
rl.close()
|
||||
switch (chosen) {
|
||||
case "0":
|
||||
await exportToCocogoat(proto)
|
||||
break
|
||||
case "1":
|
||||
await exportToSnapGenshin(proto)
|
||||
break
|
||||
case "2":
|
||||
await exportToPaimon(proto)
|
||||
break
|
||||
case "3":
|
||||
await exportToSeelie(proto)
|
||||
break
|
||||
case "raw":
|
||||
fs.writeFileSync(`./export-${Date.now()}-raw.json`, JSON.stringify(proto,null,2))
|
||||
log("OK")
|
||||
break
|
||||
default:
|
||||
await exportToCsv(proto)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
exportData
|
||||
}
|
||||
4
lib/.gitignore
vendored
Normal file
4
lib/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
.vs
|
||||
build
|
||||
YaeAchievementLib.vcxproj.user
|
||||
YaeAchievementLib.vcxproj.filters
|
||||
29
lib/YaeAchievementLib.sln
Normal file
29
lib/YaeAchievementLib.sln
Normal file
@@ -0,0 +1,29 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.1.32407.343
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "YaeAchievementLib", "YaeAchievementLib.vcxproj", "{83C3DF1A-6219-408E-98A3-C7040CCC96FD}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{83C3DF1A-6219-408E-98A3-C7040CCC96FD}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{83C3DF1A-6219-408E-98A3-C7040CCC96FD}.Debug|x64.Build.0 = Debug|x64
|
||||
{83C3DF1A-6219-408E-98A3-C7040CCC96FD}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{83C3DF1A-6219-408E-98A3-C7040CCC96FD}.Release|x64.ActiveCfg = Release|x64
|
||||
{83C3DF1A-6219-408E-98A3-C7040CCC96FD}.Release|x64.Build.0 = Release|x64
|
||||
{83C3DF1A-6219-408E-98A3-C7040CCC96FD}.Release|x86.ActiveCfg = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {470905A4-E6C4-4363-B44D-BAE9A50755A3}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
134
lib/YaeAchievementLib.vcxproj
Normal file
134
lib/YaeAchievementLib.vcxproj
Normal file
@@ -0,0 +1,134 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{83c3df1a-6219-408e-98a3-c7040ccc96fd}</ProjectGuid>
|
||||
<RootNamespace>YaeAchievementLib</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<EnableASAN>false</EnableASAN>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)build\$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>build\$(Platform)\$(Configuration)\</IntDir>
|
||||
<TargetName>YaeLib</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)build\$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>build\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;YAEACHIEVEMENTLIB_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<LanguageStandard_C>stdc17</LanguageStandard_C>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)lib\detours\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<AdditionalLibraryDirectories>$(ProjectDir)lib\detours\;$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>detours-x64.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>copy $(TargetPath) $(ProjectDir)..\bin\Debug\net6.0</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_AMD64_;NDEBUG;YAEACHIEVEMENTLIB_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<LanguageStandard_C>stdc17</LanguageStandard_C>
|
||||
<DebugInformationFormat>None</DebugInformationFormat>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)lib\detours\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<AdditionalLibraryDirectories>$(ProjectDir)lib\detours\;$(OutDir)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>detours-x64.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>copy $(TargetPath) $(ProjectDir)..\bin\Debug\net6.0</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="src\HookManager.h" />
|
||||
<ClInclude Include="src\il2cpp-api-functions.h" />
|
||||
<ClInclude Include="src\il2cpp-appdata.h" />
|
||||
<ClInclude Include="src\il2cpp-functions.h" />
|
||||
<ClInclude Include="src\il2cpp-types.h" />
|
||||
<ClInclude Include="src\il2cpp-init.h" />
|
||||
<ClInclude Include="src\il2cpp-unity-functions.h" />
|
||||
<ClInclude Include="src\pch.h" />
|
||||
<ClInclude Include="src\util.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\dllmain.cpp" />
|
||||
<ClCompile Include="src\il2cpp-init.cpp" />
|
||||
<ClCompile Include="src\pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\util.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
BIN
lib/lib/detours/detours-x64.lib
Normal file
BIN
lib/lib/detours/detours-x64.lib
Normal file
Binary file not shown.
1227
lib/lib/detours/detours.h
Normal file
1227
lib/lib/detours/detours.h
Normal file
File diff suppressed because it is too large
Load Diff
27
lib/lib/detours/detver.h
Normal file
27
lib/lib/detours/detver.h
Normal file
@@ -0,0 +1,27 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Common version parameters.
|
||||
//
|
||||
// Microsoft Research Detours Package, Version 4.0.1
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
|
||||
#define _USING_V110_SDK71_ 1
|
||||
#include "winver.h"
|
||||
#if 0
|
||||
#include <windows.h>
|
||||
#include <detours.h>
|
||||
#else
|
||||
#ifndef DETOURS_STRINGIFY
|
||||
#define DETOURS_STRINGIFY_(x) #x
|
||||
#define DETOURS_STRINGIFY(x) DETOURS_STRINGIFY_(x)
|
||||
#endif
|
||||
|
||||
#define VER_FILEFLAGSMASK 0x3fL
|
||||
#define VER_FILEFLAGS 0x0L
|
||||
#define VER_FILEOS 0x00040004L
|
||||
#define VER_FILETYPE 0x00000002L
|
||||
#define VER_FILESUBTYPE 0x00000000L
|
||||
#endif
|
||||
#define VER_DETOURS_BITS DETOURS_STRINGIFY(DETOURS_BITS)
|
||||
66
lib/src/HookManager.h
Normal file
66
lib/src/HookManager.h
Normal file
@@ -0,0 +1,66 @@
|
||||
#pragma once
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
#define CALL_ORIGIN(function, ...) \
|
||||
HookManager::call(function, __func__, __VA_ARGS__)
|
||||
|
||||
class HookManager {
|
||||
public:
|
||||
template <typename Fn>
|
||||
static void install(Fn func, Fn handler) {
|
||||
enable(func, handler);
|
||||
holderMap[reinterpret_cast<void*>(handler)] = reinterpret_cast<void*>(func);
|
||||
}
|
||||
|
||||
template <typename Fn>
|
||||
[[nodiscard]] static Fn getOrigin(Fn handler, const char* callerName = nullptr) noexcept {
|
||||
if (holderMap.count(reinterpret_cast<void*>(handler)) == 0) {
|
||||
printf("Origin not found for handler: %s. Maybe racing bug.", callerName == nullptr ? "<Unknown>" : callerName);
|
||||
return nullptr;
|
||||
}
|
||||
return reinterpret_cast<Fn>(holderMap[reinterpret_cast<void*>(handler)]);
|
||||
}
|
||||
|
||||
template <typename Fn>
|
||||
[[nodiscard]] static void detach(Fn handler) noexcept {
|
||||
disable(handler);
|
||||
holderMap.erase(reinterpret_cast<void*>(handler));
|
||||
}
|
||||
|
||||
template <typename RType, typename... Params>
|
||||
[[nodiscard]] static RType call(RType(*handler)(Params...), const char* callerName = nullptr, Params... params) {
|
||||
auto origin = getOrigin(handler, callerName);
|
||||
if (origin != nullptr)
|
||||
return origin(params...);
|
||||
|
||||
return RType();
|
||||
}
|
||||
|
||||
static void detachAll() noexcept {
|
||||
for (const auto &[key, value] : holderMap) {
|
||||
disable(key);
|
||||
}
|
||||
holderMap.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
inline static std::map<void*, void*> holderMap{};
|
||||
|
||||
template <typename Fn>
|
||||
static void disable(Fn handler) {
|
||||
Fn origin = getOrigin(handler);
|
||||
DetourTransactionBegin();
|
||||
DetourUpdateThread(GetCurrentThread());
|
||||
DetourDetach(&(PVOID&)origin, handler);
|
||||
DetourTransactionCommit();
|
||||
}
|
||||
|
||||
template <typename Fn>
|
||||
static void enable(Fn& func, Fn handler) {
|
||||
DetourTransactionBegin();
|
||||
DetourUpdateThread(GetCurrentThread());
|
||||
DetourAttach(&(PVOID&)func, handler);
|
||||
DetourTransactionCommit();
|
||||
}
|
||||
};
|
||||
114
lib/src/dllmain.cpp
Normal file
114
lib/src/dllmain.cpp
Normal file
@@ -0,0 +1,114 @@
|
||||
#include "pch.h"
|
||||
#include "util.h"
|
||||
#include "il2cpp-init.h"
|
||||
|
||||
using Genshin::ByteArray, Genshin::ClientKcpEvent, Genshin::KcpPacket, Genshin::KcpEventType;
|
||||
using std::to_string;
|
||||
|
||||
HWND unityWnd = 0;
|
||||
HANDLE hPipe = 0;
|
||||
|
||||
std::set<UINT16> PacketWhitelist = { 172, 198, 112, 2676, 7, 21, 135 }; // ping, token, loginreq
|
||||
|
||||
bool OnPacket(KcpPacket* pkt) {
|
||||
if (pkt->data == nullptr) return true;
|
||||
auto len = pkt->length;
|
||||
auto data = (ByteArray*)new BYTE[len + 32];
|
||||
data->max_length = len;
|
||||
memcpy(data->vector, pkt->data, len);
|
||||
Genshin::Packet_Xor(&data, len, nullptr);
|
||||
if (ReadMapped<UINT16>(data->vector, 0) != 0x4567) {
|
||||
delete[] data;
|
||||
return true;
|
||||
}
|
||||
if (!PacketWhitelist.contains(ReadMapped<UINT16>(data->vector, 2))) {
|
||||
//ifdef _DEBUG
|
||||
printf("Blocked cmdid: %d\n", ReadMapped<UINT16>(data->vector, 2));
|
||||
//endif
|
||||
delete[] data;
|
||||
return false;
|
||||
}
|
||||
printf("Passed cmdid: %d\n", ReadMapped<UINT16>(data->vector, 2));
|
||||
if (ReadMapped<UINT16>(data->vector, 2) == 2676) {
|
||||
auto headLength = ReadMapped<UINT16>(data->vector, 4);
|
||||
auto dataLength = ReadMapped<UINT32>(data->vector, 6);
|
||||
auto iStr = Genshin::Convert_ToBase64String(data, 10 + headLength, dataLength, nullptr);
|
||||
auto cStr = IlStringToString(iStr) + "\n";
|
||||
WriteFile(hPipe, cStr.c_str(), cStr.length(), nullptr, nullptr);
|
||||
CloseHandle(hPipe);
|
||||
ExitProcess(0);
|
||||
}
|
||||
delete[] data;
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace Hook {
|
||||
|
||||
int Kcp_Send(void* client, KcpPacket* pkt, void* method) {
|
||||
return OnPacket(pkt) ? CALL_ORIGIN(Kcp_Send, client, pkt, method) : 0;
|
||||
}
|
||||
|
||||
void MonoLoginMainPage__set_version(void* obj, Il2CppString* value, void* method) {
|
||||
auto version = IlStringToString(value);
|
||||
value = string_new(version + " YaeAchievement");
|
||||
CALL_ORIGIN(MonoLoginMainPage__set_version, obj, value, method);
|
||||
}
|
||||
|
||||
bool Kcp_Recv(void* client, ClientKcpEvent* evt, void* method) {
|
||||
auto result = CALL_ORIGIN(Kcp_Recv, client, evt, method);
|
||||
if (result == 0 || evt->fields.type != KcpEventType::EventRecvMsg) {
|
||||
return result;
|
||||
}
|
||||
return OnPacket(evt->fields.packet) ? result : false;
|
||||
}
|
||||
|
||||
std::map<INT, UINT> signatures;
|
||||
|
||||
ByteArray* UnityEngine_RecordUserData(INT type) {
|
||||
if (signatures.count(type)) {
|
||||
return GCHandle_GetObject<ByteArray>(signatures[type]);
|
||||
}
|
||||
auto result = CALL_ORIGIN(UnityEngine_RecordUserData, type);
|
||||
signatures[type] = GCHandle_New(result, true);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
void Run(HMODULE* phModule) {
|
||||
//AllocConsole();
|
||||
//freopen_s((FILE**)stdout, "CONOUT$", "w", stdout);
|
||||
while (
|
||||
GetModuleHandle("UserAssembly.dll") == nullptr ||
|
||||
(unityWnd = FindMainWindowByPID(GetCurrentProcessId())) == 0
|
||||
) {
|
||||
Sleep(1000);
|
||||
}
|
||||
InitIL2CPP();
|
||||
HookManager::install(Genshin::UnityEngine_RecordUserData, Hook::UnityEngine_RecordUserData);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
Genshin::Application_RecordUserData(i, nullptr);
|
||||
}
|
||||
HookManager::install(Genshin::Kcp_Send, Hook::Kcp_Send);
|
||||
HookManager::install(Genshin::Kcp_Recv, Hook::Kcp_Recv);
|
||||
HookManager::install(Genshin::MonoLoginMainPage__set_version, Hook::MonoLoginMainPage__set_version);
|
||||
hPipe = CreateFile(R"(\\.\pipe\YaeAchievementPipe)", GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (hPipe == INVALID_HANDLE_VALUE) {
|
||||
Win32ErrorDialog(1001);
|
||||
ExitProcess(0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// DLL entry point
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ulReasonForCall, LPVOID lpReserved) {
|
||||
switch (ulReasonForCall) {
|
||||
case DLL_PROCESS_ATTACH:
|
||||
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Run, new HMODULE(hModule), 0, NULL);
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
case DLL_PROCESS_DETACH:
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
310
lib/src/il2cpp-api-functions.h
Normal file
310
lib/src/il2cpp-api-functions.h
Normal file
@@ -0,0 +1,310 @@
|
||||
#ifndef DO_API_NO_RETURN
|
||||
#define DO_API_NO_RETURN(r, n, p) DO_API(r,n,p)
|
||||
#endif
|
||||
|
||||
#pragma region General
|
||||
DO_API(int, il2cpp_init, (const char* domain_name));
|
||||
DO_API(int, il2cpp_init_utf16, (const Il2CppChar* domain_name));
|
||||
DO_API(void, il2cpp_shutdown, ());
|
||||
DO_API(void, il2cpp_set_config_dir, (const char* config_path));
|
||||
DO_API(void, il2cpp_set_data_dir, (const char* data_path));
|
||||
DO_API(void, il2cpp_set_temp_dir, (const char* temp_path));
|
||||
DO_API(void, il2cpp_set_commandline_arguments, (int argc, const char* const argv[], const char* basedir));
|
||||
DO_API(void, il2cpp_set_commandline_arguments_utf16, (int argc, const Il2CppChar* const argv[], const char* basedir));
|
||||
DO_API(void, il2cpp_set_config_utf16, (const Il2CppChar* executablePath));
|
||||
DO_API(void, il2cpp_set_config, (const char* executablePath));
|
||||
DO_API(void, il2cpp_set_memory_callbacks, (Il2CppMemoryCallbacks* callbacks));
|
||||
DO_API(const Il2CppImage*, il2cpp_get_corlib, ());
|
||||
DO_API(void, il2cpp_add_internal_call, (const char* name, Il2CppMethodPointer method));
|
||||
DO_API(Il2CppMethodPointer, il2cpp_resolve_icall, (const char* name));
|
||||
DO_API(void*, il2cpp_alloc, (size_t size));
|
||||
DO_API(void, il2cpp_free, (void* ptr));
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Array
|
||||
DO_API(Il2CppClass*, il2cpp_array_class_get, (Il2CppClass* element_class, uint32_t rank));
|
||||
DO_API(uint32_t, il2cpp_array_length, (Il2CppArray* array));
|
||||
DO_API(uint32_t, il2cpp_array_get_byte_length, (Il2CppArray* array));
|
||||
DO_API(Il2CppArray*, il2cpp_array_new, (Il2CppClass* elementTypeInfo, il2cpp_array_size_t length));
|
||||
DO_API(Il2CppArray*, il2cpp_array_new_specific, (Il2CppClass* arrayTypeInfo, il2cpp_array_size_t length));
|
||||
DO_API(Il2CppArray*, il2cpp_array_new_full, (Il2CppClass* array_class, il2cpp_array_size_t* lengths, il2cpp_array_size_t* lower_bounds));
|
||||
DO_API(Il2CppClass*, il2cpp_bounded_array_class_get, (Il2CppClass* element_class, uint32_t rank, bool bounded));
|
||||
DO_API(int, il2cpp_array_element_size, (const Il2CppClass* array_class));
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Assembly
|
||||
DO_API(const Il2CppImage*, il2cpp_assembly_get_image, (const Il2CppAssembly* assembly));
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Class
|
||||
DO_API(void, il2cpp_class_for_each, (void(*klassReportFunc)(Il2CppClass* klass, void* userData), void* userData));
|
||||
DO_API(const Il2CppType*, il2cpp_class_enum_basetype, (Il2CppClass* klass));
|
||||
DO_API(bool, il2cpp_class_is_generic, (const Il2CppClass* klass));
|
||||
DO_API(bool, il2cpp_class_is_inflated, (const Il2CppClass* klass));
|
||||
DO_API(bool, il2cpp_class_is_assignable_from, (Il2CppClass* klass, Il2CppClass* oklass));
|
||||
DO_API(bool, il2cpp_class_is_subclass_of, (Il2CppClass* klass, Il2CppClass* klassc, bool check_interfaces));
|
||||
DO_API(bool, il2cpp_class_has_parent, (Il2CppClass* klass, Il2CppClass* klassc));
|
||||
DO_API(Il2CppClass*, il2cpp_class_from_il2cpp_type, (const Il2CppType* type));
|
||||
DO_API(Il2CppClass*, il2cpp_class_from_name, (const Il2CppImage* image, const char* namespaze, const char* name));
|
||||
DO_API(Il2CppClass*, il2cpp_class_from_system_type, (Il2CppReflectionType* type));
|
||||
DO_API(Il2CppClass*, il2cpp_class_get_element_class, (Il2CppClass* klass));
|
||||
DO_API(const EventInfo*, il2cpp_class_get_events, (Il2CppClass* klass, void** iter));
|
||||
DO_API(FieldInfo*, il2cpp_class_get_fields, (Il2CppClass* klass, void** iter));
|
||||
DO_API(Il2CppClass*, il2cpp_class_get_nested_types, (Il2CppClass* klass, void** iter));
|
||||
DO_API(Il2CppClass*, il2cpp_class_get_interfaces, (Il2CppClass* klass, void** iter));
|
||||
DO_API(const PropertyInfo*, il2cpp_class_get_properties, (Il2CppClass* klass, void** iter));
|
||||
DO_API(const PropertyInfo*, il2cpp_class_get_property_from_name, (Il2CppClass* klass, const char* name));
|
||||
DO_API(FieldInfo*, il2cpp_class_get_field_from_name, (Il2CppClass* klass, const char* name));
|
||||
DO_API(const MethodInfo*, il2cpp_class_get_methods, (Il2CppClass* klass, void** iter));
|
||||
DO_API(const MethodInfo*, il2cpp_class_get_method_from_name, (Il2CppClass* klass, const char* name, int argsCount));
|
||||
DO_API(const char*, il2cpp_class_get_name, (Il2CppClass* klass));
|
||||
DO_API(void, il2cpp_type_get_name_chunked, (const Il2CppType* type, void(*chunkReportFunc)(void* data, void* userData), void* userData));
|
||||
DO_API(const char*, il2cpp_class_get_namespace, (Il2CppClass* klass));
|
||||
DO_API(Il2CppClass*, il2cpp_class_get_parent, (Il2CppClass* klass));
|
||||
DO_API(Il2CppClass*, il2cpp_class_get_declaring_type, (Il2CppClass* klass));
|
||||
DO_API(int32_t, il2cpp_class_instance_size, (Il2CppClass* klass));
|
||||
DO_API(size_t, il2cpp_class_num_fields, (const Il2CppClass* enumKlass));
|
||||
DO_API(bool, il2cpp_class_is_valuetype, (const Il2CppClass* klass));
|
||||
DO_API(int32_t, il2cpp_class_value_size, (Il2CppClass* klass, uint32_t* align));
|
||||
DO_API(bool, il2cpp_class_is_blittable, (const Il2CppClass* klass));
|
||||
DO_API(int, il2cpp_class_get_flags, (const Il2CppClass* klass));
|
||||
DO_API(bool, il2cpp_class_is_abstract, (const Il2CppClass* klass));
|
||||
DO_API(bool, il2cpp_class_is_interface, (const Il2CppClass* klass));
|
||||
DO_API(int, il2cpp_class_array_element_size, (const Il2CppClass* klass));
|
||||
DO_API(Il2CppClass*, il2cpp_class_from_type, (const Il2CppType* type));
|
||||
DO_API(const Il2CppType*, il2cpp_class_get_type, (Il2CppClass* klass));
|
||||
DO_API(uint32_t, il2cpp_class_get_type_token, (Il2CppClass* klass));
|
||||
DO_API(bool, il2cpp_class_has_attribute, (Il2CppClass* klass, Il2CppClass* attr_class));
|
||||
DO_API(bool, il2cpp_class_has_references, (Il2CppClass* klass));
|
||||
DO_API(bool, il2cpp_class_is_enum, (const Il2CppClass* klass));
|
||||
DO_API(const Il2CppImage*, il2cpp_class_get_image, (Il2CppClass* klass));
|
||||
DO_API(const char*, il2cpp_class_get_assemblyname, (const Il2CppClass* klass));
|
||||
DO_API(int, il2cpp_class_get_rank, (const Il2CppClass* klass));
|
||||
DO_API(uint32_t, il2cpp_class_get_data_size, (const Il2CppClass* klass));
|
||||
DO_API(void*, il2cpp_class_get_static_field_data, (const Il2CppClass* klass));
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Stats
|
||||
DO_API(bool, il2cpp_stats_dump_to_file, (const char* path));
|
||||
DO_API(uint64_t, il2cpp_stats_get_value, (Il2CppStat stat));
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Domain
|
||||
DO_API(Il2CppDomain*, il2cpp_domain_get, ());
|
||||
DO_API(const Il2CppAssembly*, il2cpp_domain_assembly_open, (Il2CppDomain* domain, const char* name));
|
||||
DO_API(const Il2CppAssembly**, il2cpp_domain_get_assemblies, (const Il2CppDomain* domain, size_t* size));
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Exception
|
||||
DO_API_NO_RETURN(void, il2cpp_raise_exception, (Il2CppException*));
|
||||
DO_API(Il2CppException*, il2cpp_exception_from_name_msg, (const Il2CppImage* image, const char* name_space, const char* name, const char* msg));
|
||||
DO_API(Il2CppException*, il2cpp_get_exception_argument_null, (const char* arg));
|
||||
DO_API(void, il2cpp_format_exception, (const Il2CppException* ex, char* message, int message_size));
|
||||
DO_API(void, il2cpp_format_stack_trace, (const Il2CppException* ex, char* output, int output_size));
|
||||
DO_API(void, il2cpp_unhandled_exception, (Il2CppException*));
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Field
|
||||
DO_API(int, il2cpp_field_get_flags, (FieldInfo* field));
|
||||
DO_API(const char*, il2cpp_field_get_name, (FieldInfo* field));
|
||||
DO_API(Il2CppClass*, il2cpp_field_get_parent, (FieldInfo* field));
|
||||
DO_API(size_t, il2cpp_field_get_offset, (FieldInfo* field));
|
||||
DO_API(const Il2CppType*, il2cpp_field_get_type, (FieldInfo* field));
|
||||
DO_API(void, il2cpp_field_get_value, (Il2CppObject* obj, FieldInfo* field, void* value));
|
||||
DO_API(Il2CppObject*, il2cpp_field_get_value_object, (FieldInfo* field, Il2CppObject* obj));
|
||||
DO_API(bool, il2cpp_field_has_attribute, (FieldInfo* field, Il2CppClass* attr_class));
|
||||
DO_API(void, il2cpp_field_set_value, (Il2CppObject* obj, FieldInfo* field, void* value));
|
||||
DO_API(void, il2cpp_field_static_get_value, (FieldInfo* field, void* value));
|
||||
DO_API(void, il2cpp_field_static_set_value, (FieldInfo* field, void* value));
|
||||
DO_API(void, il2cpp_field_set_value_object, (Il2CppObject* instance, FieldInfo* field, Il2CppObject* value));
|
||||
DO_API(bool, il2cpp_field_is_literal, (FieldInfo* field));
|
||||
#pragma endregion
|
||||
|
||||
#pragma region GC
|
||||
DO_API(void, il2cpp_gc_collect, (int maxGenerations));
|
||||
DO_API(int32_t, il2cpp_gc_collect_a_little, ());
|
||||
DO_API(void, il2cpp_gc_disable, ());
|
||||
DO_API(void, il2cpp_gc_enable, ());
|
||||
DO_API(bool, il2cpp_gc_is_disabled, ());
|
||||
DO_API(int64_t, il2cpp_gc_get_max_time_slice_ns, ());
|
||||
DO_API(void, il2cpp_gc_set_max_time_slice_ns, (int64_t maxTimeSlice));
|
||||
DO_API(bool, il2cpp_gc_is_incremental, ());
|
||||
DO_API(int64_t, il2cpp_gc_get_used_size, ());
|
||||
DO_API(int64_t, il2cpp_gc_get_heap_size, ());
|
||||
DO_API(void, il2cpp_gc_wbarrier_set_field, (Il2CppObject* obj, void** targetAddress, void* object));
|
||||
DO_API(bool, il2cpp_gc_has_strict_wbarriers, ());
|
||||
DO_API(void, il2cpp_gc_set_external_allocation_tracker, (void(*func)(void*, size_t, int)));
|
||||
DO_API(void, il2cpp_gc_set_external_wbarrier_tracker, (void(*func)(void**)));
|
||||
DO_API(void, il2cpp_gc_foreach_heap, (void(*func)(void* data, void* userData), void* userData));
|
||||
DO_API(void, il2cpp_stop_gc_world, ());
|
||||
DO_API(void, il2cpp_start_gc_world, ());
|
||||
#pragma endregion
|
||||
|
||||
#pragma region GCHandle
|
||||
DO_API(uint32_t, il2cpp_gchandle_new, (Il2CppObject* obj, bool pinned));
|
||||
DO_API(uint32_t, il2cpp_gchandle_new_weakref, (Il2CppObject* obj, bool track_resurrection));
|
||||
DO_API(Il2CppObject*, il2cpp_gchandle_get_target, (uint32_t gchandle));
|
||||
DO_API(void, il2cpp_gchandle_free, (uint32_t gchandle));
|
||||
DO_API(void, il2cpp_gchandle_foreach_get_target, (void(*func)(void* data, void* userData), void* userData));
|
||||
#pragma endregion
|
||||
|
||||
#pragma region VMRuntimeInfo
|
||||
DO_API(uint32_t, il2cpp_object_header_size, ());
|
||||
DO_API(uint32_t, il2cpp_array_object_header_size, ());
|
||||
DO_API(uint32_t, il2cpp_offset_of_array_length_in_array_object_header, ());
|
||||
DO_API(uint32_t, il2cpp_offset_of_array_bounds_in_array_object_header, ());
|
||||
DO_API(uint32_t, il2cpp_allocation_granularity, ());
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Liveness
|
||||
DO_API(void*, il2cpp_unity_liveness_calculation_begin, (Il2CppClass* filter, int max_object_count, il2cpp_register_object_callback callback, void* userdata, il2cpp_WorldChangedCallback onWorldStarted, il2cpp_WorldChangedCallback onWorldStopped));
|
||||
DO_API(void, il2cpp_unity_liveness_calculation_end, (void* state));
|
||||
DO_API(void, il2cpp_unity_liveness_calculation_from_root, (Il2CppObject* root, void* state));
|
||||
DO_API(void, il2cpp_unity_liveness_calculation_from_statics, (void* state));
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Method
|
||||
DO_API(const Il2CppType*, il2cpp_method_get_return_type, (const MethodInfo* method));
|
||||
DO_API(Il2CppClass*, il2cpp_method_get_declaring_type, (const MethodInfo* method));
|
||||
DO_API(const char*, il2cpp_method_get_name, (const MethodInfo* method));
|
||||
DO_API(const MethodInfo*, il2cpp_method_get_from_reflection, (const Il2CppReflectionMethod* method));
|
||||
DO_API(Il2CppReflectionMethod*, il2cpp_method_get_object, (const MethodInfo* method, Il2CppClass* refclass));
|
||||
DO_API(bool, il2cpp_method_is_generic, (const MethodInfo* method));
|
||||
DO_API(bool, il2cpp_method_is_inflated, (const MethodInfo* method));
|
||||
DO_API(bool, il2cpp_method_is_instance, (const MethodInfo* method));
|
||||
DO_API(uint32_t, il2cpp_method_get_param_count, (const MethodInfo* method));
|
||||
DO_API(const Il2CppType*, il2cpp_method_get_param, (const MethodInfo* method, uint32_t index));
|
||||
DO_API(Il2CppClass*, il2cpp_method_get_class, (const MethodInfo* method));
|
||||
DO_API(bool, il2cpp_method_has_attribute, (const MethodInfo* method, Il2CppClass* attr_class));
|
||||
DO_API(uint32_t, il2cpp_method_get_flags, (const MethodInfo* method, uint32_t* iflags));
|
||||
DO_API(uint32_t, il2cpp_method_get_token, (const MethodInfo* method));
|
||||
DO_API(const char*, il2cpp_method_get_param_name, (const MethodInfo* method, uint32_t index));
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Property
|
||||
DO_API(uint32_t, il2cpp_property_get_flags, (PropertyInfo* prop));
|
||||
DO_API(const MethodInfo*, il2cpp_property_get_get_method, (PropertyInfo* prop));
|
||||
DO_API(const MethodInfo*, il2cpp_property_get_set_method, (PropertyInfo* prop));
|
||||
DO_API(const char*, il2cpp_property_get_name, (PropertyInfo* prop));
|
||||
DO_API(Il2CppClass*, il2cpp_property_get_parent, (PropertyInfo* prop));
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Object
|
||||
DO_API(Il2CppClass*, il2cpp_object_get_class, (Il2CppObject* obj));
|
||||
DO_API(uint32_t, il2cpp_object_get_size, (Il2CppObject* obj));
|
||||
DO_API(const MethodInfo*, il2cpp_object_get_virtual_method, (Il2CppObject* obj, const MethodInfo* method));
|
||||
DO_API(Il2CppObject*, il2cpp_object_new, (const Il2CppClass* klass));
|
||||
DO_API(void*, il2cpp_object_unbox, (Il2CppObject* obj));
|
||||
DO_API(Il2CppObject*, il2cpp_value_box, (Il2CppClass* klass, void* data));
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Monitor
|
||||
DO_API(void, il2cpp_monitor_enter, (Il2CppObject* obj));
|
||||
DO_API(bool, il2cpp_monitor_try_enter, (Il2CppObject* obj, uint32_t timeout));
|
||||
DO_API(void, il2cpp_monitor_exit, (Il2CppObject* obj));
|
||||
DO_API(void, il2cpp_monitor_pulse, (Il2CppObject* obj));
|
||||
DO_API(void, il2cpp_monitor_pulse_all, (Il2CppObject* obj));
|
||||
DO_API(void, il2cpp_monitor_wait, (Il2CppObject* obj));
|
||||
DO_API(bool, il2cpp_monitor_try_wait, (Il2CppObject* obj, uint32_t timeout));
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Runtime
|
||||
DO_API(Il2CppObject*, il2cpp_runtime_invoke, (const MethodInfo* method, void* obj, void** params, Il2CppException** exc));
|
||||
DO_API(Il2CppObject*, il2cpp_runtime_invoke_convert_args, (const MethodInfo* method, void* obj, Il2CppObject** params, int paramCount, Il2CppException** exc));
|
||||
DO_API(void, il2cpp_runtime_class_init, (Il2CppClass* klass));
|
||||
DO_API(void, il2cpp_runtime_object_init, (Il2CppObject* obj));
|
||||
DO_API(void, il2cpp_runtime_object_init_exception, (Il2CppObject* obj, Il2CppException** exc));
|
||||
DO_API(void, il2cpp_runtime_unhandled_exception_policy_set, (Il2CppRuntimeUnhandledExceptionPolicy value));
|
||||
#pragma endregion
|
||||
|
||||
#pragma region String
|
||||
DO_API(int32_t, il2cpp_string_length, (Il2CppString* str));
|
||||
DO_API(Il2CppChar*, il2cpp_string_chars, (Il2CppString* str));
|
||||
DO_API(Il2CppString*, il2cpp_string_new, (const char* str));
|
||||
DO_API(Il2CppString*, il2cpp_string_new_len, (const char* str, uint32_t length));
|
||||
DO_API(Il2CppString*, il2cpp_string_new_utf16, (const Il2CppChar* text, int32_t len));
|
||||
DO_API(Il2CppString*, il2cpp_string_new_wrapper, (const char* str));
|
||||
DO_API(Il2CppString*, il2cpp_string_intern, (Il2CppString* str));
|
||||
DO_API(Il2CppString*, il2cpp_string_is_interned, (Il2CppString* str));
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Thread
|
||||
DO_API(Il2CppThread*, il2cpp_thread_current, ());
|
||||
DO_API(Il2CppThread*, il2cpp_thread_attach, (Il2CppDomain* domain));
|
||||
DO_API(void, il2cpp_thread_detach, (Il2CppThread* thread));
|
||||
DO_API(Il2CppThread**, il2cpp_thread_get_all_attached_threads, (size_t* size));
|
||||
DO_API(bool, il2cpp_is_vm_thread, (Il2CppThread* thread));
|
||||
#pragma endregion
|
||||
|
||||
#pragma region StackTrace
|
||||
DO_API(void, il2cpp_current_thread_walk_frame_stack, (Il2CppFrameWalkFunc func, void* user_data));
|
||||
DO_API(void, il2cpp_thread_walk_frame_stack, (Il2CppThread* thread, Il2CppFrameWalkFunc func, void* user_data));
|
||||
DO_API(bool, il2cpp_current_thread_get_top_frame, (Il2CppStackFrameInfo* frame));
|
||||
DO_API(bool, il2cpp_thread_get_top_frame, (Il2CppThread* thread, Il2CppStackFrameInfo* frame));
|
||||
DO_API(bool, il2cpp_current_thread_get_frame_at, (int32_t offset, Il2CppStackFrameInfo* frame));
|
||||
DO_API(bool, il2cpp_thread_get_frame_at, (Il2CppThread* thread, int32_t offset, Il2CppStackFrameInfo* frame));
|
||||
DO_API(int32_t, il2cpp_current_thread_get_stack_depth, ());
|
||||
DO_API(int32_t, il2cpp_thread_get_stack_depth, (Il2CppThread* thread));
|
||||
DO_API(void, il2cpp_override_stack_backtrace, (Il2CppBacktraceFunc stackBacktraceFunc));
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Type
|
||||
DO_API(Il2CppObject*, il2cpp_type_get_object, (const Il2CppType* type));
|
||||
DO_API(int, il2cpp_type_get_type, (const Il2CppType* type));
|
||||
DO_API(Il2CppClass*, il2cpp_type_get_class_or_element_class, (const Il2CppType* type));
|
||||
DO_API(char*, il2cpp_type_get_name, (const Il2CppType* type));
|
||||
DO_API(bool, il2cpp_type_is_byref, (const Il2CppType* type));
|
||||
DO_API(uint32_t, il2cpp_type_get_attrs, (const Il2CppType* type));
|
||||
DO_API(bool, il2cpp_type_equals, (const Il2CppType* type, const Il2CppType* otherType));
|
||||
DO_API(char*, il2cpp_type_get_assembly_qualified_name, (const Il2CppType* type));
|
||||
DO_API(bool, il2cpp_type_is_static, (const Il2CppType* type));
|
||||
DO_API(bool, il2cpp_type_is_pointer_type, (const Il2CppType* type));
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Image
|
||||
DO_API(const Il2CppAssembly*, il2cpp_image_get_assembly, (const Il2CppImage* image));
|
||||
DO_API(const char*, il2cpp_image_get_name, (const Il2CppImage* image));
|
||||
DO_API(const char*, il2cpp_image_get_filename, (const Il2CppImage* image));
|
||||
DO_API(const MethodInfo*, il2cpp_image_get_entry_point, (const Il2CppImage* image));
|
||||
DO_API(size_t, il2cpp_image_get_class_count, (const Il2CppImage* image));
|
||||
DO_API(const Il2CppClass*, il2cpp_image_get_class, (const Il2CppImage* image, size_t index));
|
||||
#pragma endregion
|
||||
|
||||
#pragma region MemoryInformation
|
||||
DO_API(Il2CppManagedMemorySnapshot*, il2cpp_capture_memory_snapshot, ());
|
||||
DO_API(void, il2cpp_free_captured_memory_snapshot, (Il2CppManagedMemorySnapshot* snapshot));
|
||||
DO_API(void, il2cpp_set_find_plugin_callback, (Il2CppSetFindPlugInCallback method));
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Logging
|
||||
DO_API(void, il2cpp_register_log_callback, (Il2CppLogCallback method));
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Debugger
|
||||
DO_API(void, il2cpp_debugger_set_agent_options, (const char* options));
|
||||
DO_API(bool, il2cpp_is_debugger_attached, ());
|
||||
DO_API(void, il2cpp_register_debugger_agent_transport, (Il2CppDebuggerTransport* debuggerTransport));
|
||||
#pragma endregion
|
||||
|
||||
#pragma region DebugMetadata
|
||||
DO_API(bool, il2cpp_debug_get_method_info, (const MethodInfo*, Il2CppMethodDebugInfo* methodDebugInfo));
|
||||
#pragma endregion
|
||||
|
||||
#pragma region TLSModule
|
||||
DO_API(void, il2cpp_unity_install_unitytls_interface, (const void* unitytlsInterfaceStruct));
|
||||
#pragma endregion
|
||||
|
||||
#pragma region CustomAttributes
|
||||
DO_API(Il2CppCustomAttrInfo*, il2cpp_custom_attrs_from_class, (Il2CppClass* klass));
|
||||
DO_API(Il2CppCustomAttrInfo*, il2cpp_custom_attrs_from_method, (const MethodInfo* method));
|
||||
DO_API(Il2CppObject*, il2cpp_custom_attrs_get_attr, (Il2CppCustomAttrInfo* ainfo, Il2CppClass* attr_klass));
|
||||
DO_API(bool, il2cpp_custom_attrs_has_attr, (Il2CppCustomAttrInfo* ainfo, Il2CppClass* attr_klass));
|
||||
DO_API(Il2CppArray*, il2cpp_custom_attrs_construct, (Il2CppCustomAttrInfo* cinfo));
|
||||
DO_API(void, il2cpp_custom_attrs_free, (Il2CppCustomAttrInfo* ainfo));
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Il2CppClassUserDataForGetComponentOptimization
|
||||
DO_API(int, il2cpp_class_get_userdata_offset, ());
|
||||
DO_API(void, il2cpp_class_set_userdata, (Il2CppClass* klass, void* userdata));
|
||||
DO_API(void, il2cpp_set_default_thread_affinity, (int64_t affinity_mask));
|
||||
#pragma endregion
|
||||
20
lib/src/il2cpp-appdata.h
Normal file
20
lib/src/il2cpp-appdata.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
#include "il2cpp-types.h"
|
||||
|
||||
// IL2CPP APIs
|
||||
#define DO_API(r, n, p) extern r (*n) p
|
||||
#include "il2cpp-api-functions.h"
|
||||
#undef DO_API
|
||||
|
||||
// Application-specific functions
|
||||
#define DO_APP_FUNC(ca, oa, r, n, p) extern r (*n) p
|
||||
namespace Genshin {
|
||||
#include "il2cpp-functions.h"
|
||||
}
|
||||
#undef DO_APP_FUNC
|
||||
|
||||
#define DO_UNI_FUNC(ca, oa, r, n, p) extern r (*n) p
|
||||
namespace Genshin {
|
||||
#include "il2cpp-unity-functions.h"
|
||||
}
|
||||
#undef DO_UNI_FUNC
|
||||
10
lib/src/il2cpp-functions.h
Normal file
10
lib/src/il2cpp-functions.h
Normal file
@@ -0,0 +1,10 @@
|
||||
using namespace Genshin;
|
||||
|
||||
DO_APP_FUNC(0x05254960, 0x052544E0, Il2CppString*, Convert_ToBase64String, (ByteArray* value, int offset, int length, void* method));
|
||||
DO_APP_FUNC(0x020127B0, 0x02012D40, void, Packet_Xor, (ByteArray** data, int length, void* method));
|
||||
|
||||
DO_APP_FUNC(0X01AD8E40, 0x01AD9740, void, MonoLoginMainPage__set_version, (void* obj, Il2CppString* value, void* method));
|
||||
DO_APP_FUNC(0x05C25AC0, 0x05C25E60, ByteArray*, Application_RecordUserData, (int32_t nType, void* method));
|
||||
|
||||
DO_APP_FUNC(0x015C19D0, 0x015C2150, int, Kcp_Send, (void* client, KcpPacket* pkt, void* method));
|
||||
DO_APP_FUNC(0x02CF31D0, 0x02CF33A0, bool, Kcp_Recv, (void* client, ClientKcpEvent* evt, void* method));
|
||||
44
lib/src/il2cpp-init.cpp
Normal file
44
lib/src/il2cpp-init.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include "il2cpp-init.h"
|
||||
|
||||
#define DO_API(r, n, p) r (*n) p
|
||||
#include "il2cpp-api-functions.h"
|
||||
#undef DO_API
|
||||
|
||||
#define DO_APP_FUNC(ca, oa, r, n, p) r (*n) p
|
||||
namespace Genshin {
|
||||
#include "il2cpp-functions.h"
|
||||
}
|
||||
#undef DO_APP_FUNC
|
||||
|
||||
#define DO_UNI_FUNC(ca, oa, r, n, p) r (*n) p
|
||||
namespace Genshin {
|
||||
#include "il2cpp-unity-functions.h"
|
||||
}
|
||||
#undef DO_UNI_FUNC
|
||||
|
||||
using std::string;
|
||||
|
||||
UINT64 GetAddressByExports(HMODULE base, const char* name) {
|
||||
UINT64 funcAddr = reinterpret_cast<UINT64>(GetProcAddress(base, name));
|
||||
return funcAddr == 0 ? 0 : funcAddr;
|
||||
}
|
||||
|
||||
void InitIL2CPP() {
|
||||
TCHAR szFileName[MAX_PATH];
|
||||
GetModuleFileName(NULL, szFileName, MAX_PATH);
|
||||
auto isCN = strstr(szFileName, "YuanShen.exe");//string(szFileName).contains();
|
||||
auto hBase = GetModuleHandle("UserAssembly.dll");
|
||||
auto bAddr = (UINT64)hBase;
|
||||
auto cAddr = (UINT64)GetModuleHandle("UnityPlayer.dll");
|
||||
#define DO_API(r, n, p) n = (r (*) p) GetAddressByExports(hBase, #n);
|
||||
#include "il2cpp-api-functions.h"
|
||||
#undef DO_API
|
||||
#define DO_APP_FUNC(ca, oa, r, n, p) n = (r (*) p)(bAddr + (isCN ? ca : oa))
|
||||
#include "il2cpp-functions.h"
|
||||
#undef DO_APP_FUNC
|
||||
#define DO_UNI_FUNC(ca, oa, r, n, p) n = (r (*) p)(cAddr + (isCN ? ca : oa))
|
||||
#include "il2cpp-unity-functions.h"
|
||||
#undef DO_UNI_FUNC
|
||||
}
|
||||
4
lib/src/il2cpp-init.h
Normal file
4
lib/src/il2cpp-init.h
Normal file
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
// IL2CPP application initializer
|
||||
void InitIL2CPP();
|
||||
2386
lib/src/il2cpp-types.h
Normal file
2386
lib/src/il2cpp-types.h
Normal file
File diff suppressed because it is too large
Load Diff
3
lib/src/il2cpp-unity-functions.h
Normal file
3
lib/src/il2cpp-unity-functions.h
Normal file
@@ -0,0 +1,3 @@
|
||||
using namespace Genshin;
|
||||
|
||||
DO_UNI_FUNC(0x00B9D710, 0x00B9D710, ByteArray*, UnityEngine_RecordUserData, (int32_t nType));
|
||||
1
lib/src/pch.cpp
Normal file
1
lib/src/pch.cpp
Normal file
@@ -0,0 +1 @@
|
||||
#include "pch.h"
|
||||
27
lib/src/pch.h
Normal file
27
lib/src/pch.h
Normal file
@@ -0,0 +1,27 @@
|
||||
// pch.h: 这是预编译标头文件。
|
||||
// 下方列出的文件仅编译一次,提高了将来生成的生成性能。
|
||||
// 这还将影响 IntelliSense 性能,包括代码完成和许多代码浏览功能。
|
||||
// 但是,如果此处列出的文件中的任何一个在生成之间有更新,它们全部都将被重新编译。
|
||||
// 请勿在此处添加要频繁更新的文件,这将使得性能优势无效。
|
||||
|
||||
#ifndef PCH_H
|
||||
#define PCH_H
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN // 从 Windows 头文件中排除极少使用的内容
|
||||
// Windows 头文件
|
||||
#include <windows.h>
|
||||
|
||||
// 添加要在此处预编译的标头
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <codecvt>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <detours.h>
|
||||
#include "HookManager.h"
|
||||
#include "il2cpp-appdata.h"
|
||||
|
||||
#endif //PCH_H
|
||||
67
lib/src/util.cpp
Normal file
67
lib/src/util.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
#include "pch.h"
|
||||
#include "util.h"
|
||||
|
||||
#pragma region StringConvert
|
||||
|
||||
string IlStringToString(Il2CppString* str, UINT codePage) {
|
||||
auto chars = reinterpret_cast<const wchar_t*>(str->chars);
|
||||
auto len = WideCharToMultiByte(codePage, 0, chars, -1, nullptr, 0, nullptr, nullptr);
|
||||
auto buffer = new char[len];
|
||||
WideCharToMultiByte(codePage, 0, chars, -1, buffer, len, nullptr, nullptr);
|
||||
return string(buffer);
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region GC
|
||||
|
||||
UINT32 GCHandle_New(void* object, bool pinned) {
|
||||
return il2cpp_gchandle_new((Il2CppObject*)object, pinned);
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region ByteUtils
|
||||
|
||||
bool IsLittleEndian() {
|
||||
UINT i = 1;
|
||||
char* c = (char*)&i;
|
||||
return (*c);
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region FindMainWindowByPID
|
||||
|
||||
struct HandleData {
|
||||
DWORD pid;
|
||||
HWND hwnd;
|
||||
};
|
||||
|
||||
BOOL IsMainWindow(HWND handle) {
|
||||
return GetWindow(handle, GW_OWNER) == (HWND)0 && IsWindowVisible(handle) == TRUE;
|
||||
}
|
||||
|
||||
BOOL IsUnityWindow(HWND handle) {
|
||||
TCHAR name[256];
|
||||
GetClassName(handle, name, 256);
|
||||
return _strcmpi(name, "UnityWndClass") == 0;
|
||||
}
|
||||
|
||||
BOOL CALLBACK EnumWindowsCallback(HWND handle, LPARAM lParam) {
|
||||
HandleData& data = *(HandleData*)lParam;
|
||||
DWORD pid = 0;
|
||||
GetWindowThreadProcessId(handle, &pid);
|
||||
if (data.pid != pid || !IsMainWindow(handle) || !IsUnityWindow(handle))
|
||||
return TRUE;
|
||||
data.hwnd = handle;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
HWND FindMainWindowByPID(DWORD pid) {
|
||||
HandleData data = { pid, 0 };
|
||||
EnumWindows(EnumWindowsCallback, (LPARAM)&data);
|
||||
return data.hwnd;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
33
lib/src/util.h
Normal file
33
lib/src/util.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
using std::string;
|
||||
|
||||
bool IsLittleEndian();
|
||||
HWND FindMainWindowByPID(DWORD pid);
|
||||
UINT32 GCHandle_New(LPVOID object, bool pinned);
|
||||
string IlStringToString(Il2CppString* str, UINT codePage = CP_ACP);
|
||||
|
||||
#define cstring_new(str) il2cpp_string_new(str)
|
||||
#define string_new(str) cstring_new((str).c_str())
|
||||
|
||||
#define ErrorDialogT(title, msg) MessageBox(unityWnd, msg, title, MB_OK | MB_ICONERROR | MB_SYSTEMMODAL);
|
||||
#define ErrorDialog(msg) ErrorDialogT("YaeAchievement", msg)
|
||||
#define Win32ErrorDialog(code) ErrorDialogT("YaeAchievement", ("CRITICAL ERROR!\nError code: " + std::to_string(GetLastError()) + "-"#code"\n\nPlease take the screenshot and contact developer by GitHub Issue to solve this problem\nNOT MIHOYO/COGNOSPHERE CUSTOMER SERVICE!").c_str())
|
||||
|
||||
template<class T>
|
||||
static T ReadMapped(void* data, int offset, bool littleEndian = false) {
|
||||
char* cData = (char*)data;
|
||||
T result = {};
|
||||
if (IsLittleEndian() != littleEndian) {
|
||||
for (int i = 0; i < sizeof(T); i++)
|
||||
((char*)&result)[i] = cData[offset + sizeof(T) - i - 1];
|
||||
return result;
|
||||
}
|
||||
memcpy(&result, cData + offset, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
static T* GCHandle_GetObject(UINT handle) {
|
||||
return (T*) il2cpp_gchandle_get_target(handle);
|
||||
}
|
||||
9
native.d.ts
vendored
9
native.d.ts
vendored
@@ -1,9 +0,0 @@
|
||||
export function selectGameExecutable(): string
|
||||
export function checkGameIsRunning(processName: string): boolean
|
||||
export function whoUseThePort(port: number): object
|
||||
export function copyToClipboard(value: string): any
|
||||
export function enablePrivilege(): any
|
||||
export function getDeviceInfo(): any
|
||||
export function getDeviceID(): string
|
||||
export function openUrl(url: string): number
|
||||
export function pause(): any
|
||||
5
native/.gitignore
vendored
5
native/.gitignore
vendored
@@ -1,5 +0,0 @@
|
||||
CMakeLists.txt
|
||||
.idea
|
||||
cmake-build-debug
|
||||
node_modules
|
||||
build
|
||||
@@ -1,42 +0,0 @@
|
||||
{
|
||||
"targets": [
|
||||
{
|
||||
"target_name": "native",
|
||||
"sources": [
|
||||
"src/main.cc",
|
||||
"src/utils.h",
|
||||
"src/utils.cc",
|
||||
"src/define.h",
|
||||
"src/wmi/wmi.cpp",
|
||||
"src/wmi/wmi.hpp",
|
||||
"src/wmi/unistd.h",
|
||||
"src/wmi/wmiresult.cpp",
|
||||
"src/wmi/wmiresult.hpp",
|
||||
"src/wmi/wmiclasses.hpp",
|
||||
"src/wmi/wmiexception.hpp",
|
||||
"src/registry/registry.hpp"
|
||||
],
|
||||
"cflags!": [
|
||||
"-fno-exceptions"
|
||||
],
|
||||
"cflags_cc!": [
|
||||
"-fno-exceptions"
|
||||
],
|
||||
"defines": [
|
||||
"NAPI_DISABLE_CPP_EXCEPTIONS"
|
||||
],
|
||||
"include_dirs": [
|
||||
"<!(node -p \"require('node-addon-api').include_dir\")"
|
||||
],
|
||||
"msvs_settings": {
|
||||
"VCCLCompilerTool": {
|
||||
"AdditionalOptions": [
|
||||
"-std:c++latest",
|
||||
"-DUNICODE",
|
||||
"-sdl"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"name": "genshin-export-native",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"scripts": {
|
||||
"build": "node-gyp rebuild && copy .\\build\\Release\\native.node ..\\genshin-export\\"
|
||||
},
|
||||
"gypfile": true,
|
||||
"devDependencies": {
|
||||
"node-gyp": "^9.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"node-addon-api": "^4.3.0"
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <napi.h>
|
||||
#include <Windows.h>
|
||||
#include <TlHelp32.h>
|
||||
|
||||
using std::string, std::wstring, std::cout, std::to_string;
|
||||
using Napi::Object, Napi::Env, Napi::Function, Napi::Value, Napi::CallbackInfo, Napi::TypeError, Napi::Error;
|
||||
|
||||
typedef unsigned char byte;
|
||||
typedef unsigned long ul;
|
||||
typedef unsigned long long ull;
|
||||
@@ -1,194 +0,0 @@
|
||||
#include "utils.h"
|
||||
#include "define.h"
|
||||
#include "wmi/wmi.hpp"
|
||||
#include "wmi/wmiclasses.hpp"
|
||||
#include "registry/registry.hpp"
|
||||
#include <conio.h>
|
||||
#include <iphlpapi.h>
|
||||
#pragma comment(lib,"ws2_32.lib")
|
||||
#pragma comment(lib,"iphlpapi.lib")
|
||||
|
||||
using Wmi::Win32_ComputerSystem, Wmi::Win32_OperatingSystem, Wmi::retrieveWmi;
|
||||
|
||||
namespace native {
|
||||
|
||||
Value checkGameIsRunning(const CallbackInfo &info) {
|
||||
Env env = info.Env();
|
||||
if (info.Length() != 1 || !info[0].IsString()) {
|
||||
TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException();
|
||||
return env.Undefined();
|
||||
}
|
||||
wstring name = StringToWString(info[0].As<Napi::String>().Utf8Value());
|
||||
bool isRunning = false;
|
||||
PROCESSENTRY32 entry;
|
||||
entry.dwSize = sizeof(entry);
|
||||
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
|
||||
if (Process32First(snapshot, &entry) == TRUE) {
|
||||
while (Process32Next(snapshot, &entry) == TRUE) {
|
||||
if (wstring(entry.szExeFile) == name) {
|
||||
isRunning = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
CloseHandle(snapshot);
|
||||
return Napi::Boolean::New(env, isRunning);
|
||||
}
|
||||
|
||||
Value selectGameExecutable(const CallbackInfo &info) {
|
||||
Env env = info.Env();
|
||||
Napi::String path;
|
||||
if (OpenFile(env, path) != ERROR_SUCCESS) {
|
||||
Error::New(env, "Failed to open file: " + to_string(CommDlgExtendedError())).ThrowAsJavaScriptException();
|
||||
return env.Undefined();
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
Value whoUseThePort(const CallbackInfo &info) {
|
||||
Env env = info.Env();
|
||||
if (info.Length() != 1 || !info[0].IsNumber()) {
|
||||
TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException();
|
||||
return env.Undefined();
|
||||
}
|
||||
DWORD dwSize = 0;
|
||||
PMIB_TCPTABLE_OWNER_PID pTcpTable = nullptr;
|
||||
GetExtendedTcpTable(pTcpTable, &dwSize, TRUE,AF_INET,TCP_TABLE_OWNER_PID_ALL,0);
|
||||
pTcpTable = (PMIB_TCPTABLE_OWNER_PID)new byte[dwSize];
|
||||
if(GetExtendedTcpTable(pTcpTable,&dwSize,TRUE,AF_INET,TCP_TABLE_OWNER_PID_ALL,0) != NO_ERROR) {
|
||||
Error::New(env, "GetExtendedTcpTable failed").ThrowAsJavaScriptException();
|
||||
return env.Undefined();
|
||||
}
|
||||
int port = info[0].As<Napi::Number>().Int32Value();
|
||||
auto nNum = (int)pTcpTable->dwNumEntries;
|
||||
DWORD pid = 0;
|
||||
for(int i = 0; i < nNum; i++) {
|
||||
if (htons(pTcpTable->table[i].dwLocalPort) == port) {
|
||||
pid = pTcpTable->table[i].dwOwningPid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
delete pTcpTable;
|
||||
Value ret = env.Undefined();
|
||||
if (pid != 0) {
|
||||
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
|
||||
if (hProcess == nullptr) {
|
||||
Error::New(env, "OpenProcess error: " + to_string(GetLastError())).ThrowAsJavaScriptException();
|
||||
return env.Undefined();
|
||||
}
|
||||
TCHAR fnBuf[MAX_PATH];
|
||||
DWORD length = MAX_PATH;
|
||||
if (QueryFullProcessImageName(hProcess, 0, fnBuf, &length) == 0) {
|
||||
Error::New(env, "QueryFullProcessImageName error: " + to_string(GetLastError())).ThrowAsJavaScriptException();
|
||||
return env.Undefined();
|
||||
}
|
||||
Object obj = Object::New(env);
|
||||
obj.Set("pid", Napi::Number::New(env, pid));
|
||||
obj.Set("path", Napi::String::New(env, WStringToString(fnBuf)));
|
||||
ret = obj;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
Value getDeviceID(const CallbackInfo &info) {
|
||||
Env env = info.Env();
|
||||
wstring wd;
|
||||
if (RegUtils::GetString(HKEY_CURRENT_USER, L"SOFTWARE\\miHoYoSDK", L"MIHOYOSDK_DEVICE_ID", wd) != ERROR_SUCCESS) {
|
||||
return env.Undefined();
|
||||
}
|
||||
string id = WStringToString(wd);
|
||||
return Napi::String::New(env, id.substr(0, 8) + "-" + id.substr(8, 4) + "-" + id.substr(12, 4) + "-" + id.substr(16, 4) + "-" + id.substr(20, 12));
|
||||
}
|
||||
|
||||
Value getDeviceInfo(const CallbackInfo &info) {
|
||||
Env env = info.Env();
|
||||
HDC desktop = GetDC(nullptr);
|
||||
int sw = GetDeviceCaps(desktop, DESKTOPHORZRES);
|
||||
int sh = GetDeviceCaps(desktop, DESKTOPVERTRES);
|
||||
ReleaseDC(nullptr, desktop);
|
||||
DWORD buildNum = RegUtils::GetInt(env, HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", L"UBR");
|
||||
wstring locale;
|
||||
if (RegUtils::GetString(HKEY_CURRENT_USER, L"Control Panel\\International", L"LocaleName", locale) != ERROR_SUCCESS) {
|
||||
locale = L"zh-CN";
|
||||
}
|
||||
wstring country;
|
||||
if (RegUtils::GetString(HKEY_CURRENT_USER, L"Control Panel\\International\\Geo", L"Name", country) != ERROR_SUCCESS) {
|
||||
country = L"CN";
|
||||
}
|
||||
Object obj = Object::New(env);
|
||||
obj.Set("locale", Napi::String::New(env, WStringToString(locale)));
|
||||
obj.Set("screenSize", Napi::String::New(env, to_string(sw) + "x" + to_string(sh)));
|
||||
obj.Set("carrierCountry", Napi::String::New(env, WStringToString(country)));
|
||||
try {
|
||||
auto computer = retrieveWmi<Win32_ComputerSystem>();
|
||||
obj.Set("model", Napi::String::New(env, computer.Model));
|
||||
obj.Set("oemName", Napi::String::New(env, computer.Manufacturer));
|
||||
} catch (Wmi::WmiException &e) {
|
||||
obj.Set("model", Napi::String::New(env, "Unknown"));
|
||||
obj.Set("oemName", Napi::String::New(env, "Unknown"));
|
||||
}
|
||||
try {
|
||||
auto os = retrieveWmi<Win32_OperatingSystem>();
|
||||
string osv = os.Version;
|
||||
obj.Set("osBuild", Napi::String::New(env, osv + "." + to_string(buildNum)));
|
||||
obj.Set("osVersion", Napi::String::New(env, osv));
|
||||
obj.Set("timeZoneOffset", Napi::Number::New(env, os.CurrentTimeZone));
|
||||
} catch (Wmi::WmiException &e) {
|
||||
obj.Set("osBuild", Napi::String::New(env, "Unknown"));
|
||||
obj.Set("osVersion", Napi::String::New(env, "Unknown"));
|
||||
obj.Set("timeZoneOffset", Napi::Number::New(env, 480));
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
Value enablePrivilege(const CallbackInfo &info) {
|
||||
Env env = info.Env();
|
||||
EnablePrivilege(env, L"SeDebugPrivilege");
|
||||
return env.Undefined();
|
||||
}
|
||||
|
||||
Value copyToClipboard(const CallbackInfo &info) {
|
||||
Env env = info.Env();
|
||||
string text = info[0].As<Napi::String>().Utf8Value();
|
||||
if (OpenClipboard(nullptr)) {
|
||||
EmptyClipboard();
|
||||
HGLOBAL hg = GlobalAlloc(GMEM_MOVEABLE, text.length() + 1);
|
||||
if (hg != nullptr) {
|
||||
memcpy(GlobalLock(hg), text.c_str(), text.length() + 1);
|
||||
GlobalUnlock(hg);
|
||||
SetClipboardData(CF_TEXT, hg);
|
||||
}
|
||||
CloseClipboard();
|
||||
}
|
||||
return env.Undefined();
|
||||
}
|
||||
|
||||
Value pause(const CallbackInfo &info) {
|
||||
while(!_kbhit()) {
|
||||
Sleep(10);
|
||||
}
|
||||
return info.Env().Undefined();
|
||||
}
|
||||
|
||||
Value openUrl(const CallbackInfo &info) {
|
||||
Env env = info.Env();
|
||||
wstring url = StringToWString(info[0].As<Napi::String>().Utf8Value());
|
||||
HINSTANCE retcode = ShellExecute(GetConsoleWindow(), L"open", url.c_str(), nullptr, nullptr, SW_SHOWNORMAL);
|
||||
return Napi::Number::New(env, (INT_PTR)retcode); // NOLINT(cppcoreguidelines-narrowing-conversions)
|
||||
}
|
||||
|
||||
Object init(Env env, Object exports) {
|
||||
exports.Set("pause", Function::New(env, pause));
|
||||
exports.Set("openUrl", Function::New(env, openUrl));
|
||||
exports.Set("getDeviceID", Function::New(env, getDeviceID));
|
||||
exports.Set("getDeviceInfo", Function::New(env, getDeviceInfo));
|
||||
exports.Set("whoUseThePort", Function::New(env, whoUseThePort));
|
||||
exports.Set("copyToClipboard", Function::New(env, copyToClipboard));
|
||||
exports.Set("enablePrivilege", Function::New(env, enablePrivilege));
|
||||
exports.Set("checkGameIsRunning", Function::New(env, checkGameIsRunning));
|
||||
exports.Set("selectGameExecutable", Function::New(env, selectGameExecutable));
|
||||
return exports;
|
||||
}
|
||||
|
||||
NODE_API_MODULE(addon, init)
|
||||
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef REGISTRY_HPP
|
||||
#define REGISTRY_HPP
|
||||
|
||||
#include "../define.h"
|
||||
|
||||
namespace RegUtils {
|
||||
|
||||
DWORD GetInt(Env env, HKEY hKey, const wstring &path, const wstring &value) {
|
||||
DWORD data = 0;
|
||||
DWORD size = sizeof(DWORD);
|
||||
LSTATUS retcode = RegGetValue(hKey, path.c_str(), value.c_str(), RRF_RT_REG_DWORD, nullptr, &data, &size);
|
||||
if (retcode != ERROR_SUCCESS) {
|
||||
Error::New(env, "RegGetValue error: " + to_string(retcode)).ThrowAsJavaScriptException();
|
||||
return 0;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
LSTATUS GetString(HKEY hKey, const wstring &path, const wstring &value, wstring &result) {
|
||||
DWORD size = 0;
|
||||
LSTATUS retcode = RegGetValue(hKey, path.c_str(), value.c_str(), RRF_RT_REG_SZ, nullptr, nullptr, &size);
|
||||
if (retcode != ERROR_SUCCESS) {
|
||||
return retcode;
|
||||
}
|
||||
wstring data;
|
||||
DWORD len = size / sizeof(WCHAR);
|
||||
data.resize(len);
|
||||
retcode = RegGetValue(hKey, path.c_str(), value.c_str(), RRF_RT_REG_SZ, nullptr, &data[0], &size);
|
||||
if (retcode != ERROR_SUCCESS) {
|
||||
return retcode;
|
||||
}
|
||||
data.resize((len-1));
|
||||
result = data;
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
#endif //REGISTRY_HPP
|
||||
@@ -1,80 +0,0 @@
|
||||
#include "utils.h"
|
||||
#include "define.h"
|
||||
|
||||
wstring StringToWString(const string &src) {
|
||||
wstring result;
|
||||
int len = MultiByteToWideChar(CP_ACP, 0, src.c_str(), src.size(), nullptr, 0); // NOLINT(cppcoreguidelines-narrowing-conversions)
|
||||
auto *buffer = new WCHAR[len + 1];
|
||||
MultiByteToWideChar(CP_ACP, 0, src.c_str(), src.size(), buffer, len); // NOLINT(cppcoreguidelines-narrowing-conversions)
|
||||
buffer[len] = '\0';
|
||||
result.append(buffer);
|
||||
delete[] buffer;
|
||||
return result;
|
||||
}
|
||||
|
||||
string WStringToString(const wstring &src) {
|
||||
string result;
|
||||
int len = WideCharToMultiByte(CP_ACP, 0, src.c_str(), src.size(), nullptr, 0, nullptr, nullptr); // NOLINT(cppcoreguidelines-narrowing-conversions)
|
||||
char *buffer = new char[len + 1];
|
||||
WideCharToMultiByte(CP_ACP, 0, src.c_str(), src.size(), buffer, len, nullptr, nullptr); // NOLINT(cppcoreguidelines-narrowing-conversions)
|
||||
buffer[len] = '\0';
|
||||
result.append(buffer);
|
||||
delete[] buffer;
|
||||
return result;
|
||||
}
|
||||
|
||||
void Log(Env env, const string &msg) {
|
||||
auto logFunc = env.Global().Get("console").As<Object>().Get("log").As<Function>();
|
||||
logFunc.Call({ Napi::String::New(env, msg) });
|
||||
}
|
||||
|
||||
void Log(Env env, const wstring &msg) {
|
||||
auto logFunc = env.Global().Get("console").As<Object>().Get("log").As<Function>();
|
||||
logFunc.Call({ Napi::String::New(env, WStringToString(msg)) });
|
||||
}
|
||||
|
||||
LSTATUS OpenFile(Env env, Napi::String &result, HWND parent) {
|
||||
OPENFILENAME open;
|
||||
ZeroMemory(&open, sizeof(open));
|
||||
WCHAR file[32768];
|
||||
file[0]=L'\0';
|
||||
open.Flags = OFN_FILEMUSTEXIST | OFN_NONETWORKBUTTON | OFN_PATHMUSTEXIST | OFN_EXPLORER;
|
||||
open.hwndOwner = parent;
|
||||
open.nMaxFile = 32768;
|
||||
open.lpstrFile = file;
|
||||
open.lpstrTitle = L"选择原神主程序";
|
||||
open.lpstrFilter = L"国服/国际服主程序 (YuanShen/GenshinImpact.exe)\0YuanShen.exe;GenshinImpact.exe\0";
|
||||
open.lStructSize = sizeof(open);
|
||||
if(GetOpenFileName(&open)) {
|
||||
result = Napi::String::New(env, WStringToString(file));
|
||||
return ERROR_SUCCESS;
|
||||
} else {
|
||||
return ERROR_ERRORS_ENCOUNTERED;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL EnablePrivilege(Env env, const wstring &name) {
|
||||
HANDLE hToken;
|
||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) {
|
||||
Error::New(env, "OpenProcessToken error: " + to_string(GetLastError())).ThrowAsJavaScriptException();
|
||||
return FALSE;
|
||||
}
|
||||
TOKEN_PRIVILEGES tp;
|
||||
ZeroMemory(&tp, sizeof(tp));
|
||||
tp.PrivilegeCount = 1;
|
||||
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
||||
if (!LookupPrivilegeValue(nullptr, name.c_str(), &tp.Privileges[0].Luid)) {
|
||||
Error::New(env, "LookupPrivilegeValue error: " + to_string(GetLastError())).ThrowAsJavaScriptException();
|
||||
return FALSE;
|
||||
}
|
||||
if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), nullptr, nullptr)) {
|
||||
Error::New(env, "AdjustTokenPrivileges error: " + to_string(GetLastError())).ThrowAsJavaScriptException();
|
||||
return FALSE;
|
||||
}
|
||||
if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) {
|
||||
Error::New(env, "The token does not have the specified privilege.").ThrowAsJavaScriptException();
|
||||
return FALSE;
|
||||
}
|
||||
CloseHandle(hToken);
|
||||
return TRUE;
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "define.h"
|
||||
|
||||
string WStringToString(const wstring &src);
|
||||
wstring StringToWString(const string &src);
|
||||
LSTATUS OpenFile(Env env, Napi::String &result, HWND parent = GetConsoleWindow());
|
||||
BOOL EnablePrivilege(Env env, const wstring &name);
|
||||
void Log(Env env, const string &msg);
|
||||
void Log(Env env, const wstring &msg);
|
||||
|
||||
#ifndef GENSHIN_EXPORT_NATIVE_UTILS_H
|
||||
#define GENSHIN_EXPORT_NATIVE_UTILS_H
|
||||
|
||||
#endif //GENSHIN_EXPORT_NATIVE_UTILS_H
|
||||
Submodule native/src/wmi deleted from aab36ea1e1
20
package.json
20
package.json
@@ -1,20 +0,0 @@
|
||||
{
|
||||
"name": "genshin-export",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "app.js",
|
||||
"scripts": {
|
||||
"pkg": "pkg -t node16-win-x64 -C Brotli app.js --build -o app.exe",
|
||||
"pkg-for-windows7": "pkg -t node14-win-x64 -C Brotli app.js --build -o app-win7.exe"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"ini": "^2.0.0",
|
||||
"axios": "^0.26.1",
|
||||
"udp-proxy": "^1.2.0",
|
||||
"protobufjs": "^6.11.2"
|
||||
}
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
message AllAchievement {
|
||||
repeated Achievement list = 1;
|
||||
}
|
||||
|
||||
message Achievement {
|
||||
|
||||
enum Status {
|
||||
INVALID = 0;
|
||||
UNFINISHED = 1;
|
||||
FINISHED = 2;
|
||||
REWARD_TAKEN = 3;
|
||||
}
|
||||
|
||||
uint32 id = 1;
|
||||
Status status = 2;
|
||||
uint32 current = 3;
|
||||
uint32 require = 4;
|
||||
uint32 finish_timestamp = 5;
|
||||
|
||||
}
|
||||
|
||||
message QueryCurRegion {
|
||||
int32 retcode = 1;
|
||||
string message = 2;
|
||||
msg0 info = 3;
|
||||
oneof group {
|
||||
msg3 field2 = 4;
|
||||
msg4 field3 = 5;
|
||||
}
|
||||
bytes field4 = 11;
|
||||
bytes field5 = 12;
|
||||
bytes field6 = 13;
|
||||
}
|
||||
|
||||
message QueryRegionList {
|
||||
int32 retcode = 1;
|
||||
bytes field0 = 5;
|
||||
bytes field1 = 6;
|
||||
bool field2 = 7;
|
||||
repeated msg2 list = 2;
|
||||
}
|
||||
|
||||
message msg0 {
|
||||
string ip = 1;
|
||||
uint32 port = 2;
|
||||
string field0 = 3;
|
||||
string field1 = 7;
|
||||
string field2 = 8;
|
||||
string field3 = 9;
|
||||
string field4 = 10;
|
||||
string field5 = 11;
|
||||
string field6 = 12;
|
||||
string field7 = 13;
|
||||
uint32 field8 = 14;
|
||||
string field9 = 16;
|
||||
uint32 fieldA = 18;
|
||||
string fieldB = 19;
|
||||
string fieldC = 20;
|
||||
msg1 fieldD = 22;
|
||||
bytes fieldE = 23;
|
||||
string fieldF = 24;
|
||||
string fieldG = 26;
|
||||
string fieldH = 27;
|
||||
bool fieldI = 28;
|
||||
string fieldJ = 29;
|
||||
string fieldK = 30;
|
||||
string fieldL = 31;
|
||||
string fieldM = 32;
|
||||
string fieldN = 33;
|
||||
string fieldO = 34;
|
||||
msg1 fieldP = 35;
|
||||
}
|
||||
|
||||
message msg1 {
|
||||
uint32 field0 = 1;
|
||||
bool field1 = 2;
|
||||
string field2 = 3;
|
||||
string field3 = 4;
|
||||
string field4 = 5;
|
||||
string field5 = 6;
|
||||
string field6 = 7;
|
||||
}
|
||||
|
||||
message msg2 {
|
||||
string field0 = 1;
|
||||
string field1 = 2;
|
||||
string field2 = 3;
|
||||
string url = 4;
|
||||
}
|
||||
|
||||
message msg3 {
|
||||
string field0 = 1;
|
||||
}
|
||||
|
||||
message msg4 {
|
||||
uint32 field0 = 1;
|
||||
uint32 field1 = 2;
|
||||
string field2 = 3;
|
||||
string field3 = 4;
|
||||
}
|
||||
111
regionServer.js
111
regionServer.js
@@ -1,111 +0,0 @@
|
||||
const fs = require("fs")
|
||||
const https = require("https")
|
||||
const axios = require("axios")
|
||||
const { decodeProto, encodeProto, debug } = require("./utils")
|
||||
const path = require("path")
|
||||
const cert = path.join(__dirname, "./cert/root.p12")
|
||||
|
||||
const preparedRegions = {}
|
||||
let currentProxy = undefined
|
||||
|
||||
const getModifiedRegionList = async (conf) => {
|
||||
const d = await axios.get(`https://${conf.dispatchUrl}/query_region_list`, {
|
||||
responseType: "text",
|
||||
params: {
|
||||
version: conf.version,
|
||||
channel_id: conf.channel,
|
||||
sub_channel_id: conf.subChannel
|
||||
}
|
||||
}).catch(_ => {
|
||||
console.log("网络错误,请检查网络后重试 (22-1)")
|
||||
process.exit(221)
|
||||
})
|
||||
const regions = await decodeProto(Buffer.from(d.data,"base64"),"QueryRegionList")
|
||||
if (regions["retcode"] !== 0) {
|
||||
console.log(`系统错误,请稍后重试 (${regions["retcode"]}-23)`)
|
||||
process.exit(23)
|
||||
}
|
||||
regions.list = regions.list.map(item => {
|
||||
const host = new URL(item.url).host
|
||||
if (regions.list.length === 1) {
|
||||
preparedRegions[host] = true
|
||||
}
|
||||
item.url = `https://localdispatch.yuanshen.com/query_cur_region/${host}`
|
||||
return item
|
||||
})
|
||||
return (await encodeProto(regions,"QueryRegionList")).toString("base64")
|
||||
}
|
||||
|
||||
const getModifiedRegionInfo = async (url, uc, hs) => {
|
||||
const splitUrl = url.split("?")
|
||||
const host = splitUrl[0].split("/")[2]
|
||||
const noQueryRequest = splitUrl[1] === undefined
|
||||
const query = noQueryRequest ? "" : `?${splitUrl[1]}`
|
||||
const d = await axios.get(`https://${host}/query_cur_region${query}`, {
|
||||
responseType: "text"
|
||||
}).catch(_ => {
|
||||
console.log("网络错误,请检查网络后重试 (22-2)")
|
||||
process.exit(222)
|
||||
})
|
||||
if (noQueryRequest) {
|
||||
preparedRegions[host] = true
|
||||
return d.data
|
||||
} else {
|
||||
const region = await decodeProto(Buffer.from(d.data,"base64"),"QueryCurRegion")
|
||||
if (region["retcode"] !== 0) {
|
||||
console.log(`${region["message"]} (${region["retcode"]}-24)`)
|
||||
process.exit(24)
|
||||
}
|
||||
const info = region.info
|
||||
if (preparedRegions[host]) {
|
||||
if (currentProxy !== undefined) {
|
||||
currentProxy.close()
|
||||
}
|
||||
debug("Create udp proxy: %s:%d", info.ip, info.port)
|
||||
currentProxy = uc(info.ip, info.port, hs)
|
||||
} else {
|
||||
preparedRegions[host] = true
|
||||
}
|
||||
info.ip = "127.0.0.1"
|
||||
info.port = 45678
|
||||
return (await encodeProto(region,"QueryCurRegion")).toString("base64")
|
||||
}
|
||||
}
|
||||
|
||||
const agent = new https.Agent({
|
||||
rejectUnauthorized: false
|
||||
})
|
||||
|
||||
const create = async (conf, regionListLoadedCallback, regionSelectCallback) => {
|
||||
const regions = await getModifiedRegionList(conf)
|
||||
const hServer = https.createServer({
|
||||
pfx: fs.readFileSync(cert),
|
||||
passphrase: ""
|
||||
}, async (request, response) => {
|
||||
const url = request.url
|
||||
debug("HTTP: %s", url)
|
||||
response.writeHead(200, { "Content-Type": "text/html" })
|
||||
if (url.startsWith("/query_region_list")) {
|
||||
response.end(regions)
|
||||
} else if (url.startsWith("/query_cur_region")) {
|
||||
const regionInfo = await getModifiedRegionInfo(url, regionSelectCallback, hServer)
|
||||
response.end(regionInfo)
|
||||
} else {
|
||||
const frontResponse = await axios.get(`https://${conf.dispatchIP}${url}`, {
|
||||
responseType: "arraybuffer",
|
||||
httpsAgent: agent
|
||||
}).catch(err => {
|
||||
console.log("网络错误,请检查网络后重试 (22-3)")
|
||||
console.log(err.message)
|
||||
process.exit(223)
|
||||
})
|
||||
response.end(frontResponse.data)
|
||||
}
|
||||
}).listen(443, "127.0.0.1", () => {
|
||||
regionListLoadedCallback()
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
create
|
||||
}
|
||||
78
res/app.manifest
Normal file
78
res/app.manifest
Normal file
@@ -0,0 +1,78 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
|
||||
<security>
|
||||
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<!-- UAC 清单选项
|
||||
如果想要更改 Windows 用户帐户控制级别,请使用
|
||||
以下节点之一替换 requestedExecutionLevel 节点。
|
||||
|
||||
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
|
||||
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
|
||||
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
|
||||
|
||||
指定 requestedExecutionLevel 元素将禁用文件和注册表虚拟化。
|
||||
如果你的应用程序需要此虚拟化来实现向后兼容性,则移除此
|
||||
元素。
|
||||
-->
|
||||
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!-- 设计此应用程序与其一起工作且已针对此应用程序进行测试的
|
||||
Windows 版本的列表。取消评论适当的元素,
|
||||
Windows 将自动选择最兼容的环境。 -->
|
||||
|
||||
<!-- Windows Vista -->
|
||||
<!--<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />-->
|
||||
|
||||
<!-- Windows 7 -->
|
||||
<!--<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />-->
|
||||
|
||||
<!-- Windows 8 -->
|
||||
<!--<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />-->
|
||||
|
||||
<!-- Windows 8.1 -->
|
||||
<!--<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />-->
|
||||
|
||||
<!-- Windows 10 -->
|
||||
<!--<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />-->
|
||||
|
||||
</application>
|
||||
</compatibility>
|
||||
|
||||
<!-- 指示该应用程序可感知 DPI 且 Windows 在 DPI 较高时将不会对其进行
|
||||
自动缩放。Windows Presentation Foundation (WPF)应用程序自动感知 DPI,无需
|
||||
选择加入。选择加入此设置的 Windows 窗体应用程序(面向 .NET Framework 4.6)还应
|
||||
在其 app.config 中将 "EnableWindowsFormsHighDpiAutoResizing" 设置设置为 "true"。
|
||||
|
||||
将应用程序设为感知长路径。请参阅 https://docs.microsoft.com/windows/win32/fileio/maximum-file-path-limitation -->
|
||||
|
||||
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<windowsSettings>
|
||||
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
|
||||
<longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
|
||||
</windowsSettings>
|
||||
</application>
|
||||
|
||||
<!-- 启用 Windows 公共控件和对话框的主题(Windows XP 和更高版本) -->
|
||||
<!--
|
||||
<dependency>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity
|
||||
type="win32"
|
||||
name="Microsoft.Windows.Common-Controls"
|
||||
version="6.0.0.0"
|
||||
processorArchitecture="*"
|
||||
publicKeyToken="6595b64144ccf1df"
|
||||
language="*"
|
||||
/>
|
||||
</dependentAssembly>
|
||||
</dependency>
|
||||
-->
|
||||
|
||||
</assembly>
|
||||
106
src/AppCenterSDK/AppCenter.cs
Normal file
106
src/AppCenterSDK/AppCenter.cs
Normal file
@@ -0,0 +1,106 @@
|
||||
using Newtonsoft.Json;
|
||||
using System.Net;
|
||||
using YaeAchievement.AppCenterSDK.Models;
|
||||
using YaeAchievement.AppCenterSDK.Models.Serialization;
|
||||
|
||||
namespace YaeAchievement.AppCenterSDK;
|
||||
|
||||
#pragma warning disable CA1416, CA2211
|
||||
public static class AppCenter {
|
||||
|
||||
private const string LogCache = "./cache/bf18159fb833715i.miko";
|
||||
private const string AppSecret = "648b83bf-d439-49bd-97f4-e1e506bdfe39";
|
||||
private const string ApiUrl = "https://in.appcenter.ms/logs?api-version=1.0.0";
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
public static Guid? SessionID;
|
||||
public static readonly string DeviceID;
|
||||
public static readonly Device DeviceInfo;
|
||||
private static List<Log> Queue;
|
||||
private static readonly Lazy<HttpClient> httpClient = new(() => new HttpClient(new HttpClientHandler {
|
||||
Proxy = GlobalVars.DebugProxy ? new WebProxy("http://127.0.0.1:8888") : null
|
||||
}) {
|
||||
DefaultRequestHeaders = {
|
||||
{ "Install-ID", DeviceID },
|
||||
{ "App-Secret", AppSecret }
|
||||
}
|
||||
});
|
||||
|
||||
static AppCenter() {
|
||||
Queue = new List<Log>();
|
||||
DeviceID = DeviceHelper.GetDeviceID();
|
||||
DeviceInfo = new Device();
|
||||
var running = true;
|
||||
Task.Run(() => {
|
||||
// ReSharper disable once LoopVariableIsNeverChangedInsideLoop
|
||||
while (running) {
|
||||
Upload();
|
||||
Thread.Sleep(5 * 1000);
|
||||
}
|
||||
});
|
||||
AppDomain.CurrentDomain.ProcessExit += (_, _) => {
|
||||
running = false;
|
||||
if (Queue.Count > 0) {
|
||||
Directory.CreateDirectory("cache");
|
||||
File.WriteAllText(LogCache, Queue.ToJson());
|
||||
}
|
||||
};
|
||||
LogSerializer.AddLogType(PageLog.JsonIdentifier, typeof(PageLog));
|
||||
LogSerializer.AddLogType(EventLog.JsonIdentifier, typeof(EventLog));
|
||||
LogSerializer.AddLogType(HandledErrorLog.JsonIdentifier, typeof(HandledErrorLog));
|
||||
LogSerializer.AddLogType(ManagedErrorLog.JsonIdentifier, typeof(ManagedErrorLog));
|
||||
LogSerializer.AddLogType(StartServiceLog.JsonIdentifier, typeof(StartServiceLog));
|
||||
LogSerializer.AddLogType(StartSessionLog.JsonIdentifier, typeof(StartSessionLog));
|
||||
if (Directory.Exists("./cache") && File.Exists(LogCache)) {
|
||||
var list = File.ReadAllText(LogCache).FromJson()?.Logs;
|
||||
if (list != null) {
|
||||
Queue.AddRange(list);
|
||||
}
|
||||
File.Delete(LogCache);
|
||||
}
|
||||
}
|
||||
|
||||
// ReSharper restore InconsistentNaming
|
||||
public static void Upload() {
|
||||
if (Queue.Count == 0) return;
|
||||
var uploadStatus = "";
|
||||
do {
|
||||
Queue = Queue.Select(log => {
|
||||
log.Status = LogStatus.Uploading;
|
||||
return log;
|
||||
}).ToList();
|
||||
using var uploadContent = new StringContent(Queue.ToJson());
|
||||
try {
|
||||
using var response = httpClient.Value.PostAsync(ApiUrl, uploadContent).Result;
|
||||
var result = response.Content.ReadAsStringAsync().Result;
|
||||
uploadStatus = JsonConvert.DeserializeObject<LogUploadResult>(result)!.Status;
|
||||
} catch (Exception) {
|
||||
// ignored
|
||||
}
|
||||
} while (uploadStatus != "Success");
|
||||
Queue.RemoveAll(log => log.Status == LogStatus.Uploading);
|
||||
}
|
||||
|
||||
public static void Init() {
|
||||
new StartServiceLog("Analytics", "Crashes").Enqueue();
|
||||
SessionID = Guid.NewGuid();
|
||||
new StartSessionLog().Enqueue();
|
||||
}
|
||||
|
||||
public static void TrackCrash(Exception exception, bool fatal = true) {
|
||||
new ManagedErrorLog(exception, fatal).Enqueue();
|
||||
}
|
||||
|
||||
public static void Enqueue(this Log log) {
|
||||
Queue.Add(log);
|
||||
}
|
||||
|
||||
private static string ToJson(this IEnumerable<Log> queue) {
|
||||
return LogSerializer.Serialize(new LogContainer(queue));
|
||||
}
|
||||
|
||||
private static LogContainer? FromJson(this string text) {
|
||||
return LogSerializer.DeserializeLogs(text);
|
||||
}
|
||||
}
|
||||
#pragma warning restore CA1416, CA2211
|
||||
68
src/AppCenterSDK/DeviceHelper.cs
Normal file
68
src/AppCenterSDK/DeviceHelper.cs
Normal file
@@ -0,0 +1,68 @@
|
||||
using Microsoft.Win32;
|
||||
using YaeAchievement.Win32;
|
||||
|
||||
namespace YaeAchievement.AppCenterSDK;
|
||||
|
||||
#pragma warning disable CA1416
|
||||
public static class DeviceHelper {
|
||||
|
||||
public static string? GetOem() {
|
||||
using var root = Registry.LocalMachine;
|
||||
using var sub = root.OpenSubKey("HARDWARE\\DESCRIPTION\\System\\BIOS");
|
||||
var oem = sub?.GetValue("SystemManufacturer") as string;
|
||||
return oem == "System manufacturer" ? null : oem;
|
||||
}
|
||||
|
||||
public static string? GetModel() {
|
||||
using var root = Registry.LocalMachine;
|
||||
using var sub = root.OpenSubKey("HARDWARE\\DESCRIPTION\\System\\BIOS");
|
||||
var model = sub?.GetValue("SystemProductName") as string;
|
||||
return model == "System Product Name" ? null : model;
|
||||
}
|
||||
|
||||
public static string GetScreenSize() {
|
||||
var desktop = Native.GetDC(IntPtr.Zero);
|
||||
var size = $"{Native.GetDeviceCaps(desktop, 118)}x{Native.GetDeviceCaps(desktop, 117)}";
|
||||
Native.ReleaseDC(IntPtr.Zero, desktop);
|
||||
return size;
|
||||
}
|
||||
|
||||
public static string? GetCountry() {
|
||||
using var root = Registry.CurrentUser;
|
||||
using var sub = root.OpenSubKey("Control Panel\\International\\Geo");
|
||||
return sub?.GetValue("Name") as string;
|
||||
}
|
||||
|
||||
public static string GetSystemVersion() {
|
||||
using var root = Registry.LocalMachine;
|
||||
using var sub = root.OpenSubKey("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion");
|
||||
var majorVersion = sub?.GetValue("CurrentMajorVersionNumber");
|
||||
if (majorVersion != null) {
|
||||
var minorVersion = sub?.GetValue("CurrentMinorVersionNumber", "0");
|
||||
var buildNumber = sub?.GetValue("CurrentBuildNumber", "0");
|
||||
return $"{majorVersion}.{minorVersion}.{buildNumber}";
|
||||
} else {
|
||||
var version = sub?.GetValue("CurrentVersion", "0.0");
|
||||
var buildNumber = sub?.GetValue("CurrentBuild", "0");
|
||||
return $"{version}.{buildNumber}";
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetSystemBuild() {
|
||||
using var root = Registry.LocalMachine;
|
||||
using var sub = root.OpenSubKey("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion");
|
||||
return (int) (sub?.GetValue("UBR") ?? 0);
|
||||
}
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public static string GetDeviceID() {
|
||||
using var sdk = Registry.CurrentUser.OpenSubKey("SOFTWARE\\miHoYoSDK");
|
||||
if (sdk?.GetValue("MIHOYOSDK_DEVICE_ID") is not string id) {
|
||||
id = $"{Random.Shared.NextInt64().ToString().SHA1Hash().ToLower()}{DateTimeOffset.Now.ToUnixTimeMilliseconds()}";
|
||||
sdk?.SetValue("MIHOYOSDK_DEVICE_ID", id);
|
||||
}
|
||||
id = id.MD5Hash().ToLower();
|
||||
return $"{id[..8]}-{id[8..12]}-{id[12..16]}-{id[16..20]}-{id[20..]}";
|
||||
}
|
||||
}
|
||||
#pragma warning restore CA1416
|
||||
25
src/AppCenterSDK/ErrorLogHelper.cs
Normal file
25
src/AppCenterSDK/ErrorLogHelper.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using YaeAchievement.AppCenterSDK.Models;
|
||||
|
||||
namespace YaeAchievement.AppCenterSDK;
|
||||
|
||||
public static class ErrorLogHelper {
|
||||
public static MException CreateModelExceptionAndBinaries(Exception exception) {
|
||||
var modelException = new MException {
|
||||
Type = exception.GetType().ToString(),
|
||||
Message = exception.Message,
|
||||
StackTrace = exception.StackTrace
|
||||
};
|
||||
if (exception is AggregateException aggregateException) {
|
||||
if (aggregateException.InnerExceptions.Count != 0) {
|
||||
modelException.InnerExceptions = new List<MException>();
|
||||
foreach (var innerException in aggregateException.InnerExceptions) {
|
||||
modelException.InnerExceptions.Add(CreateModelExceptionAndBinaries(innerException));
|
||||
}
|
||||
}
|
||||
} else if (exception.InnerException != null) {
|
||||
modelException.InnerExceptions ??= new List<MException>();
|
||||
modelException.InnerExceptions.Add(CreateModelExceptionAndBinaries(exception.InnerException));
|
||||
}
|
||||
return modelException;
|
||||
}
|
||||
}
|
||||
51
src/AppCenterSDK/Models/Device.cs
Normal file
51
src/AppCenterSDK/Models/Device.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace YaeAchievement.AppCenterSDK.Models;
|
||||
|
||||
public class Device {
|
||||
|
||||
[JsonProperty(PropertyName = "sdkName")]
|
||||
public string SdkName { get; set; } = "appcenter.wpf.netcore";
|
||||
|
||||
[JsonProperty(PropertyName = "sdkVersion")]
|
||||
public string SdkVersion { get; set; } = "4.5.0";
|
||||
|
||||
[JsonProperty(PropertyName = "osName")]
|
||||
public string OsName { get; set; } = "WINDOWS";
|
||||
|
||||
[JsonProperty(PropertyName = "osVersion")]
|
||||
public string OsVersion { get; set; } = DeviceHelper.GetSystemVersion();
|
||||
|
||||
[JsonProperty(PropertyName = "osBuild")]
|
||||
public string OsBuild { get; set; } = $"{DeviceHelper.GetSystemVersion()}.{DeviceHelper.GetSystemBuild()}";
|
||||
|
||||
[JsonProperty(PropertyName = "model")]
|
||||
public string? Model { get; set; } = DeviceHelper.GetModel();
|
||||
|
||||
[JsonProperty(PropertyName = "oemName")]
|
||||
public string? OemName { get; set; } = DeviceHelper.GetOem();
|
||||
|
||||
[JsonProperty(PropertyName = "screenSize")]
|
||||
public string ScreenSize { get; set; } = DeviceHelper.GetScreenSize();
|
||||
|
||||
[JsonProperty(PropertyName = "carrierCountry")]
|
||||
public string Country { get; set; } = DeviceHelper.GetCountry() ?? "CN";
|
||||
|
||||
[JsonProperty(PropertyName = "locale")]
|
||||
public string Locale { get; set; } = CultureInfo.CurrentCulture.Name;
|
||||
|
||||
[JsonProperty(PropertyName = "timeZoneOffset")]
|
||||
public int TimeZoneOffset { get; set; } = (int) TimeZoneInfo.Local.BaseUtcOffset.TotalMinutes;
|
||||
|
||||
[JsonProperty(PropertyName = "appVersion")]
|
||||
public string AppVersion { get; set; } = GlobalVars.AppVersionName;
|
||||
|
||||
[JsonProperty(PropertyName = "appBuild")]
|
||||
public string AppBuild { get; set; } = GlobalVars.AppVersionCode.ToString();
|
||||
|
||||
[JsonProperty(PropertyName = "appNamespace")]
|
||||
public string AppNamespace { get; set; } = Assembly.GetEntryAssembly()?.EntryPoint?.DeclaringType?.Namespace ?? string.Empty;
|
||||
|
||||
}
|
||||
20
src/AppCenterSDK/Models/EventLog.cs
Normal file
20
src/AppCenterSDK/Models/EventLog.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace YaeAchievement.AppCenterSDK.Models;
|
||||
|
||||
[JsonObject(JsonIdentifier)]
|
||||
public class EventLog : LogWithProperties {
|
||||
|
||||
public const string JsonIdentifier = "event";
|
||||
|
||||
public EventLog(string name) {
|
||||
Name = name;
|
||||
}
|
||||
|
||||
[JsonProperty(PropertyName = "id")]
|
||||
private Guid Id { get; set; } = Guid.NewGuid();
|
||||
|
||||
[JsonProperty(PropertyName = "name")]
|
||||
private string Name { get; set; }
|
||||
|
||||
}
|
||||
21
src/AppCenterSDK/Models/HandledErrorLog.cs
Normal file
21
src/AppCenterSDK/Models/HandledErrorLog.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace YaeAchievement.AppCenterSDK.Models;
|
||||
|
||||
[JsonObject(JsonIdentifier)]
|
||||
public class HandledErrorLog : LogWithProperties {
|
||||
|
||||
public const string JsonIdentifier = "handledError";
|
||||
|
||||
public HandledErrorLog(MException exception) {
|
||||
Id = Guid.NewGuid();
|
||||
Exception = exception;
|
||||
}
|
||||
|
||||
[JsonProperty(PropertyName = "id")]
|
||||
public Guid? Id { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "exception")]
|
||||
public MException Exception { get; set; }
|
||||
|
||||
}
|
||||
23
src/AppCenterSDK/Models/Log.cs
Normal file
23
src/AppCenterSDK/Models/Log.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace YaeAchievement.AppCenterSDK.Models;
|
||||
|
||||
public abstract class Log {
|
||||
|
||||
[JsonProperty(PropertyName = "sid")]
|
||||
private Guid? Session { get; set; } = AppCenter.SessionID;
|
||||
|
||||
[JsonProperty(PropertyName = "timestamp")]
|
||||
private DateTime Timestamp { get; set; } = DateTime.UtcNow;
|
||||
|
||||
[JsonProperty(PropertyName = "device")]
|
||||
private Device Device { get; set; } = AppCenter.DeviceInfo;
|
||||
|
||||
[JsonIgnore]
|
||||
internal LogStatus Status = LogStatus.Pending;
|
||||
|
||||
}
|
||||
|
||||
public enum LogStatus {
|
||||
Pending, Uploading, Uploaded
|
||||
}
|
||||
14
src/AppCenterSDK/Models/LogContainer.cs
Normal file
14
src/AppCenterSDK/Models/LogContainer.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace YaeAchievement.AppCenterSDK.Models;
|
||||
|
||||
public class LogContainer {
|
||||
|
||||
public LogContainer(IEnumerable<Log> logs) {
|
||||
Logs = logs;
|
||||
}
|
||||
|
||||
[JsonProperty(PropertyName = "logs")]
|
||||
public IEnumerable<Log> Logs { get; set; }
|
||||
|
||||
}
|
||||
19
src/AppCenterSDK/Models/LogUploadResult.cs
Normal file
19
src/AppCenterSDK/Models/LogUploadResult.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace YaeAchievement.AppCenterSDK.Models;
|
||||
|
||||
public class LogUploadResult {
|
||||
|
||||
[JsonProperty(PropertyName = "status")]
|
||||
public string Status { get; set; } = null!;
|
||||
|
||||
[JsonProperty(PropertyName = "validDiagnosticsIds")]
|
||||
public Guid[] ValidDiagnosticsIds { get; set; } = Array.Empty<Guid>();
|
||||
|
||||
[JsonProperty(PropertyName = "throttledDiagnosticsIds")]
|
||||
public Guid[] ThrottledDiagnosticsIds { get; set; } = Array.Empty<Guid>();
|
||||
|
||||
[JsonProperty(PropertyName = "correlationId")]
|
||||
public Guid CorrelationId { get; set; }
|
||||
|
||||
}
|
||||
10
src/AppCenterSDK/Models/LogWithProperties.cs
Normal file
10
src/AppCenterSDK/Models/LogWithProperties.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace YaeAchievement.AppCenterSDK.Models;
|
||||
|
||||
public class LogWithProperties : Log {
|
||||
|
||||
[JsonProperty(PropertyName = "properties")]
|
||||
public IDictionary<string, string> Properties { get; set; } = new Dictionary<string, string>();
|
||||
|
||||
}
|
||||
22
src/AppCenterSDK/Models/MException.cs
Normal file
22
src/AppCenterSDK/Models/MException.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace YaeAchievement.AppCenterSDK.Models;
|
||||
|
||||
public class MException {
|
||||
|
||||
[JsonProperty(PropertyName = "type")]
|
||||
public string Type { get; set; } = "UnknownType";
|
||||
|
||||
[JsonProperty(PropertyName = "message")]
|
||||
public string? Message { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "stackTrace")]
|
||||
public string? StackTrace { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "frames")]
|
||||
public IList<StackFrame>? Frames { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "innerExceptions")]
|
||||
public IList<MException>? InnerExceptions { get; set; }
|
||||
|
||||
}
|
||||
50
src/AppCenterSDK/Models/ManagedErrorLog.cs
Normal file
50
src/AppCenterSDK/Models/ManagedErrorLog.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using System.Diagnostics;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace YaeAchievement.AppCenterSDK.Models;
|
||||
|
||||
[JsonObject(JsonIdentifier)]
|
||||
public class ManagedErrorLog : Log {
|
||||
|
||||
public const string JsonIdentifier = "managedError";
|
||||
|
||||
public ManagedErrorLog(
|
||||
Exception exception,
|
||||
bool fatal = true
|
||||
) {
|
||||
var p = Process.GetCurrentProcess();
|
||||
Id = Guid.NewGuid();
|
||||
Fatal = fatal;
|
||||
UserId = AppCenter.DeviceID;
|
||||
ProcessId = p.Id;
|
||||
Exception = ErrorLogHelper.CreateModelExceptionAndBinaries(exception);
|
||||
ProcessName = p.ProcessName;
|
||||
Architecture = Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE");
|
||||
AppLaunchTimestamp = p.StartTime.ToUniversalTime();
|
||||
}
|
||||
|
||||
[JsonProperty(PropertyName = "id")]
|
||||
public Guid Id { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "userId")]
|
||||
public string? UserId { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "processId")]
|
||||
public int ProcessId { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "processName")]
|
||||
public string ProcessName { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "fatal")]
|
||||
public bool Fatal { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "appLaunchTimestamp")]
|
||||
public DateTime? AppLaunchTimestamp { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "architecture")]
|
||||
public string? Architecture { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "exception")]
|
||||
public MException Exception { get; set; }
|
||||
|
||||
}
|
||||
17
src/AppCenterSDK/Models/PageLog.cs
Normal file
17
src/AppCenterSDK/Models/PageLog.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace YaeAchievement.AppCenterSDK.Models;
|
||||
|
||||
[JsonObject(JsonIdentifier)]
|
||||
public class PageLog : LogWithProperties {
|
||||
|
||||
public const string JsonIdentifier = "page";
|
||||
|
||||
public PageLog(string name) {
|
||||
Name = name;
|
||||
}
|
||||
|
||||
[JsonProperty(PropertyName = "name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
}
|
||||
60
src/AppCenterSDK/Models/Serialization/LogJsonConverter.cs
Normal file
60
src/AppCenterSDK/Models/Serialization/LogJsonConverter.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System.Reflection;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace YaeAchievement.AppCenterSDK.Models.Serialization;
|
||||
|
||||
#pragma warning disable CS8604, CS8765
|
||||
public class LogJsonConverter : JsonConverter {
|
||||
|
||||
private readonly Dictionary<string, Type> _logTypes = new ();
|
||||
private readonly object _jsonConverterLock = new ();
|
||||
private static readonly JsonSerializerSettings SerializationSettings;
|
||||
|
||||
static LogJsonConverter() {
|
||||
SerializationSettings = new JsonSerializerSettings {
|
||||
Formatting = Formatting.None,
|
||||
NullValueHandling = NullValueHandling.Ignore,
|
||||
DateFormatHandling = DateFormatHandling.IsoDateFormat,
|
||||
DateTimeZoneHandling = DateTimeZoneHandling.Utc,
|
||||
ReferenceLoopHandling = ReferenceLoopHandling.Serialize
|
||||
};
|
||||
}
|
||||
|
||||
public void AddLogType(string typeName, Type type) {
|
||||
lock (_jsonConverterLock) {
|
||||
_logTypes[typeName] = type;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType) {
|
||||
return typeof(Log).IsAssignableFrom(objectType);
|
||||
}
|
||||
|
||||
public override object? ReadJson(JsonReader reader, Type t, object o, JsonSerializer s) {
|
||||
Type logType;
|
||||
var jsonObject = JObject.Load(reader);
|
||||
var typeName = jsonObject.GetValue("type")?.ToString();
|
||||
lock (_jsonConverterLock) {
|
||||
if (typeName == null || !_logTypes.ContainsKey(typeName)) {
|
||||
throw new JsonReaderException("Could not identify type of log");
|
||||
}
|
||||
logType = _logTypes[typeName];
|
||||
jsonObject.Remove("type");
|
||||
}
|
||||
return jsonObject.ToObject(logType);
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
|
||||
var info = value.GetType().GetTypeInfo();
|
||||
if (info.GetCustomAttribute(typeof(JsonObjectAttribute)) is not JsonObjectAttribute attribute) {
|
||||
throw new JsonWriterException("Log type is missing JsonObjectAttribute");
|
||||
}
|
||||
var jsonObject = JObject.FromObject(value, JsonSerializer.CreateDefault(SerializationSettings));
|
||||
jsonObject.Add("type", JToken.FromObject(attribute.Id));
|
||||
writer.WriteRawValue(jsonObject.ToString(Formatting.None));
|
||||
}
|
||||
}
|
||||
40
src/AppCenterSDK/Models/Serialization/LogSerializer.cs
Normal file
40
src/AppCenterSDK/Models/Serialization/LogSerializer.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace YaeAchievement.AppCenterSDK.Models.Serialization;
|
||||
|
||||
#pragma warning disable CS8604, CS8765, CS8603
|
||||
public static class LogSerializer {
|
||||
|
||||
private static readonly JsonSerializerSettings SerializationSettings;
|
||||
private static readonly LogJsonConverter Converter = new ();
|
||||
|
||||
static LogSerializer() {
|
||||
SerializationSettings = new JsonSerializerSettings {
|
||||
Formatting = Formatting.None,
|
||||
NullValueHandling = NullValueHandling.Ignore,
|
||||
DateFormatHandling = DateFormatHandling.IsoDateFormat,
|
||||
DateTimeZoneHandling = DateTimeZoneHandling.Utc,
|
||||
ReferenceLoopHandling = ReferenceLoopHandling.Serialize,
|
||||
Converters = { Converter }
|
||||
};
|
||||
}
|
||||
|
||||
public static void AddLogType(string typeName, Type type) {
|
||||
Converter.AddLogType(typeName, type);
|
||||
}
|
||||
|
||||
public static string Serialize(LogContainer logContainer) {
|
||||
return JsonConvert.SerializeObject(logContainer, SerializationSettings);
|
||||
}
|
||||
|
||||
public static string Serialize(Log log) {
|
||||
return JsonConvert.SerializeObject(log, SerializationSettings);
|
||||
}
|
||||
|
||||
public static LogContainer? DeserializeLogs(string json) {
|
||||
return JsonConvert.DeserializeObject<LogContainer>(json, SerializationSettings);
|
||||
}
|
||||
}
|
||||
34
src/AppCenterSDK/Models/StackFrame.cs
Normal file
34
src/AppCenterSDK/Models/StackFrame.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace YaeAchievement.AppCenterSDK.Models;
|
||||
|
||||
public class StackFrame {
|
||||
|
||||
public StackFrame(string address, string code, string className, string methodName, int? lineNumber, string fileName) {
|
||||
Address = address;
|
||||
Code = code;
|
||||
ClassName = className;
|
||||
MethodName = methodName;
|
||||
LineNumber = lineNumber;
|
||||
FileName = fileName;
|
||||
}
|
||||
|
||||
[JsonProperty(PropertyName = "address")]
|
||||
public string Address { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "code")]
|
||||
public string Code { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "className")]
|
||||
public string ClassName { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "methodName")]
|
||||
public string MethodName { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "lineNumber")]
|
||||
public int? LineNumber { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "fileName")]
|
||||
public string FileName { get; set; }
|
||||
|
||||
}
|
||||
17
src/AppCenterSDK/Models/StartServiceLog.cs
Normal file
17
src/AppCenterSDK/Models/StartServiceLog.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace YaeAchievement.AppCenterSDK.Models;
|
||||
|
||||
[JsonObject(JsonIdentifier)]
|
||||
public class StartServiceLog : Log {
|
||||
|
||||
public const string JsonIdentifier = "startService";
|
||||
|
||||
public StartServiceLog(params string[] services) {
|
||||
Services = services;
|
||||
}
|
||||
|
||||
[JsonProperty(PropertyName = "services")]
|
||||
public string[] Services { get; set; }
|
||||
|
||||
}
|
||||
8
src/AppCenterSDK/Models/StartSessionLog.cs
Normal file
8
src/AppCenterSDK/Models/StartSessionLog.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace YaeAchievement.AppCenterSDK.Models;
|
||||
|
||||
[JsonObject(JsonIdentifier)]
|
||||
public class StartSessionLog : Log {
|
||||
public const string JsonIdentifier = "startSession";
|
||||
}
|
||||
41
src/AppConfig.cs
Normal file
41
src/AppConfig.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace YaeAchievement;
|
||||
|
||||
public class AppConfig {
|
||||
|
||||
[JsonProperty(PropertyName = "location")]
|
||||
public string? Location { get; set; }
|
||||
|
||||
private static AppConfig? _instance;
|
||||
|
||||
private static readonly string FileName = Path.Combine(GlobalVars.AppPath, "conf.json");
|
||||
|
||||
public static string GamePath => _instance!.Location!;
|
||||
|
||||
internal static void Load() {
|
||||
if (File.Exists(FileName)) {
|
||||
var text = File.ReadAllText(FileName);
|
||||
_instance = JsonConvert.DeserializeObject<AppConfig>(text)!;
|
||||
}
|
||||
if (_instance?.Location == null || !Utils.CheckGamePathValid(_instance.Location)) {
|
||||
var gameInstallPath = Utils.FindGamePathFromRegistry();
|
||||
if (!string.IsNullOrEmpty(gameInstallPath)) {
|
||||
Console.WriteLine($"自动读取到游戏路径: {gameInstallPath}");
|
||||
Console.WriteLine($"如果确认路径无误,请按 Y ;若有误或需要自行选择,请按 N ");
|
||||
var key = Console.ReadKey().Key;
|
||||
gameInstallPath = key == ConsoleKey.Y ? gameInstallPath : Utils.SelectGameExecutable();
|
||||
} else {
|
||||
gameInstallPath = Utils.SelectGameExecutable();
|
||||
}
|
||||
_instance = new AppConfig {
|
||||
Location = gameInstallPath
|
||||
};
|
||||
Save();
|
||||
}
|
||||
}
|
||||
|
||||
public static void Save() {
|
||||
File.WriteAllText(FileName, JsonConvert.SerializeObject(_instance!, Formatting.Indented));
|
||||
}
|
||||
}
|
||||
39
src/CacheFile.cs
Normal file
39
src/CacheFile.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System.IO.Compression;
|
||||
using Google.Protobuf;
|
||||
|
||||
namespace YaeAchievement;
|
||||
|
||||
public class CacheFile {
|
||||
|
||||
private readonly string _cacheName;
|
||||
private CacheItem? _content;
|
||||
|
||||
public DateTime LastWriteTime => Exists() ? File.GetLastWriteTimeUtc(_cacheName) : DateTime.UnixEpoch;
|
||||
|
||||
public CacheFile(string identifier) {
|
||||
Directory.CreateDirectory(Path.Combine(GlobalVars.AppPath, "cache"));
|
||||
_cacheName = Path.Combine(GlobalVars.AppPath, $"cache/{identifier.MD5Hash()[..16]}.miko");
|
||||
}
|
||||
|
||||
public bool Exists() => File.Exists(_cacheName);
|
||||
|
||||
public CacheItem Read() {
|
||||
if (_content == null) {
|
||||
using var fInput = File.OpenRead(_cacheName);
|
||||
using var dInput = new GZipStream(fInput, CompressionMode.Decompress);
|
||||
_content = CacheItem.Parser.ParseFrom(dInput);
|
||||
}
|
||||
return _content;
|
||||
}
|
||||
|
||||
public void Write(byte[] data, string? etag = null) {
|
||||
using var fOut = File.OpenWrite(_cacheName);
|
||||
using var cOut = new GZipStream(fOut, CompressionLevel.SmallestSize);
|
||||
new CacheItem {
|
||||
Etag = etag ?? string.Empty,
|
||||
Version = 3,
|
||||
Checksum = data.MD5Hash(),
|
||||
Content = ByteString.CopyFrom(data)
|
||||
}.WriteTo(cOut);
|
||||
}
|
||||
}
|
||||
215
src/Export.cs
Normal file
215
src/Export.cs
Normal file
@@ -0,0 +1,215 @@
|
||||
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using Microsoft.Win32;
|
||||
using Newtonsoft.Json;
|
||||
using static AchievementAllDataNotify.Types.Achievement.Types;
|
||||
|
||||
namespace YaeAchievement;
|
||||
|
||||
public static class Export {
|
||||
|
||||
public static void Choose(AchievementAllDataNotify data) {
|
||||
Console.Write("""
|
||||
导出至:
|
||||
[0] 椰羊 (https://cocogoat.work/achievement, 默认)
|
||||
[1] SnapGenshin
|
||||
[2] Paimon.moe
|
||||
[3] Seelie.me
|
||||
[4] 表格文件
|
||||
[5] 原魔工具箱
|
||||
[6] 寻空
|
||||
输入一个数字(0-6):
|
||||
""");
|
||||
if (!int.TryParse(Console.ReadLine(), out var num)) num = 0;
|
||||
((Action<AchievementAllDataNotify>) (num switch {
|
||||
1 => ToSnapGenshin,
|
||||
2 => ToPaimon,
|
||||
3 => ToSeelie,
|
||||
4 => ToCSV,
|
||||
5 => ToWxApp1,
|
||||
6 => ToXunkong,
|
||||
7 => ToRawJson,
|
||||
_ => ToCocogoat
|
||||
})).Invoke(data);
|
||||
}
|
||||
|
||||
private static void ToCocogoat(AchievementAllDataNotify data) {
|
||||
var result = JsonConvert.SerializeObject(ExportToUIAFApp(data));
|
||||
using var request = new HttpRequestMessage {
|
||||
Method = HttpMethod.Post,
|
||||
RequestUri = new Uri("https://77.cocogoat.work/v1/memo?source=全部成就"),
|
||||
Content = new StringContent(result, Encoding.UTF8, "application/json")
|
||||
};
|
||||
using var response = Utils.CHttpClient.Value.Send(request);
|
||||
if (response.StatusCode != HttpStatusCode.Created) {
|
||||
Console.WriteLine("导出失败, 请联系开发者以获取帮助");
|
||||
return;
|
||||
}
|
||||
dynamic memo = JsonConvert.DeserializeObject(response.Content.ReadAsStringAsync().Result)!;
|
||||
Console.WriteLine(Utils.ShellOpen($"https://cocogoat.work/achievement?memo={memo.key}")
|
||||
? "在浏览器内进行下一步操作"
|
||||
: $"https://cocogoat.work/achievement?memo={memo.key}");
|
||||
}
|
||||
|
||||
private static void ToWxApp1(AchievementAllDataNotify data) {
|
||||
var id = Guid.NewGuid().ToString("N").Substring(20, 8);
|
||||
var result = JsonConvert.SerializeObject(new Dictionary<string, object> {
|
||||
{ "key", id },
|
||||
{ "data", ExportToUIAFApp(data) }
|
||||
});
|
||||
using var request = new HttpRequestMessage {
|
||||
Method = HttpMethod.Post,
|
||||
RequestUri = new Uri("https://api.qyinter.com/achievementRedis"),
|
||||
Content = new StringContent(result, Encoding.UTF8, "application/json")
|
||||
};
|
||||
using var response = Utils.CHttpClient.Value.Send(request);
|
||||
Console.WriteLine($"在小程序导入页面输入以下代码: {id}");
|
||||
}
|
||||
|
||||
private static void ToSnapGenshin(AchievementAllDataNotify data) {
|
||||
if (CheckSnapScheme()) {
|
||||
Utils.CopyToClipboard(JsonConvert.SerializeObject(ExportToUIAFApp(data)));
|
||||
Utils.ShellOpen("snapgenshin://achievement/import/uiaf");
|
||||
Console.WriteLine("在 SnapGenshin 进行下一步操作");
|
||||
} else {
|
||||
Console.WriteLine("更新 SnapGenshin 至最新版本后重试");
|
||||
}
|
||||
}
|
||||
|
||||
private static void ToPaimon(AchievementAllDataNotify data) {
|
||||
var info = LoadAchievementInfo();
|
||||
var output = new Dictionary<uint, Dictionary<uint, bool>>();
|
||||
foreach (var ach in data.List.Where(a => a.Status is Status.Finished or Status.RewardTaken)) {
|
||||
if (!info.Items.TryGetValue(ach.Id, out var achInfo) || achInfo == null) {
|
||||
Console.WriteLine($"Unable to find {ach.Id} in metadata.");
|
||||
continue;
|
||||
}
|
||||
var map = output.GetValueOrDefault(achInfo.Group, new Dictionary<uint, bool>());
|
||||
map[ach.Id == 81222 ? 81219 : ach.Id] = true;
|
||||
output[achInfo.Group] = map;
|
||||
}
|
||||
var final = new Dictionary<string, Dictionary<uint, Dictionary<uint, bool>>> {
|
||||
["achievement"] = output.OrderBy(pair => pair.Key).ToDictionary(pair => pair.Key, pair => pair.Value)
|
||||
};
|
||||
var path = Path.GetFullPath($"export-{DateTime.Now:yyyyMMddHHmmss}-paimon.json");
|
||||
File.WriteAllText(path, JsonConvert.SerializeObject(final));
|
||||
Console.WriteLine($"成就数据已导出至 {path}");
|
||||
}
|
||||
|
||||
private static void ToSeelie(AchievementAllDataNotify data) {
|
||||
var output = new Dictionary<uint, Dictionary<string, bool>>();
|
||||
foreach (var ach in data.List.Where(a => a.Status is Status.Finished or Status.RewardTaken)) {
|
||||
output[ach.Id == 81222 ? 81219 : ach.Id] = new Dictionary<string, bool> {
|
||||
["done"] = true
|
||||
};
|
||||
}
|
||||
var final = new Dictionary<string, Dictionary<uint, Dictionary<string, bool>>> {
|
||||
["achievements"] = output.OrderBy(pair => pair.Key).ToDictionary(pair => pair.Key, pair => pair.Value)
|
||||
};
|
||||
var path = Path.GetFullPath($"export-{DateTime.Now:yyyyMMddHHmmss}-seelie.json");
|
||||
File.WriteAllText(path, JsonConvert.SerializeObject(final));
|
||||
Console.WriteLine($"成就数据已导出至 {path}");
|
||||
}
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
private static void ToCSV(AchievementAllDataNotify data) {
|
||||
var info = LoadAchievementInfo();
|
||||
var outList = new List<List<object>>();
|
||||
foreach (var ach in data.List.OrderBy(a => a.Id)) {
|
||||
if (UnusedAchievement.Contains(ach.Id)) continue;
|
||||
if (!info.Items.TryGetValue(ach.Id, out var achInfo) || achInfo == null) {
|
||||
Console.WriteLine($"Unable to find {ach.Id} in metadata.");
|
||||
continue;
|
||||
}
|
||||
var finishAt = "";
|
||||
if (ach.Timestamp != 0) {
|
||||
var ts = Convert.ToInt64(ach.Timestamp);
|
||||
finishAt = DateTimeOffset.FromUnixTimeSeconds(ts).ToString("yyyy/MM/dd HH:mm:ss");
|
||||
}
|
||||
var current = ach.Status != Status.Unfinished ? ach.Current == 0 ? ach.Total : ach.Current : ach.Current;
|
||||
outList.Add(new List<object> {
|
||||
ach.Id, ach.Status.ToDesc(), achInfo.Group, achInfo.Name,
|
||||
achInfo.Description, current, ach.Total, finishAt
|
||||
});
|
||||
}
|
||||
var output = new List<string> { "ID,状态,特辑,名称,描述,当前进度,目标进度,完成时间" };
|
||||
output.AddRange(outList.OrderBy(v => v[2]).Select(item => {
|
||||
item[2] = info.Group[(uint) item[2]];
|
||||
return item.JoinToString(",");
|
||||
}));
|
||||
var path = Path.GetFullPath($"achievement-{DateTime.Now:yyyyMMddHHmmss}.csv");
|
||||
File.WriteAllText(path, $"\uFEFF{string.Join("\n", output)}");
|
||||
Console.WriteLine($"成就数据已导出至 {path}");
|
||||
}
|
||||
|
||||
private static void ToXunkong(AchievementAllDataNotify data) {
|
||||
if (CheckXunkongScheme()) {
|
||||
Utils.CopyToClipboard(JsonConvert.SerializeObject(ExportToUIAFApp(data)));
|
||||
Utils.ShellOpen("xunkong://import-achievement?caller=YaeAchievement&from=clipboard");
|
||||
Console.WriteLine("在寻空中进行下一步操作");
|
||||
} else {
|
||||
Console.WriteLine("更新寻空至最新版本后重试");
|
||||
Utils.ShellOpen("ms-windows-store://pdp/?productid=9N2SVG0JMT12");
|
||||
}
|
||||
}
|
||||
|
||||
private static void ToRawJson(AchievementAllDataNotify data) {
|
||||
var path = Path.GetFullPath($"export-{DateTime.Now:yyyyMMddHHmmss}-raw.json");
|
||||
File.WriteAllText(path, JsonConvert.SerializeObject(data, Formatting.Indented));
|
||||
Console.WriteLine($"成就数据已导出至 {path}");
|
||||
}
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
private static Dictionary<string, object> ExportToUIAFApp(AchievementAllDataNotify data) {
|
||||
var output = data.List
|
||||
.Where(a => (uint)a.Status > 1 || a.Current > 0)
|
||||
.Select(ach => new Dictionary<string, uint> {
|
||||
["id"] = ach.Id,
|
||||
["status"] = (uint) ach.Status,
|
||||
["current"] = ach.Current,
|
||||
["timestamp"] = ach.Timestamp,
|
||||
})
|
||||
.ToList();
|
||||
return new Dictionary<string, object> {
|
||||
["info"] = new Dictionary<string, object> {
|
||||
["export_app"] = "YaeAchievement",
|
||||
["export_timestamp"] = DateTimeOffset.Now.ToUnixTimeMilliseconds(),
|
||||
["export_app_version"] = GlobalVars.AppVersionName,
|
||||
["uiaf_version"] = "v1.1"
|
||||
},
|
||||
["list"] = output
|
||||
};
|
||||
}
|
||||
|
||||
#pragma warning disable CA1416
|
||||
private static bool CheckSnapScheme() {
|
||||
return (string?)Registry.ClassesRoot.OpenSubKey("snapgenshin")?.GetValue("") == "URL:snapgenshin";
|
||||
}
|
||||
|
||||
private static bool CheckXunkongScheme() {
|
||||
return (string?)Registry.ClassesRoot.OpenSubKey("xunkong")?.GetValue("") == "URL:xunkong";
|
||||
}
|
||||
#pragma warning restore CA1416
|
||||
|
||||
private static string JoinToString(this IEnumerable<object> list, string separator) {
|
||||
return string.Join(separator, list);
|
||||
}
|
||||
|
||||
private static readonly List<uint> UnusedAchievement = new() { 84517 };
|
||||
|
||||
private static string ToDesc(this Status status) {
|
||||
return status switch {
|
||||
Status.Invalid => "未知",
|
||||
Status.Finished => "已完成但未领取奖励",
|
||||
Status.Unfinished => "未完成",
|
||||
Status.RewardTaken => "已完成",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(status), status, null)
|
||||
};
|
||||
}
|
||||
|
||||
private static AchievementInfo LoadAchievementInfo() {
|
||||
var b = Utils.GetBucketFileAsByteArray("schicksal/metadata");
|
||||
return AchievementInfo.Parser.ParseFrom(b);
|
||||
}
|
||||
}
|
||||
41
src/Extensions.cs
Normal file
41
src/Extensions.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace YaeAchievement;
|
||||
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
public static class Extensions {
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
private static readonly Lazy<MD5> md5 = new (MD5.Create);
|
||||
// ReSharper disable once InconsistentNaming
|
||||
private static readonly Lazy<SHA1> sha1 = new (SHA1.Create);
|
||||
|
||||
public static byte[] ToBytes(this string text) {
|
||||
return Encoding.UTF8.GetBytes(text);
|
||||
}
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public static string MD5Hash(this string text) {
|
||||
return text.ToBytes().MD5Hash();
|
||||
}
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public static string MD5Hash(this byte[] data) {
|
||||
return md5.Value.ComputeHash(data).ToHex().ToLower();
|
||||
}
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public static string SHA1Hash(this string text, bool base64 = true) {
|
||||
var bytes = sha1.Value.ComputeHash(text.ToBytes());
|
||||
return base64 ? bytes.ToBase64() : bytes.ToHex();
|
||||
}
|
||||
|
||||
public static string ToHex(this byte[] bytes) {
|
||||
return Convert.ToHexString(bytes);
|
||||
}
|
||||
|
||||
public static string ToBase64(this byte[] bytes) {
|
||||
return Convert.ToBase64String(bytes);
|
||||
}
|
||||
}
|
||||
24
src/GlobalVars.cs
Normal file
24
src/GlobalVars.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System.Reflection;
|
||||
|
||||
namespace YaeAchievement;
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
// ReSharper disable ConvertToConstant.Global
|
||||
// ReSharper disable FieldCanBeMadeReadOnly.Global
|
||||
#pragma warning disable CA2211
|
||||
|
||||
public static class GlobalVars {
|
||||
|
||||
public static bool DebugProxy = false;
|
||||
public static bool CheckGamePath = true;
|
||||
public static bool UnexpectedExit = true;
|
||||
public static Version AppVersion = Assembly.GetEntryAssembly()!.GetName().Version!;
|
||||
public static readonly string AppPath = AppDomain.CurrentDomain.BaseDirectory;
|
||||
|
||||
public const uint AppVersionCode = 29;
|
||||
public const string AppVersionName = "2.1";
|
||||
public const string LibName = "YaeLib.dll";
|
||||
public const string PipeName = "YaeAchievementPipe";
|
||||
public const string BucketHost = "https://cn-cd-1259389942.file.myqcloud.com";
|
||||
|
||||
}
|
||||
52
src/Injector.cs
Normal file
52
src/Injector.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using System.ComponentModel;
|
||||
using YaeAchievement.Win32;
|
||||
using static YaeAchievement.Win32.Native;
|
||||
|
||||
namespace YaeAchievement;
|
||||
|
||||
public static class Injector {
|
||||
|
||||
public static unsafe bool CreateProcess(string path, out IntPtr hProc, out IntPtr hThread, out uint pid) {
|
||||
var si = new StartupInfo();
|
||||
SecurityAttributes* attr = null;
|
||||
var dir = Path.GetDirectoryName(path)!;
|
||||
var result = Native.CreateProcess(
|
||||
path, null, ref *attr, ref *attr, false,
|
||||
CreationFlags.CreateSuspended, IntPtr.Zero, dir, ref si, out var pi
|
||||
);
|
||||
pid = pi.dwProcessID;
|
||||
hProc = pi.hProcess;
|
||||
hThread = pi.hThread;
|
||||
return result;
|
||||
}
|
||||
|
||||
// todo: refactor
|
||||
public static int LoadLibraryAndInject(IntPtr hProc, string libPath) {
|
||||
var hKernel = GetModuleHandle("kernel32.dll");
|
||||
if (hKernel == IntPtr.Zero) {
|
||||
return new Win32Exception().PrintMsgAndReturnErrCode("GetModuleHandle fail");
|
||||
}
|
||||
var pLoadLibrary = GetProcAddress(hKernel, "LoadLibraryA");
|
||||
if (pLoadLibrary == IntPtr.Zero) {
|
||||
return new Win32Exception().PrintMsgAndReturnErrCode("GetProcAddress fail");
|
||||
}
|
||||
var pBase = VirtualAllocEx(hProc, IntPtr.Zero, libPath.Length + 1, AllocationType.Reserve | AllocationType.Commit, MemoryProtection.ReadWrite);
|
||||
if (pBase == IntPtr.Zero) {
|
||||
return new Win32Exception().PrintMsgAndReturnErrCode("VirtualAllocEx fail");
|
||||
}
|
||||
if (!WriteProcessMemory(hProc, pBase, libPath.ToCharArray(), libPath.Length, out _)) {
|
||||
return new Win32Exception().PrintMsgAndReturnErrCode("WriteProcessMemory fail");
|
||||
}
|
||||
var hThread = CreateRemoteThread(hProc, IntPtr.Zero, 0, pLoadLibrary, pBase, 0, out _);
|
||||
if (hThread == IntPtr.Zero) {
|
||||
var e = new Win32Exception();
|
||||
VirtualFreeEx(hProc, pBase, 0, AllocationType.Release);
|
||||
return e.PrintMsgAndReturnErrCode("CreateRemoteThread fail");
|
||||
}
|
||||
if (WaitForSingleObject(hThread, 2000) == 0) {
|
||||
VirtualFreeEx(hProc, pBase, 0, AllocationType.Release);
|
||||
}
|
||||
return !CloseHandle(hThread) ? new Win32Exception().PrintMsgAndReturnErrCode("CloseHandle fail") : 0;
|
||||
}
|
||||
|
||||
}
|
||||
43
src/Program.cs
Normal file
43
src/Program.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using YaeAchievement;
|
||||
using YaeAchievement.AppCenterSDK;
|
||||
using YaeAchievement.AppCenterSDK.Models;
|
||||
using static YaeAchievement.Utils;
|
||||
|
||||
InstallExitHook();
|
||||
|
||||
CheckVcRuntime();
|
||||
CheckIsTempDir();
|
||||
CheckSelfIsRunning();
|
||||
TryDisableQuickEdit();
|
||||
InstallExceptionHook();
|
||||
CheckGenshinIsRunning();
|
||||
|
||||
Console.WriteLine("----------------------------------------------------");
|
||||
Console.WriteLine($"YaeAchievement - 原神成就导出工具 ({GlobalVars.AppVersionName})");
|
||||
Console.WriteLine("https://github.com/HolographicHat/YaeAchievement");
|
||||
Console.WriteLine("----------------------------------------------------");
|
||||
|
||||
AppConfig.Load();
|
||||
CheckUpdate();
|
||||
AppCenter.Init();
|
||||
new EventLog("AppInit") {
|
||||
Properties = {
|
||||
{ "AppVersion", GlobalVars.AppVersionName },
|
||||
{ "SystemVersion", DeviceHelper.GetSystemVersion() }
|
||||
}
|
||||
}.Enqueue();
|
||||
var historyCache = new CacheFile("ExportData");
|
||||
if (historyCache.LastWriteTime.AddMinutes(10) > DateTime.UtcNow) {
|
||||
Console.WriteLine("使用上一次获取到的成就数据");
|
||||
Console.WriteLine("要重新获取数据,手动删除 cache\\d1a8ef40a67a5929.miko 后重新启动 YaeAchievement");
|
||||
Export.Choose(AchievementAllDataNotify.Parser.ParseFrom(historyCache.Read().Content));
|
||||
} else {
|
||||
StartAndWaitResult(AppConfig.GamePath, str => {
|
||||
GlobalVars.UnexpectedExit = false;
|
||||
var data = Convert.FromBase64String(str);
|
||||
var list = AchievementAllDataNotify.Parser.ParseFrom(data);
|
||||
historyCache.Write(data);
|
||||
Export.Choose(list);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
584
src/Proto/AchievementAllDataNotify.cs
Normal file
584
src/Proto/AchievementAllDataNotify.cs
Normal file
@@ -0,0 +1,584 @@
|
||||
// <auto-generated>
|
||||
// Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
// source: AchievementAllDataNotify.proto
|
||||
// </auto-generated>
|
||||
#pragma warning disable 1591, 0612, 3021, 8981
|
||||
#region Designer generated code
|
||||
|
||||
using pb = global::Google.Protobuf;
|
||||
using pbc = global::Google.Protobuf.Collections;
|
||||
using pbr = global::Google.Protobuf.Reflection;
|
||||
using scg = global::System.Collections.Generic;
|
||||
/// <summary>Holder for reflection information generated from AchievementAllDataNotify.proto</summary>
|
||||
public static partial class AchievementAllDataNotifyReflection {
|
||||
|
||||
#region Descriptor
|
||||
/// <summary>File descriptor for AchievementAllDataNotify.proto</summary>
|
||||
public static pbr::FileDescriptor Descriptor {
|
||||
get { return descriptor; }
|
||||
}
|
||||
private static pbr::FileDescriptor descriptor;
|
||||
|
||||
static AchievementAllDataNotifyReflection() {
|
||||
byte[] descriptorData = global::System.Convert.FromBase64String(
|
||||
string.Concat(
|
||||
"Ch5BY2hpZXZlbWVudEFsbERhdGFOb3RpZnkucHJvdG8iowIKGEFjaGlldmVt",
|
||||
"ZW50QWxsRGF0YU5vdGlmeRIzCgRsaXN0GAQgAygLMiUuQWNoaWV2ZW1lbnRB",
|
||||
"bGxEYXRhTm90aWZ5LkFjaGlldmVtZW50GtEBCgtBY2hpZXZlbWVudBIKCgJp",
|
||||
"ZBgOIAEoDRI8CgZzdGF0dXMYDSABKA4yLC5BY2hpZXZlbWVudEFsbERhdGFO",
|
||||
"b3RpZnkuQWNoaWV2ZW1lbnQuU3RhdHVzEg8KB2N1cnJlbnQYDCABKA0SDQoF",
|
||||
"dG90YWwYCCABKA0SEQoJdGltZXN0YW1wGAsgASgNIkUKBlN0YXR1cxILCgdJ",
|
||||
"TlZBTElEEAASDgoKVU5GSU5JU0hFRBABEgwKCEZJTklTSEVEEAISEAoMUkVX",
|
||||
"QVJEX1RBS0VOEANiBnByb3RvMw=="));
|
||||
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
|
||||
new pbr::FileDescriptor[] { },
|
||||
new pbr::GeneratedClrTypeInfo(null, null, new pbr::GeneratedClrTypeInfo[] {
|
||||
new pbr::GeneratedClrTypeInfo(typeof(global::AchievementAllDataNotify), global::AchievementAllDataNotify.Parser, new[]{ "List" }, null, null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::AchievementAllDataNotify.Types.Achievement), global::AchievementAllDataNotify.Types.Achievement.Parser, new[]{ "Id", "Status", "Current", "Total", "Timestamp" }, null, new[]{ typeof(global::AchievementAllDataNotify.Types.Achievement.Types.Status) }, null, null)})
|
||||
}));
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
#region Messages
|
||||
public sealed partial class AchievementAllDataNotify : pb::IMessage<AchievementAllDataNotify>
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
|
||||
, pb::IBufferMessage
|
||||
#endif
|
||||
{
|
||||
private static readonly pb::MessageParser<AchievementAllDataNotify> _parser = new pb::MessageParser<AchievementAllDataNotify>(() => new AchievementAllDataNotify());
|
||||
private pb::UnknownFieldSet _unknownFields;
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public static pb::MessageParser<AchievementAllDataNotify> Parser { get { return _parser; } }
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public static pbr::MessageDescriptor Descriptor {
|
||||
get { return global::AchievementAllDataNotifyReflection.Descriptor.MessageTypes[0]; }
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
pbr::MessageDescriptor pb::IMessage.Descriptor {
|
||||
get { return Descriptor; }
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public AchievementAllDataNotify() {
|
||||
OnConstruction();
|
||||
}
|
||||
|
||||
partial void OnConstruction();
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public AchievementAllDataNotify(AchievementAllDataNotify other) : this() {
|
||||
list_ = other.list_.Clone();
|
||||
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public AchievementAllDataNotify Clone() {
|
||||
return new AchievementAllDataNotify(this);
|
||||
}
|
||||
|
||||
/// <summary>Field number for the "list" field.</summary>
|
||||
public const int ListFieldNumber = 4;
|
||||
private static readonly pb::FieldCodec<global::AchievementAllDataNotify.Types.Achievement> _repeated_list_codec
|
||||
= pb::FieldCodec.ForMessage(34, global::AchievementAllDataNotify.Types.Achievement.Parser);
|
||||
private readonly pbc::RepeatedField<global::AchievementAllDataNotify.Types.Achievement> list_ = new pbc::RepeatedField<global::AchievementAllDataNotify.Types.Achievement>();
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public pbc::RepeatedField<global::AchievementAllDataNotify.Types.Achievement> List {
|
||||
get { return list_; }
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public override bool Equals(object other) {
|
||||
return Equals(other as AchievementAllDataNotify);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public bool Equals(AchievementAllDataNotify other) {
|
||||
if (ReferenceEquals(other, null)) {
|
||||
return false;
|
||||
}
|
||||
if (ReferenceEquals(other, this)) {
|
||||
return true;
|
||||
}
|
||||
if(!list_.Equals(other.list_)) return false;
|
||||
return Equals(_unknownFields, other._unknownFields);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public override int GetHashCode() {
|
||||
int hash = 1;
|
||||
hash ^= list_.GetHashCode();
|
||||
if (_unknownFields != null) {
|
||||
hash ^= _unknownFields.GetHashCode();
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public override string ToString() {
|
||||
return pb::JsonFormatter.ToDiagnosticString(this);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public void WriteTo(pb::CodedOutputStream output) {
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
|
||||
output.WriteRawMessage(this);
|
||||
#else
|
||||
list_.WriteTo(output, _repeated_list_codec);
|
||||
if (_unknownFields != null) {
|
||||
_unknownFields.WriteTo(output);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
|
||||
list_.WriteTo(ref output, _repeated_list_codec);
|
||||
if (_unknownFields != null) {
|
||||
_unknownFields.WriteTo(ref output);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public int CalculateSize() {
|
||||
int size = 0;
|
||||
size += list_.CalculateSize(_repeated_list_codec);
|
||||
if (_unknownFields != null) {
|
||||
size += _unknownFields.CalculateSize();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public void MergeFrom(AchievementAllDataNotify other) {
|
||||
if (other == null) {
|
||||
return;
|
||||
}
|
||||
list_.Add(other.list_);
|
||||
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public void MergeFrom(pb::CodedInputStream input) {
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
|
||||
input.ReadRawMessage(this);
|
||||
#else
|
||||
uint tag;
|
||||
while ((tag = input.ReadTag()) != 0) {
|
||||
switch(tag) {
|
||||
default:
|
||||
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
|
||||
break;
|
||||
case 34: {
|
||||
list_.AddEntriesFrom(input, _repeated_list_codec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
|
||||
uint tag;
|
||||
while ((tag = input.ReadTag()) != 0) {
|
||||
switch(tag) {
|
||||
default:
|
||||
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
|
||||
break;
|
||||
case 34: {
|
||||
list_.AddEntriesFrom(ref input, _repeated_list_codec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#region Nested types
|
||||
/// <summary>Container for nested types declared in the AchievementAllDataNotify message type.</summary>
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public static partial class Types {
|
||||
public sealed partial class Achievement : pb::IMessage<Achievement>
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
|
||||
, pb::IBufferMessage
|
||||
#endif
|
||||
{
|
||||
private static readonly pb::MessageParser<Achievement> _parser = new pb::MessageParser<Achievement>(() => new Achievement());
|
||||
private pb::UnknownFieldSet _unknownFields;
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public static pb::MessageParser<Achievement> Parser { get { return _parser; } }
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public static pbr::MessageDescriptor Descriptor {
|
||||
get { return global::AchievementAllDataNotify.Descriptor.NestedTypes[0]; }
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
pbr::MessageDescriptor pb::IMessage.Descriptor {
|
||||
get { return Descriptor; }
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public Achievement() {
|
||||
OnConstruction();
|
||||
}
|
||||
|
||||
partial void OnConstruction();
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public Achievement(Achievement other) : this() {
|
||||
id_ = other.id_;
|
||||
status_ = other.status_;
|
||||
current_ = other.current_;
|
||||
total_ = other.total_;
|
||||
timestamp_ = other.timestamp_;
|
||||
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public Achievement Clone() {
|
||||
return new Achievement(this);
|
||||
}
|
||||
|
||||
/// <summary>Field number for the "id" field.</summary>
|
||||
public const int IdFieldNumber = 14;
|
||||
private uint id_;
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public uint Id {
|
||||
get { return id_; }
|
||||
set {
|
||||
id_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Field number for the "status" field.</summary>
|
||||
public const int StatusFieldNumber = 13;
|
||||
private global::AchievementAllDataNotify.Types.Achievement.Types.Status status_ = global::AchievementAllDataNotify.Types.Achievement.Types.Status.Invalid;
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public global::AchievementAllDataNotify.Types.Achievement.Types.Status Status {
|
||||
get { return status_; }
|
||||
set {
|
||||
status_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Field number for the "current" field.</summary>
|
||||
public const int CurrentFieldNumber = 12;
|
||||
private uint current_;
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public uint Current {
|
||||
get { return current_; }
|
||||
set {
|
||||
current_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Field number for the "total" field.</summary>
|
||||
public const int TotalFieldNumber = 8;
|
||||
private uint total_;
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public uint Total {
|
||||
get { return total_; }
|
||||
set {
|
||||
total_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Field number for the "timestamp" field.</summary>
|
||||
public const int TimestampFieldNumber = 11;
|
||||
private uint timestamp_;
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public uint Timestamp {
|
||||
get { return timestamp_; }
|
||||
set {
|
||||
timestamp_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public override bool Equals(object other) {
|
||||
return Equals(other as Achievement);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public bool Equals(Achievement other) {
|
||||
if (ReferenceEquals(other, null)) {
|
||||
return false;
|
||||
}
|
||||
if (ReferenceEquals(other, this)) {
|
||||
return true;
|
||||
}
|
||||
if (Id != other.Id) return false;
|
||||
if (Status != other.Status) return false;
|
||||
if (Current != other.Current) return false;
|
||||
if (Total != other.Total) return false;
|
||||
if (Timestamp != other.Timestamp) return false;
|
||||
return Equals(_unknownFields, other._unknownFields);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public override int GetHashCode() {
|
||||
int hash = 1;
|
||||
if (Id != 0) hash ^= Id.GetHashCode();
|
||||
if (Status != global::AchievementAllDataNotify.Types.Achievement.Types.Status.Invalid) hash ^= Status.GetHashCode();
|
||||
if (Current != 0) hash ^= Current.GetHashCode();
|
||||
if (Total != 0) hash ^= Total.GetHashCode();
|
||||
if (Timestamp != 0) hash ^= Timestamp.GetHashCode();
|
||||
if (_unknownFields != null) {
|
||||
hash ^= _unknownFields.GetHashCode();
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public override string ToString() {
|
||||
return pb::JsonFormatter.ToDiagnosticString(this);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public void WriteTo(pb::CodedOutputStream output) {
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
|
||||
output.WriteRawMessage(this);
|
||||
#else
|
||||
if (Total != 0) {
|
||||
output.WriteRawTag(64);
|
||||
output.WriteUInt32(Total);
|
||||
}
|
||||
if (Timestamp != 0) {
|
||||
output.WriteRawTag(88);
|
||||
output.WriteUInt32(Timestamp);
|
||||
}
|
||||
if (Current != 0) {
|
||||
output.WriteRawTag(96);
|
||||
output.WriteUInt32(Current);
|
||||
}
|
||||
if (Status != global::AchievementAllDataNotify.Types.Achievement.Types.Status.Invalid) {
|
||||
output.WriteRawTag(104);
|
||||
output.WriteEnum((int) Status);
|
||||
}
|
||||
if (Id != 0) {
|
||||
output.WriteRawTag(112);
|
||||
output.WriteUInt32(Id);
|
||||
}
|
||||
if (_unknownFields != null) {
|
||||
_unknownFields.WriteTo(output);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
|
||||
if (Total != 0) {
|
||||
output.WriteRawTag(64);
|
||||
output.WriteUInt32(Total);
|
||||
}
|
||||
if (Timestamp != 0) {
|
||||
output.WriteRawTag(88);
|
||||
output.WriteUInt32(Timestamp);
|
||||
}
|
||||
if (Current != 0) {
|
||||
output.WriteRawTag(96);
|
||||
output.WriteUInt32(Current);
|
||||
}
|
||||
if (Status != global::AchievementAllDataNotify.Types.Achievement.Types.Status.Invalid) {
|
||||
output.WriteRawTag(104);
|
||||
output.WriteEnum((int) Status);
|
||||
}
|
||||
if (Id != 0) {
|
||||
output.WriteRawTag(112);
|
||||
output.WriteUInt32(Id);
|
||||
}
|
||||
if (_unknownFields != null) {
|
||||
_unknownFields.WriteTo(ref output);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public int CalculateSize() {
|
||||
int size = 0;
|
||||
if (Id != 0) {
|
||||
size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Id);
|
||||
}
|
||||
if (Status != global::AchievementAllDataNotify.Types.Achievement.Types.Status.Invalid) {
|
||||
size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Status);
|
||||
}
|
||||
if (Current != 0) {
|
||||
size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Current);
|
||||
}
|
||||
if (Total != 0) {
|
||||
size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Total);
|
||||
}
|
||||
if (Timestamp != 0) {
|
||||
size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Timestamp);
|
||||
}
|
||||
if (_unknownFields != null) {
|
||||
size += _unknownFields.CalculateSize();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public void MergeFrom(Achievement other) {
|
||||
if (other == null) {
|
||||
return;
|
||||
}
|
||||
if (other.Id != 0) {
|
||||
Id = other.Id;
|
||||
}
|
||||
if (other.Status != global::AchievementAllDataNotify.Types.Achievement.Types.Status.Invalid) {
|
||||
Status = other.Status;
|
||||
}
|
||||
if (other.Current != 0) {
|
||||
Current = other.Current;
|
||||
}
|
||||
if (other.Total != 0) {
|
||||
Total = other.Total;
|
||||
}
|
||||
if (other.Timestamp != 0) {
|
||||
Timestamp = other.Timestamp;
|
||||
}
|
||||
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public void MergeFrom(pb::CodedInputStream input) {
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
|
||||
input.ReadRawMessage(this);
|
||||
#else
|
||||
uint tag;
|
||||
while ((tag = input.ReadTag()) != 0) {
|
||||
switch(tag) {
|
||||
default:
|
||||
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
|
||||
break;
|
||||
case 64: {
|
||||
Total = input.ReadUInt32();
|
||||
break;
|
||||
}
|
||||
case 88: {
|
||||
Timestamp = input.ReadUInt32();
|
||||
break;
|
||||
}
|
||||
case 96: {
|
||||
Current = input.ReadUInt32();
|
||||
break;
|
||||
}
|
||||
case 104: {
|
||||
Status = (global::AchievementAllDataNotify.Types.Achievement.Types.Status) input.ReadEnum();
|
||||
break;
|
||||
}
|
||||
case 112: {
|
||||
Id = input.ReadUInt32();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
|
||||
uint tag;
|
||||
while ((tag = input.ReadTag()) != 0) {
|
||||
switch(tag) {
|
||||
default:
|
||||
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
|
||||
break;
|
||||
case 64: {
|
||||
Total = input.ReadUInt32();
|
||||
break;
|
||||
}
|
||||
case 88: {
|
||||
Timestamp = input.ReadUInt32();
|
||||
break;
|
||||
}
|
||||
case 96: {
|
||||
Current = input.ReadUInt32();
|
||||
break;
|
||||
}
|
||||
case 104: {
|
||||
Status = (global::AchievementAllDataNotify.Types.Achievement.Types.Status) input.ReadEnum();
|
||||
break;
|
||||
}
|
||||
case 112: {
|
||||
Id = input.ReadUInt32();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#region Nested types
|
||||
/// <summary>Container for nested types declared in the Achievement message type.</summary>
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public static partial class Types {
|
||||
public enum Status {
|
||||
[pbr::OriginalName("INVALID")] Invalid = 0,
|
||||
[pbr::OriginalName("UNFINISHED")] Unfinished = 1,
|
||||
[pbr::OriginalName("FINISHED")] Finished = 2,
|
||||
[pbr::OriginalName("REWARD_TAKEN")] RewardTaken = 3,
|
||||
}
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#endregion Designer generated code
|
||||
588
src/Proto/AchievementInfo.cs
Normal file
588
src/Proto/AchievementInfo.cs
Normal file
@@ -0,0 +1,588 @@
|
||||
// <auto-generated>
|
||||
// Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
// source: AchievementInfo.proto
|
||||
// </auto-generated>
|
||||
#pragma warning disable 1591, 0612, 3021, 8981
|
||||
#region Designer generated code
|
||||
|
||||
using pb = global::Google.Protobuf;
|
||||
using pbc = global::Google.Protobuf.Collections;
|
||||
using pbr = global::Google.Protobuf.Reflection;
|
||||
using scg = global::System.Collections.Generic;
|
||||
/// <summary>Holder for reflection information generated from AchievementInfo.proto</summary>
|
||||
public static partial class AchievementInfoReflection {
|
||||
|
||||
#region Descriptor
|
||||
/// <summary>File descriptor for AchievementInfo.proto</summary>
|
||||
public static pbr::FileDescriptor Descriptor {
|
||||
get { return descriptor; }
|
||||
}
|
||||
private static pbr::FileDescriptor descriptor;
|
||||
|
||||
static AchievementInfoReflection() {
|
||||
byte[] descriptorData = global::System.Convert.FromBase64String(
|
||||
string.Concat(
|
||||
"ChVBY2hpZXZlbWVudEluZm8ucHJvdG8iUAoPQWNoaWV2ZW1lbnRJdGVtEgsK",
|
||||
"A3ByZRgBIAEoDRINCgVncm91cBgCIAEoDRIMCgRuYW1lGAMgASgJEhMKC2Rl",
|
||||
"c2NyaXB0aW9uGAQgASgJIugBCg9BY2hpZXZlbWVudEluZm8SDwoHdmVyc2lv",
|
||||
"bhgBIAEoCRIqCgVncm91cBgCIAMoCzIbLkFjaGlldmVtZW50SW5mby5Hcm91",
|
||||
"cEVudHJ5EioKBWl0ZW1zGAMgAygLMhsuQWNoaWV2ZW1lbnRJbmZvLkl0ZW1z",
|
||||
"RW50cnkaLAoKR3JvdXBFbnRyeRILCgNrZXkYASABKA0SDQoFdmFsdWUYAiAB",
|
||||
"KAk6AjgBGj4KCkl0ZW1zRW50cnkSCwoDa2V5GAEgASgNEh8KBXZhbHVlGAIg",
|
||||
"ASgLMhAuQWNoaWV2ZW1lbnRJdGVtOgI4AWIGcHJvdG8z"));
|
||||
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
|
||||
new pbr::FileDescriptor[] { },
|
||||
new pbr::GeneratedClrTypeInfo(null, null, new pbr::GeneratedClrTypeInfo[] {
|
||||
new pbr::GeneratedClrTypeInfo(typeof(global::AchievementItem), global::AchievementItem.Parser, new[]{ "Pre", "Group", "Name", "Description" }, null, null, null, null),
|
||||
new pbr::GeneratedClrTypeInfo(typeof(global::AchievementInfo), global::AchievementInfo.Parser, new[]{ "Version", "Group", "Items" }, null, null, null, new pbr::GeneratedClrTypeInfo[] { null, null, })
|
||||
}));
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
#region Messages
|
||||
public sealed partial class AchievementItem : pb::IMessage<AchievementItem>
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
|
||||
, pb::IBufferMessage
|
||||
#endif
|
||||
{
|
||||
private static readonly pb::MessageParser<AchievementItem> _parser = new pb::MessageParser<AchievementItem>(() => new AchievementItem());
|
||||
private pb::UnknownFieldSet _unknownFields;
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public static pb::MessageParser<AchievementItem> Parser { get { return _parser; } }
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public static pbr::MessageDescriptor Descriptor {
|
||||
get { return global::AchievementInfoReflection.Descriptor.MessageTypes[0]; }
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
pbr::MessageDescriptor pb::IMessage.Descriptor {
|
||||
get { return Descriptor; }
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public AchievementItem() {
|
||||
OnConstruction();
|
||||
}
|
||||
|
||||
partial void OnConstruction();
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public AchievementItem(AchievementItem other) : this() {
|
||||
pre_ = other.pre_;
|
||||
group_ = other.group_;
|
||||
name_ = other.name_;
|
||||
description_ = other.description_;
|
||||
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public AchievementItem Clone() {
|
||||
return new AchievementItem(this);
|
||||
}
|
||||
|
||||
/// <summary>Field number for the "pre" field.</summary>
|
||||
public const int PreFieldNumber = 1;
|
||||
private uint pre_;
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public uint Pre {
|
||||
get { return pre_; }
|
||||
set {
|
||||
pre_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Field number for the "group" field.</summary>
|
||||
public const int GroupFieldNumber = 2;
|
||||
private uint group_;
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public uint Group {
|
||||
get { return group_; }
|
||||
set {
|
||||
group_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Field number for the "name" field.</summary>
|
||||
public const int NameFieldNumber = 3;
|
||||
private string name_ = "";
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public string Name {
|
||||
get { return name_; }
|
||||
set {
|
||||
name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Field number for the "description" field.</summary>
|
||||
public const int DescriptionFieldNumber = 4;
|
||||
private string description_ = "";
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public string Description {
|
||||
get { return description_; }
|
||||
set {
|
||||
description_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public override bool Equals(object other) {
|
||||
return Equals(other as AchievementItem);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public bool Equals(AchievementItem other) {
|
||||
if (ReferenceEquals(other, null)) {
|
||||
return false;
|
||||
}
|
||||
if (ReferenceEquals(other, this)) {
|
||||
return true;
|
||||
}
|
||||
if (Pre != other.Pre) return false;
|
||||
if (Group != other.Group) return false;
|
||||
if (Name != other.Name) return false;
|
||||
if (Description != other.Description) return false;
|
||||
return Equals(_unknownFields, other._unknownFields);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public override int GetHashCode() {
|
||||
int hash = 1;
|
||||
if (Pre != 0) hash ^= Pre.GetHashCode();
|
||||
if (Group != 0) hash ^= Group.GetHashCode();
|
||||
if (Name.Length != 0) hash ^= Name.GetHashCode();
|
||||
if (Description.Length != 0) hash ^= Description.GetHashCode();
|
||||
if (_unknownFields != null) {
|
||||
hash ^= _unknownFields.GetHashCode();
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public override string ToString() {
|
||||
return pb::JsonFormatter.ToDiagnosticString(this);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public void WriteTo(pb::CodedOutputStream output) {
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
|
||||
output.WriteRawMessage(this);
|
||||
#else
|
||||
if (Pre != 0) {
|
||||
output.WriteRawTag(8);
|
||||
output.WriteUInt32(Pre);
|
||||
}
|
||||
if (Group != 0) {
|
||||
output.WriteRawTag(16);
|
||||
output.WriteUInt32(Group);
|
||||
}
|
||||
if (Name.Length != 0) {
|
||||
output.WriteRawTag(26);
|
||||
output.WriteString(Name);
|
||||
}
|
||||
if (Description.Length != 0) {
|
||||
output.WriteRawTag(34);
|
||||
output.WriteString(Description);
|
||||
}
|
||||
if (_unknownFields != null) {
|
||||
_unknownFields.WriteTo(output);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
|
||||
if (Pre != 0) {
|
||||
output.WriteRawTag(8);
|
||||
output.WriteUInt32(Pre);
|
||||
}
|
||||
if (Group != 0) {
|
||||
output.WriteRawTag(16);
|
||||
output.WriteUInt32(Group);
|
||||
}
|
||||
if (Name.Length != 0) {
|
||||
output.WriteRawTag(26);
|
||||
output.WriteString(Name);
|
||||
}
|
||||
if (Description.Length != 0) {
|
||||
output.WriteRawTag(34);
|
||||
output.WriteString(Description);
|
||||
}
|
||||
if (_unknownFields != null) {
|
||||
_unknownFields.WriteTo(ref output);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public int CalculateSize() {
|
||||
int size = 0;
|
||||
if (Pre != 0) {
|
||||
size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Pre);
|
||||
}
|
||||
if (Group != 0) {
|
||||
size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Group);
|
||||
}
|
||||
if (Name.Length != 0) {
|
||||
size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
|
||||
}
|
||||
if (Description.Length != 0) {
|
||||
size += 1 + pb::CodedOutputStream.ComputeStringSize(Description);
|
||||
}
|
||||
if (_unknownFields != null) {
|
||||
size += _unknownFields.CalculateSize();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public void MergeFrom(AchievementItem other) {
|
||||
if (other == null) {
|
||||
return;
|
||||
}
|
||||
if (other.Pre != 0) {
|
||||
Pre = other.Pre;
|
||||
}
|
||||
if (other.Group != 0) {
|
||||
Group = other.Group;
|
||||
}
|
||||
if (other.Name.Length != 0) {
|
||||
Name = other.Name;
|
||||
}
|
||||
if (other.Description.Length != 0) {
|
||||
Description = other.Description;
|
||||
}
|
||||
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public void MergeFrom(pb::CodedInputStream input) {
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
|
||||
input.ReadRawMessage(this);
|
||||
#else
|
||||
uint tag;
|
||||
while ((tag = input.ReadTag()) != 0) {
|
||||
switch(tag) {
|
||||
default:
|
||||
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
|
||||
break;
|
||||
case 8: {
|
||||
Pre = input.ReadUInt32();
|
||||
break;
|
||||
}
|
||||
case 16: {
|
||||
Group = input.ReadUInt32();
|
||||
break;
|
||||
}
|
||||
case 26: {
|
||||
Name = input.ReadString();
|
||||
break;
|
||||
}
|
||||
case 34: {
|
||||
Description = input.ReadString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
|
||||
uint tag;
|
||||
while ((tag = input.ReadTag()) != 0) {
|
||||
switch(tag) {
|
||||
default:
|
||||
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
|
||||
break;
|
||||
case 8: {
|
||||
Pre = input.ReadUInt32();
|
||||
break;
|
||||
}
|
||||
case 16: {
|
||||
Group = input.ReadUInt32();
|
||||
break;
|
||||
}
|
||||
case 26: {
|
||||
Name = input.ReadString();
|
||||
break;
|
||||
}
|
||||
case 34: {
|
||||
Description = input.ReadString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
public sealed partial class AchievementInfo : pb::IMessage<AchievementInfo>
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
|
||||
, pb::IBufferMessage
|
||||
#endif
|
||||
{
|
||||
private static readonly pb::MessageParser<AchievementInfo> _parser = new pb::MessageParser<AchievementInfo>(() => new AchievementInfo());
|
||||
private pb::UnknownFieldSet _unknownFields;
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public static pb::MessageParser<AchievementInfo> Parser { get { return _parser; } }
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public static pbr::MessageDescriptor Descriptor {
|
||||
get { return global::AchievementInfoReflection.Descriptor.MessageTypes[1]; }
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
pbr::MessageDescriptor pb::IMessage.Descriptor {
|
||||
get { return Descriptor; }
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public AchievementInfo() {
|
||||
OnConstruction();
|
||||
}
|
||||
|
||||
partial void OnConstruction();
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public AchievementInfo(AchievementInfo other) : this() {
|
||||
version_ = other.version_;
|
||||
group_ = other.group_.Clone();
|
||||
items_ = other.items_.Clone();
|
||||
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public AchievementInfo Clone() {
|
||||
return new AchievementInfo(this);
|
||||
}
|
||||
|
||||
/// <summary>Field number for the "version" field.</summary>
|
||||
public const int VersionFieldNumber = 1;
|
||||
private string version_ = "";
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public string Version {
|
||||
get { return version_; }
|
||||
set {
|
||||
version_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Field number for the "group" field.</summary>
|
||||
public const int GroupFieldNumber = 2;
|
||||
private static readonly pbc::MapField<uint, string>.Codec _map_group_codec
|
||||
= new pbc::MapField<uint, string>.Codec(pb::FieldCodec.ForUInt32(8, 0), pb::FieldCodec.ForString(18, ""), 18);
|
||||
private readonly pbc::MapField<uint, string> group_ = new pbc::MapField<uint, string>();
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public pbc::MapField<uint, string> Group {
|
||||
get { return group_; }
|
||||
}
|
||||
|
||||
/// <summary>Field number for the "items" field.</summary>
|
||||
public const int ItemsFieldNumber = 3;
|
||||
private static readonly pbc::MapField<uint, global::AchievementItem>.Codec _map_items_codec
|
||||
= new pbc::MapField<uint, global::AchievementItem>.Codec(pb::FieldCodec.ForUInt32(8, 0), pb::FieldCodec.ForMessage(18, global::AchievementItem.Parser), 26);
|
||||
private readonly pbc::MapField<uint, global::AchievementItem> items_ = new pbc::MapField<uint, global::AchievementItem>();
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public pbc::MapField<uint, global::AchievementItem> Items {
|
||||
get { return items_; }
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public override bool Equals(object other) {
|
||||
return Equals(other as AchievementInfo);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public bool Equals(AchievementInfo other) {
|
||||
if (ReferenceEquals(other, null)) {
|
||||
return false;
|
||||
}
|
||||
if (ReferenceEquals(other, this)) {
|
||||
return true;
|
||||
}
|
||||
if (Version != other.Version) return false;
|
||||
if (!Group.Equals(other.Group)) return false;
|
||||
if (!Items.Equals(other.Items)) return false;
|
||||
return Equals(_unknownFields, other._unknownFields);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public override int GetHashCode() {
|
||||
int hash = 1;
|
||||
if (Version.Length != 0) hash ^= Version.GetHashCode();
|
||||
hash ^= Group.GetHashCode();
|
||||
hash ^= Items.GetHashCode();
|
||||
if (_unknownFields != null) {
|
||||
hash ^= _unknownFields.GetHashCode();
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public override string ToString() {
|
||||
return pb::JsonFormatter.ToDiagnosticString(this);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public void WriteTo(pb::CodedOutputStream output) {
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
|
||||
output.WriteRawMessage(this);
|
||||
#else
|
||||
if (Version.Length != 0) {
|
||||
output.WriteRawTag(10);
|
||||
output.WriteString(Version);
|
||||
}
|
||||
group_.WriteTo(output, _map_group_codec);
|
||||
items_.WriteTo(output, _map_items_codec);
|
||||
if (_unknownFields != null) {
|
||||
_unknownFields.WriteTo(output);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
|
||||
if (Version.Length != 0) {
|
||||
output.WriteRawTag(10);
|
||||
output.WriteString(Version);
|
||||
}
|
||||
group_.WriteTo(ref output, _map_group_codec);
|
||||
items_.WriteTo(ref output, _map_items_codec);
|
||||
if (_unknownFields != null) {
|
||||
_unknownFields.WriteTo(ref output);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public int CalculateSize() {
|
||||
int size = 0;
|
||||
if (Version.Length != 0) {
|
||||
size += 1 + pb::CodedOutputStream.ComputeStringSize(Version);
|
||||
}
|
||||
size += group_.CalculateSize(_map_group_codec);
|
||||
size += items_.CalculateSize(_map_items_codec);
|
||||
if (_unknownFields != null) {
|
||||
size += _unknownFields.CalculateSize();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public void MergeFrom(AchievementInfo other) {
|
||||
if (other == null) {
|
||||
return;
|
||||
}
|
||||
if (other.Version.Length != 0) {
|
||||
Version = other.Version;
|
||||
}
|
||||
group_.Add(other.group_);
|
||||
items_.Add(other.items_);
|
||||
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public void MergeFrom(pb::CodedInputStream input) {
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
|
||||
input.ReadRawMessage(this);
|
||||
#else
|
||||
uint tag;
|
||||
while ((tag = input.ReadTag()) != 0) {
|
||||
switch(tag) {
|
||||
default:
|
||||
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
|
||||
break;
|
||||
case 10: {
|
||||
Version = input.ReadString();
|
||||
break;
|
||||
}
|
||||
case 18: {
|
||||
group_.AddEntriesFrom(input, _map_group_codec);
|
||||
break;
|
||||
}
|
||||
case 26: {
|
||||
items_.AddEntriesFrom(input, _map_items_codec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
|
||||
uint tag;
|
||||
while ((tag = input.ReadTag()) != 0) {
|
||||
switch(tag) {
|
||||
default:
|
||||
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
|
||||
break;
|
||||
case 10: {
|
||||
Version = input.ReadString();
|
||||
break;
|
||||
}
|
||||
case 18: {
|
||||
group_.AddEntriesFrom(ref input, _map_group_codec);
|
||||
break;
|
||||
}
|
||||
case 26: {
|
||||
items_.AddEntriesFrom(ref input, _map_items_codec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#endregion Designer generated code
|
||||
341
src/Proto/CacheItem.cs
Normal file
341
src/Proto/CacheItem.cs
Normal file
@@ -0,0 +1,341 @@
|
||||
// <auto-generated>
|
||||
// Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
// source: CacheItem.proto
|
||||
// </auto-generated>
|
||||
#pragma warning disable 1591, 0612, 3021, 8981
|
||||
#region Designer generated code
|
||||
|
||||
using pb = global::Google.Protobuf;
|
||||
using pbc = global::Google.Protobuf.Collections;
|
||||
using pbr = global::Google.Protobuf.Reflection;
|
||||
using scg = global::System.Collections.Generic;
|
||||
/// <summary>Holder for reflection information generated from CacheItem.proto</summary>
|
||||
public static partial class CacheItemReflection {
|
||||
|
||||
#region Descriptor
|
||||
/// <summary>File descriptor for CacheItem.proto</summary>
|
||||
public static pbr::FileDescriptor Descriptor {
|
||||
get { return descriptor; }
|
||||
}
|
||||
private static pbr::FileDescriptor descriptor;
|
||||
|
||||
static CacheItemReflection() {
|
||||
byte[] descriptorData = global::System.Convert.FromBase64String(
|
||||
string.Concat(
|
||||
"Cg9DYWNoZUl0ZW0ucHJvdG8iTQoJQ2FjaGVJdGVtEg8KB3ZlcnNpb24YASAB",
|
||||
"KAUSEAoIY2hlY2tzdW0YAiABKAkSDAoEZXRhZxgDIAEoCRIPCgdjb250ZW50",
|
||||
"GAQgASgMYgZwcm90bzM="));
|
||||
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
|
||||
new pbr::FileDescriptor[] { },
|
||||
new pbr::GeneratedClrTypeInfo(null, null, new pbr::GeneratedClrTypeInfo[] {
|
||||
new pbr::GeneratedClrTypeInfo(typeof(global::CacheItem), global::CacheItem.Parser, new[]{ "Version", "Checksum", "Etag", "Content" }, null, null, null, null)
|
||||
}));
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
#region Messages
|
||||
public sealed partial class CacheItem : pb::IMessage<CacheItem>
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
|
||||
, pb::IBufferMessage
|
||||
#endif
|
||||
{
|
||||
private static readonly pb::MessageParser<CacheItem> _parser = new pb::MessageParser<CacheItem>(() => new CacheItem());
|
||||
private pb::UnknownFieldSet _unknownFields;
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public static pb::MessageParser<CacheItem> Parser { get { return _parser; } }
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public static pbr::MessageDescriptor Descriptor {
|
||||
get { return global::CacheItemReflection.Descriptor.MessageTypes[0]; }
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
pbr::MessageDescriptor pb::IMessage.Descriptor {
|
||||
get { return Descriptor; }
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public CacheItem() {
|
||||
OnConstruction();
|
||||
}
|
||||
|
||||
partial void OnConstruction();
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public CacheItem(CacheItem other) : this() {
|
||||
version_ = other.version_;
|
||||
checksum_ = other.checksum_;
|
||||
etag_ = other.etag_;
|
||||
content_ = other.content_;
|
||||
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public CacheItem Clone() {
|
||||
return new CacheItem(this);
|
||||
}
|
||||
|
||||
/// <summary>Field number for the "version" field.</summary>
|
||||
public const int VersionFieldNumber = 1;
|
||||
private int version_;
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public int Version {
|
||||
get { return version_; }
|
||||
set {
|
||||
version_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Field number for the "checksum" field.</summary>
|
||||
public const int ChecksumFieldNumber = 2;
|
||||
private string checksum_ = "";
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public string Checksum {
|
||||
get { return checksum_; }
|
||||
set {
|
||||
checksum_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Field number for the "etag" field.</summary>
|
||||
public const int EtagFieldNumber = 3;
|
||||
private string etag_ = "";
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public string Etag {
|
||||
get { return etag_; }
|
||||
set {
|
||||
etag_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Field number for the "content" field.</summary>
|
||||
public const int ContentFieldNumber = 4;
|
||||
private pb::ByteString content_ = pb::ByteString.Empty;
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public pb::ByteString Content {
|
||||
get { return content_; }
|
||||
set {
|
||||
content_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public override bool Equals(object other) {
|
||||
return Equals(other as CacheItem);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public bool Equals(CacheItem other) {
|
||||
if (ReferenceEquals(other, null)) {
|
||||
return false;
|
||||
}
|
||||
if (ReferenceEquals(other, this)) {
|
||||
return true;
|
||||
}
|
||||
if (Version != other.Version) return false;
|
||||
if (Checksum != other.Checksum) return false;
|
||||
if (Etag != other.Etag) return false;
|
||||
if (Content != other.Content) return false;
|
||||
return Equals(_unknownFields, other._unknownFields);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public override int GetHashCode() {
|
||||
int hash = 1;
|
||||
if (Version != 0) hash ^= Version.GetHashCode();
|
||||
if (Checksum.Length != 0) hash ^= Checksum.GetHashCode();
|
||||
if (Etag.Length != 0) hash ^= Etag.GetHashCode();
|
||||
if (Content.Length != 0) hash ^= Content.GetHashCode();
|
||||
if (_unknownFields != null) {
|
||||
hash ^= _unknownFields.GetHashCode();
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public override string ToString() {
|
||||
return pb::JsonFormatter.ToDiagnosticString(this);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public void WriteTo(pb::CodedOutputStream output) {
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
|
||||
output.WriteRawMessage(this);
|
||||
#else
|
||||
if (Version != 0) {
|
||||
output.WriteRawTag(8);
|
||||
output.WriteInt32(Version);
|
||||
}
|
||||
if (Checksum.Length != 0) {
|
||||
output.WriteRawTag(18);
|
||||
output.WriteString(Checksum);
|
||||
}
|
||||
if (Etag.Length != 0) {
|
||||
output.WriteRawTag(26);
|
||||
output.WriteString(Etag);
|
||||
}
|
||||
if (Content.Length != 0) {
|
||||
output.WriteRawTag(34);
|
||||
output.WriteBytes(Content);
|
||||
}
|
||||
if (_unknownFields != null) {
|
||||
_unknownFields.WriteTo(output);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
|
||||
if (Version != 0) {
|
||||
output.WriteRawTag(8);
|
||||
output.WriteInt32(Version);
|
||||
}
|
||||
if (Checksum.Length != 0) {
|
||||
output.WriteRawTag(18);
|
||||
output.WriteString(Checksum);
|
||||
}
|
||||
if (Etag.Length != 0) {
|
||||
output.WriteRawTag(26);
|
||||
output.WriteString(Etag);
|
||||
}
|
||||
if (Content.Length != 0) {
|
||||
output.WriteRawTag(34);
|
||||
output.WriteBytes(Content);
|
||||
}
|
||||
if (_unknownFields != null) {
|
||||
_unknownFields.WriteTo(ref output);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public int CalculateSize() {
|
||||
int size = 0;
|
||||
if (Version != 0) {
|
||||
size += 1 + pb::CodedOutputStream.ComputeInt32Size(Version);
|
||||
}
|
||||
if (Checksum.Length != 0) {
|
||||
size += 1 + pb::CodedOutputStream.ComputeStringSize(Checksum);
|
||||
}
|
||||
if (Etag.Length != 0) {
|
||||
size += 1 + pb::CodedOutputStream.ComputeStringSize(Etag);
|
||||
}
|
||||
if (Content.Length != 0) {
|
||||
size += 1 + pb::CodedOutputStream.ComputeBytesSize(Content);
|
||||
}
|
||||
if (_unknownFields != null) {
|
||||
size += _unknownFields.CalculateSize();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public void MergeFrom(CacheItem other) {
|
||||
if (other == null) {
|
||||
return;
|
||||
}
|
||||
if (other.Version != 0) {
|
||||
Version = other.Version;
|
||||
}
|
||||
if (other.Checksum.Length != 0) {
|
||||
Checksum = other.Checksum;
|
||||
}
|
||||
if (other.Etag.Length != 0) {
|
||||
Etag = other.Etag;
|
||||
}
|
||||
if (other.Content.Length != 0) {
|
||||
Content = other.Content;
|
||||
}
|
||||
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public void MergeFrom(pb::CodedInputStream input) {
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
|
||||
input.ReadRawMessage(this);
|
||||
#else
|
||||
uint tag;
|
||||
while ((tag = input.ReadTag()) != 0) {
|
||||
switch(tag) {
|
||||
default:
|
||||
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
|
||||
break;
|
||||
case 8: {
|
||||
Version = input.ReadInt32();
|
||||
break;
|
||||
}
|
||||
case 18: {
|
||||
Checksum = input.ReadString();
|
||||
break;
|
||||
}
|
||||
case 26: {
|
||||
Etag = input.ReadString();
|
||||
break;
|
||||
}
|
||||
case 34: {
|
||||
Content = input.ReadBytes();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
|
||||
uint tag;
|
||||
while ((tag = input.ReadTag()) != 0) {
|
||||
switch(tag) {
|
||||
default:
|
||||
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
|
||||
break;
|
||||
case 8: {
|
||||
Version = input.ReadInt32();
|
||||
break;
|
||||
}
|
||||
case 18: {
|
||||
Checksum = input.ReadString();
|
||||
break;
|
||||
}
|
||||
case 26: {
|
||||
Etag = input.ReadString();
|
||||
break;
|
||||
}
|
||||
case 34: {
|
||||
Content = input.ReadBytes();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#endregion Designer generated code
|
||||
454
src/Proto/UpdateInfo.cs
Normal file
454
src/Proto/UpdateInfo.cs
Normal file
@@ -0,0 +1,454 @@
|
||||
// <auto-generated>
|
||||
// Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
// source: UpdateInfo.proto
|
||||
// </auto-generated>
|
||||
#pragma warning disable 1591, 0612, 3021, 8981
|
||||
#region Designer generated code
|
||||
|
||||
using pb = global::Google.Protobuf;
|
||||
using pbc = global::Google.Protobuf.Collections;
|
||||
using pbr = global::Google.Protobuf.Reflection;
|
||||
using scg = global::System.Collections.Generic;
|
||||
/// <summary>Holder for reflection information generated from UpdateInfo.proto</summary>
|
||||
public static partial class UpdateInfoReflection {
|
||||
|
||||
#region Descriptor
|
||||
/// <summary>File descriptor for UpdateInfo.proto</summary>
|
||||
public static pbr::FileDescriptor Descriptor {
|
||||
get { return descriptor; }
|
||||
}
|
||||
private static pbr::FileDescriptor descriptor;
|
||||
|
||||
static UpdateInfoReflection() {
|
||||
byte[] descriptorData = global::System.Convert.FromBase64String(
|
||||
string.Concat(
|
||||
"ChBVcGRhdGVJbmZvLnByb3RvIqwBCgpVcGRhdGVJbmZvEhMKC3ZlcnNpb25D",
|
||||
"b2RlGAEgASgNEhMKC3ZlcnNpb25OYW1lGAIgASgJEhMKC2Rlc2NyaXB0aW9u",
|
||||
"GAMgASgJEhMKC3BhY2thZ2VMaW5rGAQgASgJEhMKC2ZvcmNlVXBkYXRlGAUg",
|
||||
"ASgIEhkKEWVuYWJsZUxpYkRvd25sb2FkGAYgASgIEhoKEmVuYWJsZUF1dG9E",
|
||||
"b3dubG9hZBgHIAEoCGIGcHJvdG8z"));
|
||||
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
|
||||
new pbr::FileDescriptor[] { },
|
||||
new pbr::GeneratedClrTypeInfo(null, null, new pbr::GeneratedClrTypeInfo[] {
|
||||
new pbr::GeneratedClrTypeInfo(typeof(global::UpdateInfo), global::UpdateInfo.Parser, new[]{ "VersionCode", "VersionName", "Description", "PackageLink", "ForceUpdate", "EnableLibDownload", "EnableAutoDownload" }, null, null, null, null)
|
||||
}));
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
#region Messages
|
||||
public sealed partial class UpdateInfo : pb::IMessage<UpdateInfo>
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
|
||||
, pb::IBufferMessage
|
||||
#endif
|
||||
{
|
||||
private static readonly pb::MessageParser<UpdateInfo> _parser = new pb::MessageParser<UpdateInfo>(() => new UpdateInfo());
|
||||
private pb::UnknownFieldSet _unknownFields;
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public static pb::MessageParser<UpdateInfo> Parser { get { return _parser; } }
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public static pbr::MessageDescriptor Descriptor {
|
||||
get { return global::UpdateInfoReflection.Descriptor.MessageTypes[0]; }
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
pbr::MessageDescriptor pb::IMessage.Descriptor {
|
||||
get { return Descriptor; }
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public UpdateInfo() {
|
||||
OnConstruction();
|
||||
}
|
||||
|
||||
partial void OnConstruction();
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public UpdateInfo(UpdateInfo other) : this() {
|
||||
versionCode_ = other.versionCode_;
|
||||
versionName_ = other.versionName_;
|
||||
description_ = other.description_;
|
||||
packageLink_ = other.packageLink_;
|
||||
forceUpdate_ = other.forceUpdate_;
|
||||
enableLibDownload_ = other.enableLibDownload_;
|
||||
enableAutoDownload_ = other.enableAutoDownload_;
|
||||
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public UpdateInfo Clone() {
|
||||
return new UpdateInfo(this);
|
||||
}
|
||||
|
||||
/// <summary>Field number for the "versionCode" field.</summary>
|
||||
public const int VersionCodeFieldNumber = 1;
|
||||
private uint versionCode_;
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public uint VersionCode {
|
||||
get { return versionCode_; }
|
||||
set {
|
||||
versionCode_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Field number for the "versionName" field.</summary>
|
||||
public const int VersionNameFieldNumber = 2;
|
||||
private string versionName_ = "";
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public string VersionName {
|
||||
get { return versionName_; }
|
||||
set {
|
||||
versionName_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Field number for the "description" field.</summary>
|
||||
public const int DescriptionFieldNumber = 3;
|
||||
private string description_ = "";
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public string Description {
|
||||
get { return description_; }
|
||||
set {
|
||||
description_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Field number for the "packageLink" field.</summary>
|
||||
public const int PackageLinkFieldNumber = 4;
|
||||
private string packageLink_ = "";
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public string PackageLink {
|
||||
get { return packageLink_; }
|
||||
set {
|
||||
packageLink_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Field number for the "forceUpdate" field.</summary>
|
||||
public const int ForceUpdateFieldNumber = 5;
|
||||
private bool forceUpdate_;
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public bool ForceUpdate {
|
||||
get { return forceUpdate_; }
|
||||
set {
|
||||
forceUpdate_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Field number for the "enableLibDownload" field.</summary>
|
||||
public const int EnableLibDownloadFieldNumber = 6;
|
||||
private bool enableLibDownload_;
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public bool EnableLibDownload {
|
||||
get { return enableLibDownload_; }
|
||||
set {
|
||||
enableLibDownload_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Field number for the "enableAutoDownload" field.</summary>
|
||||
public const int EnableAutoDownloadFieldNumber = 7;
|
||||
private bool enableAutoDownload_;
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public bool EnableAutoDownload {
|
||||
get { return enableAutoDownload_; }
|
||||
set {
|
||||
enableAutoDownload_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public override bool Equals(object other) {
|
||||
return Equals(other as UpdateInfo);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public bool Equals(UpdateInfo other) {
|
||||
if (ReferenceEquals(other, null)) {
|
||||
return false;
|
||||
}
|
||||
if (ReferenceEquals(other, this)) {
|
||||
return true;
|
||||
}
|
||||
if (VersionCode != other.VersionCode) return false;
|
||||
if (VersionName != other.VersionName) return false;
|
||||
if (Description != other.Description) return false;
|
||||
if (PackageLink != other.PackageLink) return false;
|
||||
if (ForceUpdate != other.ForceUpdate) return false;
|
||||
if (EnableLibDownload != other.EnableLibDownload) return false;
|
||||
if (EnableAutoDownload != other.EnableAutoDownload) return false;
|
||||
return Equals(_unknownFields, other._unknownFields);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public override int GetHashCode() {
|
||||
int hash = 1;
|
||||
if (VersionCode != 0) hash ^= VersionCode.GetHashCode();
|
||||
if (VersionName.Length != 0) hash ^= VersionName.GetHashCode();
|
||||
if (Description.Length != 0) hash ^= Description.GetHashCode();
|
||||
if (PackageLink.Length != 0) hash ^= PackageLink.GetHashCode();
|
||||
if (ForceUpdate != false) hash ^= ForceUpdate.GetHashCode();
|
||||
if (EnableLibDownload != false) hash ^= EnableLibDownload.GetHashCode();
|
||||
if (EnableAutoDownload != false) hash ^= EnableAutoDownload.GetHashCode();
|
||||
if (_unknownFields != null) {
|
||||
hash ^= _unknownFields.GetHashCode();
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public override string ToString() {
|
||||
return pb::JsonFormatter.ToDiagnosticString(this);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public void WriteTo(pb::CodedOutputStream output) {
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
|
||||
output.WriteRawMessage(this);
|
||||
#else
|
||||
if (VersionCode != 0) {
|
||||
output.WriteRawTag(8);
|
||||
output.WriteUInt32(VersionCode);
|
||||
}
|
||||
if (VersionName.Length != 0) {
|
||||
output.WriteRawTag(18);
|
||||
output.WriteString(VersionName);
|
||||
}
|
||||
if (Description.Length != 0) {
|
||||
output.WriteRawTag(26);
|
||||
output.WriteString(Description);
|
||||
}
|
||||
if (PackageLink.Length != 0) {
|
||||
output.WriteRawTag(34);
|
||||
output.WriteString(PackageLink);
|
||||
}
|
||||
if (ForceUpdate != false) {
|
||||
output.WriteRawTag(40);
|
||||
output.WriteBool(ForceUpdate);
|
||||
}
|
||||
if (EnableLibDownload != false) {
|
||||
output.WriteRawTag(48);
|
||||
output.WriteBool(EnableLibDownload);
|
||||
}
|
||||
if (EnableAutoDownload != false) {
|
||||
output.WriteRawTag(56);
|
||||
output.WriteBool(EnableAutoDownload);
|
||||
}
|
||||
if (_unknownFields != null) {
|
||||
_unknownFields.WriteTo(output);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
|
||||
if (VersionCode != 0) {
|
||||
output.WriteRawTag(8);
|
||||
output.WriteUInt32(VersionCode);
|
||||
}
|
||||
if (VersionName.Length != 0) {
|
||||
output.WriteRawTag(18);
|
||||
output.WriteString(VersionName);
|
||||
}
|
||||
if (Description.Length != 0) {
|
||||
output.WriteRawTag(26);
|
||||
output.WriteString(Description);
|
||||
}
|
||||
if (PackageLink.Length != 0) {
|
||||
output.WriteRawTag(34);
|
||||
output.WriteString(PackageLink);
|
||||
}
|
||||
if (ForceUpdate != false) {
|
||||
output.WriteRawTag(40);
|
||||
output.WriteBool(ForceUpdate);
|
||||
}
|
||||
if (EnableLibDownload != false) {
|
||||
output.WriteRawTag(48);
|
||||
output.WriteBool(EnableLibDownload);
|
||||
}
|
||||
if (EnableAutoDownload != false) {
|
||||
output.WriteRawTag(56);
|
||||
output.WriteBool(EnableAutoDownload);
|
||||
}
|
||||
if (_unknownFields != null) {
|
||||
_unknownFields.WriteTo(ref output);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public int CalculateSize() {
|
||||
int size = 0;
|
||||
if (VersionCode != 0) {
|
||||
size += 1 + pb::CodedOutputStream.ComputeUInt32Size(VersionCode);
|
||||
}
|
||||
if (VersionName.Length != 0) {
|
||||
size += 1 + pb::CodedOutputStream.ComputeStringSize(VersionName);
|
||||
}
|
||||
if (Description.Length != 0) {
|
||||
size += 1 + pb::CodedOutputStream.ComputeStringSize(Description);
|
||||
}
|
||||
if (PackageLink.Length != 0) {
|
||||
size += 1 + pb::CodedOutputStream.ComputeStringSize(PackageLink);
|
||||
}
|
||||
if (ForceUpdate != false) {
|
||||
size += 1 + 1;
|
||||
}
|
||||
if (EnableLibDownload != false) {
|
||||
size += 1 + 1;
|
||||
}
|
||||
if (EnableAutoDownload != false) {
|
||||
size += 1 + 1;
|
||||
}
|
||||
if (_unknownFields != null) {
|
||||
size += _unknownFields.CalculateSize();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public void MergeFrom(UpdateInfo other) {
|
||||
if (other == null) {
|
||||
return;
|
||||
}
|
||||
if (other.VersionCode != 0) {
|
||||
VersionCode = other.VersionCode;
|
||||
}
|
||||
if (other.VersionName.Length != 0) {
|
||||
VersionName = other.VersionName;
|
||||
}
|
||||
if (other.Description.Length != 0) {
|
||||
Description = other.Description;
|
||||
}
|
||||
if (other.PackageLink.Length != 0) {
|
||||
PackageLink = other.PackageLink;
|
||||
}
|
||||
if (other.ForceUpdate != false) {
|
||||
ForceUpdate = other.ForceUpdate;
|
||||
}
|
||||
if (other.EnableLibDownload != false) {
|
||||
EnableLibDownload = other.EnableLibDownload;
|
||||
}
|
||||
if (other.EnableAutoDownload != false) {
|
||||
EnableAutoDownload = other.EnableAutoDownload;
|
||||
}
|
||||
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public void MergeFrom(pb::CodedInputStream input) {
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
|
||||
input.ReadRawMessage(this);
|
||||
#else
|
||||
uint tag;
|
||||
while ((tag = input.ReadTag()) != 0) {
|
||||
switch(tag) {
|
||||
default:
|
||||
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
|
||||
break;
|
||||
case 8: {
|
||||
VersionCode = input.ReadUInt32();
|
||||
break;
|
||||
}
|
||||
case 18: {
|
||||
VersionName = input.ReadString();
|
||||
break;
|
||||
}
|
||||
case 26: {
|
||||
Description = input.ReadString();
|
||||
break;
|
||||
}
|
||||
case 34: {
|
||||
PackageLink = input.ReadString();
|
||||
break;
|
||||
}
|
||||
case 40: {
|
||||
ForceUpdate = input.ReadBool();
|
||||
break;
|
||||
}
|
||||
case 48: {
|
||||
EnableLibDownload = input.ReadBool();
|
||||
break;
|
||||
}
|
||||
case 56: {
|
||||
EnableAutoDownload = input.ReadBool();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
|
||||
uint tag;
|
||||
while ((tag = input.ReadTag()) != 0) {
|
||||
switch(tag) {
|
||||
default:
|
||||
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
|
||||
break;
|
||||
case 8: {
|
||||
VersionCode = input.ReadUInt32();
|
||||
break;
|
||||
}
|
||||
case 18: {
|
||||
VersionName = input.ReadString();
|
||||
break;
|
||||
}
|
||||
case 26: {
|
||||
Description = input.ReadString();
|
||||
break;
|
||||
}
|
||||
case 34: {
|
||||
PackageLink = input.ReadString();
|
||||
break;
|
||||
}
|
||||
case 40: {
|
||||
ForceUpdate = input.ReadBool();
|
||||
break;
|
||||
}
|
||||
case 48: {
|
||||
EnableLibDownload = input.ReadBool();
|
||||
break;
|
||||
}
|
||||
case 56: {
|
||||
EnableAutoDownload = input.ReadBool();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#endregion Designer generated code
|
||||
297
src/Utils.cs
Normal file
297
src/Utils.cs
Normal file
@@ -0,0 +1,297 @@
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO.Pipes;
|
||||
using System.Net;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.Win32;
|
||||
using YaeAchievement.AppCenterSDK;
|
||||
using YaeAchievement.Win32;
|
||||
using static YaeAchievement.Win32.OpenFileFlags;
|
||||
|
||||
namespace YaeAchievement;
|
||||
|
||||
public static class Utils {
|
||||
|
||||
public static readonly Lazy<HttpClient> CHttpClient = new (() => {
|
||||
var c = new HttpClient(new HttpClientHandler {
|
||||
Proxy = GlobalVars.DebugProxy ? new WebProxy("http://127.0.0.1:8888") : null,
|
||||
AutomaticDecompression = DecompressionMethods.Brotli | DecompressionMethods.GZip
|
||||
}) {
|
||||
DefaultRequestHeaders = {
|
||||
UserAgent = {
|
||||
new ProductInfoHeaderValue("YaeAchievement", GlobalVars.AppVersion.ToString(2))
|
||||
}
|
||||
}
|
||||
};
|
||||
return c;
|
||||
});
|
||||
|
||||
public static byte[] GetBucketFileAsByteArray(string path, bool cache = true) {
|
||||
using var msg = new HttpRequestMessage {
|
||||
Method = HttpMethod.Get,
|
||||
RequestUri = new Uri($"{GlobalVars.BucketHost}/{path}")
|
||||
};
|
||||
var cacheFile = new CacheFile(path);
|
||||
if (cache && cacheFile.Exists()) {
|
||||
msg.Headers.TryAddWithoutValidation("If-None-Match", $"{cacheFile.Read().Etag}");
|
||||
}
|
||||
using var response = CHttpClient.Value.Send(msg);
|
||||
if (cache && response.StatusCode == HttpStatusCode.NotModified) {
|
||||
return cacheFile.Read().Content.ToByteArray();
|
||||
}
|
||||
response.EnsureSuccessStatusCode();
|
||||
var responseBytes = response.Content.ReadAsByteArrayAsync().Result;
|
||||
if (cache) {
|
||||
var etag = response.Headers.ETag!.Tag;
|
||||
cacheFile.Write(responseBytes, etag);
|
||||
}
|
||||
return responseBytes;
|
||||
}
|
||||
|
||||
public static void CopyToClipboard(string text) {
|
||||
if (Native.OpenClipboard(IntPtr.Zero)) {
|
||||
Native.EmptyClipboard();
|
||||
var hGlobal = Marshal.AllocHGlobal((text.Length + 1) * 2);
|
||||
var hPtr = Native.GlobalLock(hGlobal);
|
||||
Marshal.Copy(text.ToCharArray(), 0, hPtr, text.Length);
|
||||
Native.GlobalUnlock(hPtr);
|
||||
Native.SetClipboardData(13, hGlobal);
|
||||
Marshal.FreeHGlobal(hGlobal);
|
||||
Native.CloseClipboard();
|
||||
} else {
|
||||
throw new Win32Exception();
|
||||
}
|
||||
}
|
||||
|
||||
public static void CheckUpdate() {
|
||||
var info = UpdateInfo.Parser.ParseFrom(GetBucketFileAsByteArray("schicksal/version"))!;
|
||||
if (GlobalVars.AppVersionCode != info.VersionCode) {
|
||||
Console.WriteLine($"有可用更新: {GlobalVars.AppVersionName} => {info.VersionName}");
|
||||
Console.WriteLine($"更新内容: \n{info.Description}");
|
||||
if (info.EnableAutoDownload) {
|
||||
Console.WriteLine("正在下载更新包...");
|
||||
var fullPath = Path.GetFullPath($"update.{Path.GetExtension(info.PackageLink)}");
|
||||
File.WriteAllBytes(fullPath, GetBucketFileAsByteArray(info.PackageLink));
|
||||
Console.WriteLine("关闭程序后, 将压缩包解压至当前目录即可完成更新.");
|
||||
ShellOpen(fullPath);
|
||||
Environment.Exit(0);
|
||||
}
|
||||
Console.WriteLine($"下载地址: {info.PackageLink}");
|
||||
if (info.ForceUpdate) {
|
||||
Environment.Exit(0);
|
||||
}
|
||||
}
|
||||
if (info.EnableLibDownload) {
|
||||
File.WriteAllBytes(GlobalVars.LibName, GetBucketFileAsByteArray("schicksal/lib.dll"));
|
||||
}
|
||||
}
|
||||
|
||||
public static void CheckSelfIsRunning() {
|
||||
Process.EnterDebugMode();
|
||||
var cur = Process.GetCurrentProcess();
|
||||
foreach (var process in Process.GetProcesses().Where(process => process.Id != cur.Id)) {
|
||||
if (process.ProcessName == cur.ProcessName) {
|
||||
Console.WriteLine("另一个实例正在运行,请关闭后重试");
|
||||
Environment.Exit(302);
|
||||
}
|
||||
}
|
||||
Process.LeaveDebugMode();
|
||||
}
|
||||
|
||||
public static void CheckIsTempDir() {
|
||||
if (GlobalVars.AppPath.Contains(Path.GetTempPath())) {
|
||||
Console.WriteLine("请将程序完整解压后再运行");
|
||||
Environment.Exit(303);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool ShellOpen(string path) {
|
||||
return new Process {
|
||||
StartInfo = {
|
||||
FileName = path,
|
||||
UseShellExecute = true
|
||||
}
|
||||
}.Start();
|
||||
}
|
||||
|
||||
public static bool CheckGamePathValid(string? path) {
|
||||
if (path == null) return false;
|
||||
var dir = Path.GetDirectoryName(path)!;
|
||||
return !GlobalVars.CheckGamePath || File.Exists(Path.Combine(dir, "UnityPlayer.dll"));
|
||||
}
|
||||
|
||||
public static string SelectGameExecutable() {
|
||||
var fnPtr = Marshal.AllocHGlobal(32768);
|
||||
Native.RtlZeroMemory(fnPtr, 32768);
|
||||
var ofn = new OpenFileName {
|
||||
file = fnPtr,
|
||||
size = Marshal.SizeOf<OpenFileName>(),
|
||||
owner = Native.GetConsoleWindow(),
|
||||
flags = Explorer | NoNetworkButton | FileMustExist | NoChangeDir,
|
||||
title = "选择主程序",
|
||||
filter = "国服/国际服主程序 (YuanShen/GenshinImpact.exe)\0YuanShen.exe;GenshinImpact.exe\0",
|
||||
maxFile = 32768
|
||||
};
|
||||
new Thread(() => {
|
||||
var handle = Native.FindWindow("#32770", "选择主程序");
|
||||
while (handle == IntPtr.Zero) {
|
||||
handle = Native.FindWindow("#32770", "选择主程序");
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
var currentThreadId = Native.GetCurrentThreadId();
|
||||
var foregroundThreadId = Native.GetWindowThreadProcessId(Native.GetForegroundWindow(), out _);
|
||||
Native.AttachThreadInput(currentThreadId, foregroundThreadId, true);
|
||||
Native.SetWindowPos(handle, new IntPtr(-1), 0, 0, 0, 0, 1 | 2);
|
||||
Native.SetForegroundWindow(handle);
|
||||
Native.AttachThreadInput(currentThreadId, foregroundThreadId, false);
|
||||
}).Start();
|
||||
if(!Native.GetOpenFileName(ofn)) {
|
||||
var err = Native.CommDlgExtendedError();
|
||||
if (err != 0) {
|
||||
throw new SystemException($"Dialog error: {err}");
|
||||
}
|
||||
Console.WriteLine("操作被取消");
|
||||
Environment.Exit(0);
|
||||
}
|
||||
var path = Marshal.PtrToStringAuto(fnPtr)!;
|
||||
Marshal.FreeHGlobal(fnPtr);
|
||||
return path;
|
||||
}
|
||||
|
||||
// ReSharper disable once UnusedMethodReturnValue.Global
|
||||
public static bool TryDisableQuickEdit() {
|
||||
var handle = Native.GetStdHandle();
|
||||
return Native.GetConsoleMode(handle, out var mode) && Native.SetConsoleMode(handle, mode&~64);
|
||||
}
|
||||
|
||||
public static void CheckGenshinIsRunning() {
|
||||
Process.EnterDebugMode();
|
||||
foreach (var process in Process.GetProcesses()) {
|
||||
if (process.ProcessName is "GenshinImpact" or "YuanShen" && !process.HasExited) {
|
||||
Console.WriteLine($"原神正在运行,请关闭后重试 ({process.Id})");
|
||||
Environment.Exit(301);
|
||||
}
|
||||
}
|
||||
Process.LeaveDebugMode();
|
||||
}
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
private static Process? proc;
|
||||
|
||||
public static void InstallExitHook() {
|
||||
AppDomain.CurrentDomain.ProcessExit += (_, _) => {
|
||||
proc?.Kill();
|
||||
Console.WriteLine("按任意键退出");
|
||||
Console.ReadKey();
|
||||
};
|
||||
}
|
||||
|
||||
public static void InstallExceptionHook() {
|
||||
AppDomain.CurrentDomain.UnhandledException += (_, e) => {
|
||||
Console.WriteLine(e.ExceptionObject.ToString());
|
||||
Console.WriteLine("正在上报错误信息...");
|
||||
AppCenter.TrackCrash((Exception) e.ExceptionObject);
|
||||
AppCenter.Upload();
|
||||
Environment.Exit(-1);
|
||||
};
|
||||
}
|
||||
|
||||
// ReSharper disable once UnusedMethodReturnValue.Global
|
||||
public static Thread StartAndWaitResult(string exePath, Func<string, bool> onReceive) {
|
||||
const string lib = "C:/ProgramData/yae.dll";
|
||||
File.Copy(Path.GetFullPath(GlobalVars.LibName), lib, true);
|
||||
AppDomain.CurrentDomain.ProcessExit += (_, _) => {
|
||||
File.Delete(lib);
|
||||
};
|
||||
if (!Injector.CreateProcess(exePath, out var hProcess, out var hThread, out var pid)) {
|
||||
Environment.Exit(new Win32Exception().PrintMsgAndReturnErrCode("ICreateProcess fail"));
|
||||
}
|
||||
if (Injector.LoadLibraryAndInject(hProcess, lib) != 0) {
|
||||
if (!Native.TerminateProcess(hProcess, 0)) {
|
||||
Environment.Exit(new Win32Exception().PrintMsgAndReturnErrCode("TerminateProcess fail"));
|
||||
}
|
||||
}
|
||||
Console.WriteLine($"原神正在启动 ({pid})");
|
||||
proc = Process.GetProcessById(Convert.ToInt32(pid));
|
||||
proc.EnableRaisingEvents = true;
|
||||
proc.Exited += (_, _) => {
|
||||
if (GlobalVars.UnexpectedExit) {
|
||||
proc = null;
|
||||
Console.WriteLine("游戏进程异常退出");
|
||||
Environment.Exit(114514);
|
||||
}
|
||||
};
|
||||
if (Native.ResumeThread(hThread) == 0xFFFFFFFF) {
|
||||
var e = new Win32Exception();
|
||||
if (!Native.TerminateProcess(hProcess, 0)) {
|
||||
new Win32Exception().PrintMsgAndReturnErrCode("TerminateProcess fail");
|
||||
}
|
||||
Environment.Exit(e.PrintMsgAndReturnErrCode("ResumeThread fail"));
|
||||
}
|
||||
if (!Native.CloseHandle(hProcess)) {
|
||||
Environment.Exit(new Win32Exception().PrintMsgAndReturnErrCode("CloseHandle fail"));
|
||||
}
|
||||
var ts = new ThreadStart(() => {
|
||||
var server = new NamedPipeServerStream(GlobalVars.PipeName);
|
||||
server.WaitForConnection();
|
||||
using var reader = new StreamReader(server);
|
||||
while (!proc.HasExited) {
|
||||
var line = reader.ReadLine();
|
||||
if (line?.Length > 0) {
|
||||
if (onReceive(line)) {
|
||||
break;
|
||||
}
|
||||
server.Disconnect();
|
||||
server.WaitForConnection();
|
||||
}
|
||||
}
|
||||
});
|
||||
var th = new Thread(ts);
|
||||
th.Start();
|
||||
return th;
|
||||
}
|
||||
|
||||
#pragma warning disable CA1416
|
||||
/// <summary>
|
||||
/// 从注册表中寻找安装路径 暂时只支持国服
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string? FindGamePathFromRegistry() {
|
||||
try {
|
||||
using var root = Registry.LocalMachine;
|
||||
using var sub = root.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\原神");
|
||||
if (sub == null) {
|
||||
return null;
|
||||
}
|
||||
var installLocation = sub.GetValue("InstallPath")?.ToString();
|
||||
if (!string.IsNullOrEmpty(installLocation)) {
|
||||
var folder = Path.Combine(installLocation, "Genshin Impact Game\\");
|
||||
var exePath = Path.Combine(folder, "YuanShen.exe");
|
||||
if (File.Exists(Path.Combine(folder, "UnityPlayer.dll")) && File.Exists(exePath)) {
|
||||
return exePath;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Console.WriteLine(e.Message);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void CheckVcRuntime() {
|
||||
using var root = Registry.LocalMachine;
|
||||
using var sub = root.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall")!;
|
||||
var installed = sub.GetSubKeyNames()
|
||||
.Select(subKeyName => sub.OpenSubKey(subKeyName))
|
||||
.Select(item => item?.GetValue("DisplayName") as string ?? string.Empty)
|
||||
.Any(name => name.Contains("Microsoft Visual C++ 2022 X64 "));
|
||||
if (!installed) {
|
||||
const string vcDownloadUrl = "https://aka.ms/vs/17/release/vc_redist.x64.exe";
|
||||
Console.WriteLine("未安装 VcRuntime");
|
||||
Console.WriteLine($"下载地址: {vcDownloadUrl}");
|
||||
Console.WriteLine("安装完成后,重新打开 YaeAchievement");
|
||||
ShellOpen(vcDownloadUrl);
|
||||
Environment.Exit(303);
|
||||
}
|
||||
}
|
||||
}
|
||||
16
src/Win32/AllocationType.cs
Normal file
16
src/Win32/AllocationType.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
namespace YaeAchievement.Win32;
|
||||
|
||||
[Flags]
|
||||
public enum AllocationType : uint {
|
||||
Commit = 0x00001000,
|
||||
Reserve = 0x00002000,
|
||||
Reset = 0x00080000,
|
||||
TopDown = 0x00100000,
|
||||
WriteWatch = 0x00200000,
|
||||
Physical = 0x00400000,
|
||||
Rotate = 0x00800000,
|
||||
ResetUndo = 0x01000000,
|
||||
LargePages = 0x20000000,
|
||||
Decommit = 0x00004000,
|
||||
Release = 0x00008000
|
||||
}
|
||||
9
src/Win32/CreationFlags.cs
Normal file
9
src/Win32/CreationFlags.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace YaeAchievement.Win32;
|
||||
|
||||
[Flags]
|
||||
public enum CreationFlags : uint {
|
||||
CreateSuspended = 0x00000004,
|
||||
DetachedProcess = 0x00000008,
|
||||
CreateNoWindow = 0x08000000,
|
||||
ExtendedStartupInfoPresent = 0x00080000
|
||||
}
|
||||
14
src/Win32/Extensions.cs
Normal file
14
src/Win32/Extensions.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System.ComponentModel;
|
||||
using YaeAchievement.AppCenterSDK;
|
||||
|
||||
namespace YaeAchievement.Win32;
|
||||
|
||||
public static class Extensions {
|
||||
|
||||
public static int PrintMsgAndReturnErrCode(this Win32Exception ex, string msg) {
|
||||
Console.WriteLine($"{msg}: {ex.Message}");
|
||||
AppCenter.TrackCrash(ex, false);
|
||||
return ex.NativeErrorCode;
|
||||
}
|
||||
|
||||
}
|
||||
16
src/Win32/MemoryProtection.cs
Normal file
16
src/Win32/MemoryProtection.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
namespace YaeAchievement.Win32;
|
||||
|
||||
[Flags]
|
||||
public enum MemoryProtection : uint {
|
||||
Execute = 0x10,
|
||||
ExecuteRead = 0x20,
|
||||
ExecuteReadWrite = 0x40,
|
||||
ExecuteWriteCopy = 0x80,
|
||||
NoAccess = 0x01,
|
||||
ReadOnly = 0x02,
|
||||
ReadWrite = 0x04,
|
||||
WriteCopy = 0x08,
|
||||
GuardModifierFlag = 0x100,
|
||||
NoCacheModifierFlag = 0x200,
|
||||
WriteCombineModifierFlag = 0x400
|
||||
}
|
||||
152
src/Win32/Native.cs
Normal file
152
src/Win32/Native.cs
Normal file
@@ -0,0 +1,152 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
|
||||
namespace YaeAchievement.Win32;
|
||||
|
||||
#pragma warning disable CA1401, CA2101
|
||||
public static class Native {
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
|
||||
public static extern bool CreateProcess(
|
||||
string lpApplicationName,
|
||||
string? lpCommandLine,
|
||||
ref SecurityAttributes lpProcessAttributes,
|
||||
ref SecurityAttributes lpThreadAttributes,
|
||||
bool bInheritHandles,
|
||||
CreationFlags dwCreationFlags,
|
||||
IntPtr lpEnvironment,
|
||||
string? lpCurrentDirectory,
|
||||
[In] ref StartupInfo lpStartupInfo,
|
||||
out ProcessInformation lpProcessInformation
|
||||
);
|
||||
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern bool TerminateProcess(IntPtr hProcess, uint uExitCode);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern bool WriteProcessMemory(
|
||||
IntPtr hProcess,
|
||||
IntPtr lpBaseAddress,
|
||||
char[] lpBuffer,
|
||||
int nSize,
|
||||
out IntPtr lpNumberOfBytesWritten
|
||||
);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
public static extern IntPtr GetModuleHandle(string lpModuleName);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
|
||||
public static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
|
||||
public static extern IntPtr VirtualAllocEx(
|
||||
IntPtr hProcess,
|
||||
IntPtr lpAddress,
|
||||
int dwSize,
|
||||
AllocationType flAllocationType,
|
||||
MemoryProtection flProtect
|
||||
);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
|
||||
public static extern bool VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, int dwSize, AllocationType dwFreeType);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern uint ResumeThread(IntPtr hThread);
|
||||
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern bool CloseHandle(IntPtr hObject);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern IntPtr CreateRemoteThread(
|
||||
IntPtr hProcess,
|
||||
IntPtr lpThreadAttributes,
|
||||
int dwStackSize,
|
||||
IntPtr lpStartAddress,
|
||||
IntPtr lpParameter,
|
||||
uint dwCreationFlags,
|
||||
out IntPtr lpThreadId
|
||||
);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern IntPtr GetConsoleWindow();
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
private const int STD_INPUT_HANDLE = -10;
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern IntPtr GetStdHandle(int nStdHandle = STD_INPUT_HANDLE);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern bool GetConsoleMode(IntPtr handle, out int lpMode);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern bool SetConsoleMode(IntPtr handle, int ioMode);
|
||||
|
||||
[DllImport("comdlg32.dll", SetLastError = true)]
|
||||
public static extern int CommDlgExtendedError();
|
||||
|
||||
[DllImport("comdlg32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
public static extern bool GetOpenFileName([In, Out] OpenFileName ofn);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern IntPtr GlobalLock(IntPtr mem);
|
||||
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern bool GlobalUnlock(IntPtr mem);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool OpenClipboard(IntPtr owner);
|
||||
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
public static extern bool CloseClipboard();
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
public static extern IntPtr SetClipboardData(uint uFormat, IntPtr data);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern bool EmptyClipboard();
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern void RtlZeroMemory(IntPtr dst, ulong length);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
public static extern bool SetForegroundWindow(IntPtr hWnd);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, uint uFlags);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint pid);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern uint GetCurrentThreadId();
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
public static extern IntPtr GetForegroundWindow();
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
public static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);
|
||||
|
||||
[DllImport("gdi32.dll")]
|
||||
public static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern IntPtr GetDC(IntPtr hWnd);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern bool ReleaseDC(IntPtr hWnd, IntPtr hdc);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern uint WaitForSingleObject(IntPtr handle, ulong dwMilliseconds);
|
||||
|
||||
}
|
||||
9
src/Win32/OpenFileFlags.cs
Normal file
9
src/Win32/OpenFileFlags.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace YaeAchievement.Win32;
|
||||
|
||||
[Flags]
|
||||
public enum OpenFileFlags : uint {
|
||||
Explorer = 0x00080000,
|
||||
NoChangeDir = 0x00000008,
|
||||
FileMustExist = 0x00001000,
|
||||
NoNetworkButton = 0x00020000,
|
||||
}
|
||||
32
src/Win32/OpenFileName.cs
Normal file
32
src/Win32/OpenFileName.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
// ReSharper disable FieldCanBeMadeReadOnly.Global
|
||||
|
||||
namespace YaeAchievement.Win32;
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
public struct OpenFileName {
|
||||
public int size;
|
||||
public IntPtr owner;
|
||||
public IntPtr instance;
|
||||
public string filter;
|
||||
public IntPtr customFilter;
|
||||
public int maxCustFilter;
|
||||
public int filterIndex;
|
||||
public IntPtr file;
|
||||
public int maxFile;
|
||||
public IntPtr fileTitle;
|
||||
public int maxFileTitle;
|
||||
public string initialDir;
|
||||
public string title;
|
||||
public OpenFileFlags flags;
|
||||
public short fileOffset;
|
||||
public short fileExtension;
|
||||
public string defExt;
|
||||
public IntPtr custData;
|
||||
public IntPtr hook;
|
||||
public string templateName;
|
||||
public IntPtr reservedPtr;
|
||||
public int reservedInt;
|
||||
public int flagsEx;
|
||||
}
|
||||
14
src/Win32/ProcessInformation.cs
Normal file
14
src/Win32/ProcessInformation.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
// ReSharper disable FieldCanBeMadeReadOnly.Global
|
||||
|
||||
namespace YaeAchievement.Win32;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct ProcessInformation {
|
||||
public IntPtr hProcess;
|
||||
public IntPtr hThread;
|
||||
public uint dwProcessID;
|
||||
public uint dwThreadID;
|
||||
}
|
||||
12
src/Win32/SecurityAttributes.cs
Normal file
12
src/Win32/SecurityAttributes.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
// ReSharper disable FieldCanBeMadeReadOnly.Global
|
||||
|
||||
namespace YaeAchievement.Win32;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct SecurityAttributes {
|
||||
public int nLength;
|
||||
public IntPtr lpSecurityDescriptor;
|
||||
}
|
||||
28
src/Win32/StartupInfo.cs
Normal file
28
src/Win32/StartupInfo.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
// ReSharper disable FieldCanBeMadeReadOnly.Global
|
||||
|
||||
namespace YaeAchievement.Win32;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||
public struct StartupInfo {
|
||||
public uint cb;
|
||||
public string lpReserved;
|
||||
public string lpDesktop;
|
||||
public string lpTitle;
|
||||
public uint dwX;
|
||||
public uint dwY;
|
||||
public uint dwXSize;
|
||||
public uint dwYSize;
|
||||
public uint dwXCountChars;
|
||||
public uint dwYCountChars;
|
||||
public uint dwFillAttribute;
|
||||
public uint dwFlags;
|
||||
public ushort wShowWindow;
|
||||
public ushort cbReserved2;
|
||||
public IntPtr lpReserved2;
|
||||
public IntPtr hStdInput;
|
||||
public IntPtr hStdOutput;
|
||||
public IntPtr hStdError;
|
||||
}
|
||||
284
utils.js
284
utils.js
@@ -1,284 +0,0 @@
|
||||
const fs = require("fs")
|
||||
const dns = require("dns")
|
||||
const ini = require("ini")
|
||||
const zlib = require("zlib")
|
||||
const cloud = require("./secret")
|
||||
const native = require("./native")
|
||||
const readline = require("readline")
|
||||
const protobuf = require("protobufjs")
|
||||
const { version } = require("./version")
|
||||
const { promisify } = require("util")
|
||||
const { createHash } = require("crypto")
|
||||
const path = require("path")
|
||||
const { uploadEvent } = require("./appcenter")
|
||||
const messages = path.join(__dirname, "./proto/Messages.proto")
|
||||
|
||||
const encodeProto = (object, name) => protobuf.load(messages).then(r => {
|
||||
const msgType = r.lookupType(name)
|
||||
const msgInst = msgType.create(object)
|
||||
return msgType.encode(msgInst).finish()
|
||||
})
|
||||
|
||||
const decodeProto = (buf, name) => protobuf.load(messages).then(r => {
|
||||
return r.lookupType(name).decode(buf)
|
||||
})
|
||||
|
||||
const checkPath = path => new Promise((resolve, reject) => {
|
||||
if (!fs.existsSync(`${path}/UnityPlayer.dll`) || !fs.existsSync(`${path}/pkg_version`)) {
|
||||
reject(`路径有误 ${path}`)
|
||||
} else {
|
||||
resolve(path)
|
||||
}
|
||||
})
|
||||
|
||||
let conf
|
||||
|
||||
const initConfig = async () => {
|
||||
const configFileName = "./config.json"
|
||||
if (fs.existsSync(configFileName)) {
|
||||
conf = JSON.parse(fs.readFileSync(configFileName, "utf-8"))
|
||||
if (conf.offlineResource !== undefined || conf.customCDN !== undefined || conf.proxy !== undefined) {
|
||||
conf.proxy = undefined
|
||||
conf.customCDN = undefined
|
||||
conf.offlineResource = undefined
|
||||
fs.writeFileSync(configFileName, JSON.stringify(conf, null, 2))
|
||||
}
|
||||
} else {
|
||||
conf = {
|
||||
path: []
|
||||
}
|
||||
const p = path.dirname(native.selectGameExecutable())
|
||||
await checkPath(p).catch(reason => {
|
||||
console.log(reason)
|
||||
process.exit(1)
|
||||
})
|
||||
conf.path.push(p)
|
||||
fs.writeFileSync(configFileName, JSON.stringify(conf, null, 2))
|
||||
}
|
||||
if (conf.path.length === 1) {
|
||||
await checkPath(conf.path[0]).catch(reason => {
|
||||
console.log(reason)
|
||||
process.exit(1)
|
||||
}).then(p => {
|
||||
conf.path = p
|
||||
})
|
||||
} else {
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout
|
||||
})
|
||||
const question = (query) => new Promise(resolve => {
|
||||
rl.question(query, resolve)
|
||||
})
|
||||
const idx = await question(`选择客户端: \n${conf.path.map((s, i) => {
|
||||
const fp = fs.existsSync(`${s}/GenshinImpact.exe`) ? `${s}\\GenshinImpact.exe` : `${s}\\YuanShen.exe`
|
||||
return `[${i}] ${fp}`
|
||||
}).join("\n")}\n> `)
|
||||
await checkPath(conf.path[parseInt(idx)]).catch(reason => {
|
||||
console.log(reason)
|
||||
process.exit(1)
|
||||
}).then(p => {
|
||||
conf.path = p
|
||||
})
|
||||
rl.close()
|
||||
}
|
||||
conf.isOversea = fs.existsSync(conf.path + "/GenshinImpact.exe")
|
||||
conf.dataDir = conf.isOversea ? conf.path + "/GenshinImpact_Data" : conf.path + "/YuanShen_Data"
|
||||
const readGameRes = (path) => fs.readFileSync(conf.dataDir + path, "utf-8")
|
||||
const genshinConf = ini.parse(fs.readFileSync(`${conf.path}/config.ini`, "utf-8"))["General"]
|
||||
conf.channel = genshinConf["channel"]
|
||||
conf.subChannel = genshinConf["sub_channel"]
|
||||
conf.version = readGameRes("/Persistent/ChannelName") + readGameRes("/Persistent/ScriptVersion")
|
||||
conf.executable = conf.isOversea ? `${conf.path}/GenshinImpact.exe` : `${conf.path}/YuanShen.exe`
|
||||
conf.dispatchUrl = `dispatch${conf.isOversea ? "os" : "cn"}global.yuanshen.com`
|
||||
conf.dispatchIP = (await promisify(dns.lookup).bind(dns)(conf.dispatchUrl, 4)).address
|
||||
uploadEvent("AppInitialize", { ClientVersion: version.name, GameVersion: conf.version })
|
||||
return conf
|
||||
}
|
||||
|
||||
const checkGameIsRunning = () => {
|
||||
const name = path.basename(conf.executable)
|
||||
if (native.checkGameIsRunning(name)) {
|
||||
console.log("原神正在运行,请关闭后重试")
|
||||
process.exit(301)
|
||||
}
|
||||
}
|
||||
|
||||
const checkPortIsUsing = () => {
|
||||
const portUsage = native.whoUseThePort(443)
|
||||
if (portUsage !== undefined) {
|
||||
console.log(`443端口被 ${path.basename(portUsage["path"])}(${portUsage["pid"]}) 占用,结束该进程后重试`)
|
||||
process.exit(14)
|
||||
}
|
||||
}
|
||||
|
||||
const splitPacket = buf => {
|
||||
let offset = 0
|
||||
let arr = []
|
||||
while (offset < buf.length) {
|
||||
let dataLength = buf.readUInt32LE(offset + 24)
|
||||
arr.push(buf.subarray(offset, offset + 28 + dataLength))
|
||||
offset += dataLength + 28
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
const md5 = str => {
|
||||
const h = createHash("md5")
|
||||
h.update(str)
|
||||
return h.digest("hex")
|
||||
}
|
||||
|
||||
/*
|
||||
* Structure:
|
||||
* UInt16 = 0x4321: magic num
|
||||
* UInt8 = 0x2 : version
|
||||
* Char[32] : data md5
|
||||
* ... : compressed data
|
||||
*/
|
||||
|
||||
const loadCache = async (fp = "latest-data") => {
|
||||
log(`正在加载资源: ${fp}`)
|
||||
const startAt = Date.now()
|
||||
fs.mkdirSync("./cache", { recursive: true })
|
||||
// remove old cache file
|
||||
fs.readdir("./cache/", (err, files) => {
|
||||
if (err === null) files.forEach(s => {
|
||||
const fn = `./cache/${s}`
|
||||
if (!fn.endsWith(".ch")) fs.rm(fn,_ => {})
|
||||
})
|
||||
})
|
||||
const localPath = `./cache/${md5(fp)}.ch`
|
||||
const headers = {
|
||||
"x-content-hash": "0".repeat(32)
|
||||
}
|
||||
let fd = Buffer.alloc(0)
|
||||
if (fs.existsSync(localPath)) {
|
||||
fd = fs.readFileSync(localPath)
|
||||
if (fd.readUInt16BE(0) === 0x4321 && fd.readUInt8(2) === 2) {
|
||||
headers["x-content-hash"] = fd.subarray(3, 35).toString("utf-8")
|
||||
}
|
||||
}
|
||||
const resp = await cloud.get(`/${fp}`, "application/json", headers, "arraybuffer")
|
||||
if (resp.status === 304) {
|
||||
log(`完成 (Cache, ${Date.now() - startAt}ms)`)
|
||||
return JSON.parse(brotliDecompressSync(fd.subarray(35)).toString())
|
||||
} else {
|
||||
const compressedData = resp.data
|
||||
const decompressedData = brotliDecompressSync(compressedData)
|
||||
const buf = Buffer.allocUnsafe(compressedData.length + 35)
|
||||
buf.writeUInt16BE(0x4321, 0)
|
||||
buf.writeUInt8(0x2, 2)
|
||||
buf.fill(md5(decompressedData), 3)
|
||||
buf.fill(compressedData, 35)
|
||||
fs.writeFileSync(localPath, buf)
|
||||
log(`完成 (Network, ${Date.now() - startAt}ms)`)
|
||||
return JSON.parse(decompressedData)
|
||||
}
|
||||
}
|
||||
|
||||
const isDebug = false
|
||||
|
||||
const debug = (msg, ...params) => {
|
||||
if (isDebug) log(msg, ...params)
|
||||
}
|
||||
|
||||
const log = (msg, ...params) => {
|
||||
const time = new Date()
|
||||
const timeStr = time.getHours().toString().padStart(2, "0") + ":" + time.getMinutes().toString().padStart(2, "0") + ":" + time.getSeconds().toString().padStart(2, "0")
|
||||
console.log(`${timeStr} ${msg}`, ...params)
|
||||
}
|
||||
|
||||
const upload = async data => {
|
||||
return await cloud.post("/achievement-export", data)
|
||||
}
|
||||
|
||||
const checkUpdate = async () => {
|
||||
const data = (await cloud.get("/latest-version")).data
|
||||
if (data["vc"] !== version.code) {
|
||||
log(`有可用更新: ${version.name} => ${data["vn"]}`)
|
||||
log(`更新内容: \n${data["ds"]}`)
|
||||
log("下载地址: https://github.com/HolographicHat/genshin-achievement-export/releases\n")
|
||||
}
|
||||
}
|
||||
|
||||
const brotliCompressSync = data => zlib.brotliCompressSync(data,{
|
||||
params: {
|
||||
[zlib.constants.BROTLI_PARAM_QUALITY]: zlib.constants.BROTLI_MAX_QUALITY,
|
||||
[zlib.constants.BROTLI_PARAM_SIZE_HINT]: data.length
|
||||
}
|
||||
})
|
||||
|
||||
const brotliDecompressSync = data => zlib.brotliDecompressSync(data)
|
||||
|
||||
let hostsContent = undefined
|
||||
|
||||
const setupHost = (restore = false) => {
|
||||
if (restore && hostsContent === undefined) return
|
||||
const path = `${process.env.windir}\\System32\\drivers\\etc\\hosts`
|
||||
if (!fs.existsSync(path)) {
|
||||
fs.writeFileSync(path, "")
|
||||
}
|
||||
fs.chmodSync(path, 0o777)
|
||||
if (restore) {
|
||||
fs.writeFileSync(path, hostsContent)
|
||||
} else {
|
||||
hostsContent = fs.readFileSync(path, "utf-8")
|
||||
const requireHosts = new Map()
|
||||
requireHosts.set(conf.dispatchUrl, "127.0.0.1")
|
||||
requireHosts.set("localdispatch.yuanshen.com", "127.0.0.1")
|
||||
const currentHosts = new Map()
|
||||
hostsContent.split("\n").map(l => l.trim()).filter(l => !l.startsWith("#") && l.length > 0).forEach(value => {
|
||||
const pair = value.trim().split(" ").filter(v => v.trim().length !== 0)
|
||||
currentHosts.set(pair[1], pair[0])
|
||||
})
|
||||
requireHosts.forEach((value, key) => {
|
||||
if (currentHosts.has(key)) {
|
||||
if (currentHosts.get(key) === value) {
|
||||
requireHosts.delete(key)
|
||||
} else {
|
||||
currentHosts.delete(key)
|
||||
}
|
||||
}
|
||||
})
|
||||
requireHosts.forEach((ip, host) => {
|
||||
currentHosts.set(host, ip)
|
||||
})
|
||||
const newContent = Array.from(currentHosts.entries()).map(pair => {
|
||||
return `${pair[1]} ${pair[0]}`
|
||||
}).join("\n")
|
||||
fs.writeFileSync(path, newContent)
|
||||
}
|
||||
debug("修改SystemHosts")
|
||||
process.on("exit", () => {
|
||||
fs.writeFileSync(path, hostsContent)
|
||||
})
|
||||
}
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
class KPacket {
|
||||
|
||||
constructor(data) {
|
||||
this.origin = data
|
||||
this.conv = data.readUInt32BE(0)
|
||||
this.token = data.readUInt32BE(4)
|
||||
this.cmd = data.readUInt8(8)
|
||||
this.frg = data.readUInt8(9)
|
||||
this.wnd = data.readUInt16LE(10)
|
||||
this.ts = data.readUInt32LE(12)
|
||||
this.sn = data.readUInt32LE(16)
|
||||
this.una = data.readUInt32LE(20)
|
||||
this.length = data.readUInt32LE(24)
|
||||
this.data = data.subarray(28)
|
||||
this.hash = (() => {
|
||||
const h = createHash("sha256")
|
||||
h.update(Buffer.concat([Buffer.of(this.sn, this.frg), this.data]))
|
||||
return h.digest("hex")
|
||||
})()
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
log, encodeProto, decodeProto, initConfig, splitPacket, upload, brotliCompressSync, brotliDecompressSync,
|
||||
setupHost, loadCache, debug, checkUpdate, KPacket, checkGameIsRunning, checkPortIsUsing
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
const version = {
|
||||
code: 6,
|
||||
name: "1.5"
|
||||
}
|
||||
|
||||
module.exports = { version }
|
||||
Reference in New Issue
Block a user