惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

C
CXSECURITY Database RSS Feed - CXSecurity.com
K
Kaspersky official blog
A
Arctic Wolf
Attack and Defense Labs
Attack and Defense Labs
L
LINUX DO - 热门话题
N
News | PayPal Newsroom
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
L
Lohrmann on Cybersecurity
PCI Perspectives
PCI Perspectives
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
The Last Watchdog
The Last Watchdog
B
Blog RSS Feed
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
W
WeLiveSecurity
Know Your Adversary
Know Your Adversary
博客园 - Franky
T
Tenable Blog
T
Tailwind CSS Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Help Net Security
Help Net Security
WordPress大学
WordPress大学
T
The Exploit Database - CXSecurity.com
www.infosecurity-magazine.com
www.infosecurity-magazine.com
博客园 - 司徒正美
阮一峰的网络日志
阮一峰的网络日志
D
Darknet – Hacking Tools, Hacker News & Cyber Security
H
Heimdal Security Blog
TaoSecurity Blog
TaoSecurity Blog
S
Security Affairs
J
Java Code Geeks
小众软件
小众软件
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Apple Machine Learning Research
Apple Machine Learning Research
NISL@THU
NISL@THU
O
OpenAI News
The Cloudflare Blog
月光博客
月光博客
Google Online Security Blog
Google Online Security Blog
V
V2EX
罗磊的独立博客
美团技术团队
博客园 - 三生石上(FineUI控件)
Security Latest
Security Latest
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
C
Cyber Attacks, Cyber Crime and Cyber Security
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Cyberwarzone
Cyberwarzone
L
LINUX DO - 最新话题
Hacker News - Newest:
Hacker News - Newest: "LLM"
大猫的无限游戏
大猫的无限游戏

czp's blog

Ubuntu 下使用 zsh · HonKit 使用 VNC 来远程管理服务器 · HonKit Linux 下无限试用 JetBrains · HonKit 使用 KMS 激活 Windows · HonKit 为 KVM 中的 Windows 虚拟机启用 VirtIO · HonKit 在 Spring Boot 中处理 MissingKotlinParameterException · HonKit 用 Spring Native 拯救微服务 · HonKit 正确调试 PHP · HonKit Ubuntu 增加最大文件打开数量限制 · HonKit 将 Minecraft 服务端编译到 native · HonKit 用凝聚力购买 P 社游戏 DLC · HonKit 模拟超星网课 Android 客户端 · HonKit 模拟 Bilibili Android 客户端 · HonKit 模拟哔咔 Android 客户端 · HonKit 异步是什么 · HonKit GCP Pub/Sub push 至 IAP 保护的 Endpoint · HonKit 部署 Spring Native 到 GCP App Engine · HonKit 多个 Gradle SubProject 同时编译导致 CI/CD 内存耗尽 · HonKit Google Cloud Build 运行 DIND · HonKit 在 Google Storage 中部署 SPA · HonKit Terraform 不自动更新 CloudRun service · HonKit Telegram Bot 收不到普通群聊消息的问题 · HonKit 加密货币交易 · HonKit 挖掘以太坊 · HonKit 挖掘门罗币 · HonKit 小明学英语 · HonKit 卖程序的小女孩 · HonKit 一个测试工程师走进一家酒吧 · HonKit 我给你们讲个 TCP 笑话吧! · HonKit 我给你们讲个 UDP 笑话吧! · HonKit 格局打开 · HonKit c 语言常见未定义行为 · HonKit Kotlin 协程 · HonKit 在 Spring Boot 中正确注册 Jackson Module · HonKit Spring Boot Jpa 使用 Google Cloud SQL · HonKit Spring Boot 中配置单页应用 · HonKit Spring Boot 无法加载 ClasspathResource 问题 · HonKit 正确打包 Spring Boot 到 war · HonKit czp's blog · HonKit 鸣谢列表 · HonKit 友链 · HonKit
在 Kotlin 使用 SpaceEngineers Remote API · HonKit
2026-04-11 · via czp's blog

众所周知, SpaceEngineers 的服务端(vanilla, 非 torch)上那个查看服务器内游戏信息的玩意是通过网络来获取信息的(localhost). 实际上这个东西有独立版本应用程序, 也在服务端根目录下, 叫做 VRageRemoteClient . VRage 是 SpaceEngineers 使用的游戏引擎, 这个游戏引擎本身也是 Keen 开发的.

于是在谷歌上搜索 SpaceEngineers API, 只能找到这个页面 https://www.spaceengineersgame.com/dedicated-servers.html 并且介绍 API 有哪几个的, 只有页面最下方的一张图 https://www.spaceengineersgame.com/uploads/2/1/9/6/21961362/736604853_orig.png. 页面下方有一段 c# 代码用于示例, 但是有些东西是 .Net 平台特定的, 在其他语言可能有麻烦.

示例代码是这样的

private readonly string m_remoteUrl = "/vrageremote/{0}";

public RestRequest CreateRequest(string resourceLink, Method method, 
params Tuple<string, string>[] queryParams)
{
    string methodUrl = string.Format(m_remoteUrl, resourceLink);
    RestRequest request = new RestRequest(methodUrl, method); 
    string date = DateTime.UtcNow.ToString("r", CultureInfo.InvariantCulture);
    request.AddHeader("Date", date); 
    m_nonce = random.Next(0, int.MaxValue);
    string nonce = m_nonce.ToString();
    StringBuilder message = new StringBuilder();
    message.Append(methodUrl); 
    if (queryParams.Length > 0)
    {
        message.Append("?");
    }

    for (int i = 0; i < queryParams.Length; i++)
    {
        var param = queryParams[i];
        request.AddQueryParameter(param.Item1, param.Item2);
        message.AppendFormat("{0}={1}", param.Item1, param.Item2);
        if (i != queryParams.Length - 1)
        {
            message.Append("&");
        }
    }

    message.AppendLine();
    message.AppendLine(nonce);
    message.AppendLine(date);
    byte[] messageBuffer = Encoding.UTF8.GetBytes(message.ToString());

    byte[] key = Convert.FromBase64String(m_securityKey);
    byte[] computedHash;
    using (HMACSHA1 hmac = new HMACSHA1(key))
    {
        computedHash = hmac.ComputeHash(messageBuffer);
    }

    string hash = Convert.ToBase64String(computedHash);
    request.AddHeader("Authorization", string.Format("{0}:{1}", nonce, hash));
    return request;
}

可以看出, 最终的请求必须有至少以下两个 header

Date: httpDateString()
Authorization: "$nonce:$hash"

在示例代码中, 我们可以看到 c# 中是这样得到 Date 的: DateTime.UtcNow.ToString("r", CultureInfo.InvariantCulture) , c# 在输出时间字符串的时候会根据不同的 culture(fr, de, cn...) 来得到不同的结果, 而 InvariantCulture 用于得到统一的结果. 它的输出是这样的

Tue, 15 May 2012 16:34:16 GMT

这其实就是平时俗称的 HttpDateString , 在不同的语言中根据这个格式来格式化时间即可, 例如在 Java 中

DateTimeFormatter
    .ofPattern("EEE, dd MMM yyyy HH:mm:ss z")
    .withLocale(Locale.US)
    .withZone("GMT")

Authorization 由两部分组成, nonce 就是一个大于 0 的 Int 类型随机数. 而这个 hash 就很有来头了, hash 的值是把 url(包含 query params), nonce, date 用 StringBuilder.AppendLine 拼接在一起然后做一次 HmacSHA1 , 用到的 key 就是 VRageRemoteClient 上需要填入的 Security Key. .Net 的 AppendLine 是平台相关的, 所以使用的是

val nonce = Random.nextInt(0..Int.MAX_VALUE)
val date = Instant.now().toHttpDateString()
val message = "$url\r\n$nonce\r\n$date\r\n"
val hash = Mac.getInstance("HmacSHA1").apply {
    init(secretKey)
}.doFinal(message.toByteArray()).let {
    Base64.getEncoder().encodeToString(it)
}

如果想要百分百还原, 还可以加上 UA

userAgent("RestSharp/106.6.10")

好了, 我们现在知道如何发送一个合法的请求了. 不过有些东西网页上没有讲到, 以下记录一些遇到的坑.

send message(POST /v1/session/chat) 是唯一一个 BODY 有内容的请求, 需要特别注意的是, BODY 应该是这样的

"This is a message"

它 自 身 包 含 引 号!

get message(GET /v1/session/chat) 有一个可选参数(Query Param)名称为 Date , 值是一个 DateTime.Ticks (最后转换为 Long 类型), 用于控制服务器返回的消息(复数)从哪个时间之后开始(闭区间).

如果没有这个参数, 服务器将返回所有聊天消息. 聊天消息中包含 timestamp 字段, 最后一条消息的这个字段的值加一, 就可以作为下一次请求聊天消息时所用的 Date 的值.

c# 的 DateTime.Ticks 是一个从 0001-01-01T00:00:00.00Z 开始以 100毫秒 为时间间隔递增的数字. 如果要对这个时间进行处理, 就需要转换为对应语言中的时间类型. 以 Kotlin 为例

//c# ticks
internal typealias Ticks = Long

private val offset = Duration.between(
    Instant.parse("0001-01-01T00:00:00.00Z"),
    Instant.ofEpochSecond(0)
).seconds
private val zoneOffset = ZoneOffset.ofTotalSeconds(TimeZone.getDefault().rawOffset / 1000)

fun Ticks.toLocalDateTime() =
    LocalDateTime.ofEpochSecond(
        this / 10_000_000 - offset,
        0,
        zoneOffset
    )!!

banned players 和 kicked players 这两个 API 返回的列表总是空的, 不太明确原因.

之前把 SpaceEngineers Remote API 完整的用 Kotlin 实现了一遍 https://github.com/czp3009/space-engineers-remote-api

然后又试着写了一个可以在手机上管理服务器的 Android App https://github.com/czp3009/SpaceEngineersRemoteClient

不过这个 APP 有很多问题, 重构又懒得弄, 你猜我能咕咕咕到什么时候