找回密码
 加入我们
搜索
      
查看: 4405|回复: 32

[软件] 自研程序发布 —— SteamID Converter

[复制链接]
发表于 2025-2-26 11:09 | 显示全部楼层 |阅读模式
本帖最后由 imyz 于 2025-2-27 09:17 编辑

原计划是上周发布的,可偏不巧周末豪无徵兆就发烧+鼻塞+流涕+咳嗽+腹泻多个症状并发,尤其鼻塞+腹泻搞得简直没办法睡觉,头晕脑胀的,不是躺着不停翻身就是马桶蹲,接连好几天几乎无法直立超 30 分钟,也不清楚是不是近期较凶的甲流所致,就这样一粒药没吃生扛了三五天啥事儿也做不了......

(一)、序言
      2024 年国庆假期行将结束的某日正畅玩 L4D2 期间,竟然有人进入游戏(开了友伤)二话不说就打队友捣蛋,在熟练地永封其 Steam 帐号之余,脑海中不禁又浮现出 SteamID 格式转换这件旧事。因偶尔会遇到 RegularID, SteamID3, SteamID64 这三种格式相互手工转换的场景,早在 N 年前还为此专门拜读过官方文档,当时也没打算深入了解,图省事就用 Excel 公式来快速完成前两种的转换,而第三种 SteamID64 这一格式因其长度超 Excel 最大 15 位的限制,导致计算转换后的结果无法在单元格中完整显示,又因当时的确没有更多的实际使用场景,于是这事就这么一直搁置了,导致对 SteamID 一直都是一知半解的状态,其中的一些细节后来也随时间流逝一并淡忘了。经这回这一闹,一时兴起就决定写个转换程序来实现三者之间的相互转换,除了可一劳永逸外,也是打算给这桩旧事作个了结。原本是打算先看下是否有现成的开源代码可“借鉴”,但上网搜的结果悉数是在线网页转换的,而我只是想要个本地运行的工具取代 Excel 公式,那么显然此路不通。好在我对平生所学 C/C++/C# 还有些信心,而 C++ 在 macOS 和 Linux 平台还有先天优势,跨平台与执行效率亦可兼得,所以也没多想就直接动手。不过遗憾之处在于长假刚好结束,完美地错过了可不必从一堆碎片时间中挑一段来做一件事的大好时机,只得从原本就不充裕的闲暇中再挤出一段。

      第一版 .dll 的 C++ 代码花了好几个夜晚辛苦堆出来了。没错,顶层设计就是采用动态链接库 + GUI 的方案,理由很简单,为使跨平台堆码量最小,将其中共性的纯转换计算功能作为公因子提取出来无疑是最优解,也方便今后与其它程序共享,而这也是为什么程序界面标题以“UI”结尾的原因;而另一方面,在春节前的预告中已提示过 Windows GUI 我为偷懒用了托管代码,而这也决定了 .dll 是 Windows 平台最优解,资深码农对这一点应当深有感触吧(细节留待后续章节再细说)。在堆码过程中才发现,我真的将当年曾遇到的一个陈年困惑给忘一干净:同一个玩家个人帐号其 RegularID 格式即 STEAM_X:Y:Z 当中的 X,即:Account Universe 的取值为什么在有的游戏中为 0 而有的之中则为 1,即:STEAM_0:Y:Z = STEAM_1:Y:Z?但凡读过官方文档的都应当清楚 Valve 针对这几种格式相互转换这事可谓“知而不言、言又未尽”,若还有未曾读过该文档不知我所云的,以下便是官方文档的门牌号:

SteamID - Valve Developer Community


(二)、初识 SteamID
      对于初读者,头几遍读下来大概率会感觉 RegularID, SteamID3, SteamID64 这三种格式之间的相互转换无外乎就是小学数学 加、减、乘、除 四则运算加上字符串比较与拼接,貌似挺简单。然而一旦深入后便会发现,官方文档实际上主要是交待了整个 SteamID 宇宙(Account Universe)中极小极小极小的一部分内容,即:Types of Steam Accounts 帐号类型为 ‘U’ 的玩家个人帐号(Individual)部分,也是玩家们能直接接触到的这部分,之所以用三个极小来强调的原因将在下文中再详细解释。简单地讲,我因一时兴起而堆出来的第一版代码当时只能完成个人帐号的转换,或者换个说法,我第一版代码只能转换个人帐号的根本原因,实际上是我压根无法从官方文档中找到除个人帐号之外的其它类型要如何处理和转换的具体方法,例如:Game Server, Anonymous User 类型的 SteamID 应当长啥样?要如何转换?再如:Chat 类型的 “T / L / c” 这三个字母要按什么规则进行匹配?此外,我前面讲到的曾遇到的“陈年困惑”在官方文档中可谓只字未提,可算作官方埋下的一个坑。

      接着说“坑”。以我自己的 SteamID(STEAM_X:Y:Z)为例,当年带我入坑 Steam 的是 CS:S (Counter-Strike: Source) 这款游戏,自打注册那天起在 CS:S 中显示的一直都是 X = 0,而在其后让我越陷越深的 L4D1/2 之中却发现 X = 1,虽然在几年前 Valve 采用 SteamID3 个人帐号格式([U:1:W])替代了 CS:S 此前的 RegularID 格式(至少在眼不见心不烦这一点上 Valve 算是真正做到了),可这个困惑如今在我脑海中被重新唤醒…… 可眼下第一版动态库代码都堆出来了,怎么说也应当善始善终不是?!于是 Windows 平台的 GUI 初版于 2024 年 10 月中下旬也完成了。虽然初版程序能跑起来,但限于以上原因,后续针对 macOS 以及 Linux 平台的堆码/调试始终没提上日程,也是因为前面的那个困惑,我本身对这一版代码也不满意,它显然离作为工具发布还有很长的路要走,甚至不排除推倒重来的可能。为了解惑,在第一版代码出来之后,我还向 Steam Support 提了问,希望能得到官方对于 X 取值,以及除个人帐号之外的其他类型 SteamID 的转换规则作进一步详细解释。Steam Support 客服很快有回复,先是问我为什么需要这些问题的答案,我以 CS:S 和 L4D2 采用不同格式 SteamID 为例给出了具体需求场景,可遗憾的是,客服最终给我的答复却是说,官方给的上面那个文档已经能回答并满足我所提的问题,随后便关闭了该 Case 不再接受进一步咨询和提问,所以我至今也不确定是不是我提问和作答的方式不对……

      既然官方不提供我更多有用信息,留给我的唯有不断翻新我对官方文档的解读这一选项。所以,在随后长达一个多月的时间,我愣是没再碰代码,而是利用闲暇时间反复思考,从多个角度假设前提条件和结论,再从逻辑上反推该假设的合理性。时间一转眼就来到了 12 月的某天,在经历了反复推理后,其中一个猜想终于在各方面都符合逻辑,也能很好地解释 STEAM_X:Y:Z 这类 RegularID 为什么长这样,并且该推理极有可能就是 Valve 真实的设计方案。要说清这件事,还得从 Steam 的发展历程聊起,咱们先回顾一下以下历史事件(若有谬误还请指正):

  • 1999/?/??: AMD 首次公开提出 x86-64 指令集(amd64)
  • 2003/9/12: Valve 发布 Steam 平台
  • 2003/4/24: AMD 发布 K8 架构的 Opteron 64-bit 服务器 CPU
  • 2003/9/23: AMD 发布 K8 架构的 Athlon64 64-bit 桌面 CPU……(与当时 Intel 专用于安腾 Itanium CPU 的 IA-64 不同之处在于,x86-64(amd64) 指令集因其本质是 x86 的扩展指令集,它在保留向下兼容现有 32-bit 和 16-bit 的操作系统和应用程序的同时原生支持 64-bit 应用,而 K8 Athlon64 则是首款支持该特性的民用级 64-bit CPU,当时在业界引起了不小的轰动,标志着 64-bit 计算正式进入民用市场。)
  • 2007/10/10: Valve Orangebox 橙盒版发布
  • 2008/11/17: Left 4 Dead 在 Steam 平台全球发布;


      基于以上历史事件,至少可以得出以下几个基本事实:
  • 2003 年 9 月之前,桌面 PC 仍均处于 32-bit 时代;
  • 2003 年 Valve 发布的 Steam Client 甚至整个 Steam 平台都是 32-bit 版本,并且没有 64-bit 版;
  • 2003 年直至 2008 年这段时期,32-bit 桌面 PC 是主流;
  • 官方明确指出 X 取值发生 0->1 的变化最早是 Left 4 Dead,即 2008 年,详见以下官方文档截图;


01.Change of Value of X.png

      基于以上基本事实,可以大胆推测:早在 2003 年那个 PC 市场还未出现 x86-64 硬件的年代,Valve 当时在规划设计 SteamID 宇宙时还是基于 32-bit (4 Bytes),换句话说,那时可能还不存在 SteamID64,或者根本没有对外透露过;既然有 SteamID64,同理,RegularID 格式对应的我暂记作 SteamID32。不过这话搁 SteamID 转换这事上应当如何理解呢?不妨再进一步据官方文档推测:既然 Y 被定义为最低位(用途不详),猜测 X 当时要么与 Z 共享余下 31 位且为最高位,其取值范围仅有 0 或 1 因而被定义为 0(程序猿/媴们对该做法应当有共识!),要么 X 当时压根就不占任何位而纯粹被定义为 0。同时再猜测:早在2007年橙盒版发布之前,[U:1:W] 这种 SteamID3 格式(请注意不是 SteamID32)还没有被设计出来……

      再进一步,随着后续 64-bit 服务器及 PC 的逐步普及,Valve 也意识到了 RegularID 固有的问题,即:Z ≤ 31bits 最大仅能支持不到 21.5 亿个帐号,即使按 32 位算,其总数也不足 43 亿,其中还要考虑分配给 Server 的帐号、Chat, Clan 等这类需求,以及一人多号、新老用户更迭,再结合 Steam 最近几年的体量以及对未来的预估等等,若继续停留在 32-bit,那么 Steam 帐号早晚必将面临与当年 IPv4 一样的困境,由此可推测 SteamID3 和 SteamID64 这两种原生支持 64-bit 的格式(尤其是后者)必然是在 64-bit 硬件出现和普及之后才对外发布的。不过,Valve 貌似在这一点上没有对外官宣过,并且将 SteamID32 从原 32-bit 扩展至如今的 64-bit 的 SteamID64 这事做得悄无声息(至少我没找到过这类官宣文档),从官方文档上看,为了使玩家对该过程“无感”,Valve 的做法是在保持原 RegularID 格式不变的情况下,在原 SteamID32 高位直接新增 32 bits,新增的这 32 bits 中的最高位序第 63-56 共 8 bits 作为 X,55-52 这 4 bits 作为帐号类型 Account Type,而 51-32 这 20 bits 作为帐号实例 Account Instance。可是,这样一来又带来另一个新问题:因传统的 STEAM_X:Y:Z 这类 RegularID 基于 32-bit 设计而无法原生支持 Account Type 和 Account Instance 这两个新增特性,摆在 Valve 面前的问题就很清楚了:新老玩家该如何兼顾?新产品显然得原生支持 64-bit 新帐号并且不大可能因为兼容这种事而跳票,假如想让包括橙盒版在内的之前早已发布的产品同时支持全新的 64-bit 帐号,又要确保相应的修改不影响现有的游戏服务及体验,这简直就是“Mission Impossible”并且完全没必要,因为可以在不改变现有产品的前提下,再设计一个新帐号格式并搭配相应的映射规则就可以完美地将新老游戏及玩家“切割”开而互不影响,同时在最大限度内使玩家无感…… 从事实的结果来看,Valve 大体上是按这个思路做了,但做法却稍有不同,其首先将玩家个人帐号(Individual)区别于其它类型帐号并单独进行如下的极小修改:
  • 保持已有玩家帐号不变,而新注册玩家的帐号的 X 由原 0 改为 1,即:新玩家帐号所属的 SteamID 宇宙编号为 1;
  • 强制规定所有新老玩家个人帐号在 1 号宇宙中对应的帐号类型 Type = 1(未交待缘由);
  • 强制规定所有新老玩家个人帐号在 1 号宇宙中对应的帐号实例 Instance = 1(未交待缘由);


      经以上调整之后,因 STEAM_X:Y:Z 中的 X 在原 32-bit 体系下 (1 bit) 本身也支持 0 与 1 的取值,很明显以上调整完全可实现玩家无感。此外,上述修改也确定并解释了官方文档中个人帐号所对应的那个 SteamID64 identifier 为什么是 0x0110000100000000 这个很奇怪的十六进制数了,再进一步展开,那么玩家个人帐号在 64-bit 体系的 1 号宇宙中的取得范围也只可能是:0x0110000100000000 ~ 0x01100001FFFFFFFF,再将其转换成十进制可能大家看起来更加亲切和熟悉:76561197960265728 ~ 76561202255233023。至此,再结合官方文档给出的 X、Type 和 Instance 取值范围来理解,玩家个人帐号的数量在目前已知 6 个宇宙中 (6 x 2^24) 的占比简直可以忽略不计,这也正回应并解释了我上文 “极小极小极小”一说。

      接着说个人帐号,第一步的调整已清楚了,可事实上 Valve 第二步于 2008 年发布 Left 4 Dead 时却依然沿用了 STEAM_X:Y:Z 格式的 RegularID 而非可支持新特性的 SteamID3(再次强调不是 SteamID32)。这一点我也没想透,只能猜测当时 SteamID3 格式还没通过内测甚至还没被提上日程,否则很难解释为什么如今 Valve 却硬要将 CS:S 的改为 SteamID3 格式,若不是因为 Valve 当年的这一骚操作而导致我失去自己服务器的管理员权限,我可能至今都不会关注到这事,当时也不明白为啥 Valve 要改这东西,以为纯粹是成心和服务器插件过不去…… 而如今结合上面的猜测再回想,大致是之前错怪 Valve 了,包括那个所谓的骚操作,其根本的原因应当是 Valve 为今后全面支持 64-bit 而迈出的一小步。不过,只改 X 取值这一做法的好处也是显然的,既实现上述极小修改又可对玩家而言无感,至少从玩家角度看,X 由 0 变 1 这一变化总好过 STEAM_X:Y:Z 一夜变 [U:1:W] 这种。至此,我的陈年困惑的答案也就显而易见了:

      玩家帐号中的 X 的取值并非 0 与 1 均可,而是早在硬件仍处于 32-bit 那个连地主家也没余粮的年代,Valve 因条件所限而将玩家帐号定义在 0 号宇宙或者只有 0 号宇宙,这大体就是最初 X = 0 的来源;随着 64-bit 硬件的普及以及 Valve 体量不断扩大,将 Steam 帐号体系由原 32-bit 全面转向 64-bit 已是必然,而 Valve 官方作出的决定是在将玩家帐号迁移至 1 号宇宙的同时“弃用” 0 号宇宙,这就是其后 X = 1 的来源。而 Valve 为了确保早在 32-bit 那个年代就注册的这部分“存量玩家”对这一变化无感,官方在后台自己做了映射规则,即:STEAM_0:Y:Z = STEAM_1:Y:Z。为什么我前面要用“弃用”?首先,官方文档在 Universe 定义中对 0 的注释是 Individual/Unspecified,前面那个 Individual 很容易理解,可其后的“Unspecified 未指定”这字眼,结合我上述的推理后就显得耐人寻味了…… 这样说可能还会有人不明白我在暗示什么,那我先从技术层面分析:在 64-bit 帐号体系下,X 已被定义为最高 8 位,然后再查下官方对帐号类型的定义表,Type = 0 这一类型被定义为 Invalid 即无效,二结合起来理解不难猜测,在 0 号宇宙中,X = 0 不能避免某个帐号类型的 Type 和 Instance 二者同时为 0 的情况,如此一来,高 32 位就全为 0 了,即 SteamID64 -> SteamID32,一下又回到解放前这事好像不能忍!猜测 Valve 是刻意为了避免这三者同时为 0 才有了弃用 0 号宇宙的念头,并且好像也真的这么做了。之所以还用 Individual 来挂个名其实应当是有两层意思:一是原 32-bit 时代注册的旧帐号目前依然还活跃着,至少绝大部分还活跃着,所以做出“在 64-bit 体系的 0 号宇宙中继续保留原 Individual 号段”这一假象,应当是 Valve 特意为了给关注到这件事的玩家们造成“一切还是老样子”的错觉;二是原 32-bit 体系中的 0 号宇宙的整体体量只等价于 64-bit 体系当中一个弼马温级别的 Individual 帐号类型。当然也可以简单地理解为:考虑到毕竟是 32-bit 时代的功臣,卸磨杀驴这种事容易引起公愤对吧。

      为防止仍未真正读懂我所表达的意思的看官们进一步提出诸如 “假如官方实际并未真正弃用 0 号宇宙,而是将 32-bit 时代注册的存量玩家的帐号继续保留在新的 0 号宇宙中难道就不行吗?” 这类疑问,我的回答会是“当然也可以”!原因在于 SteamID 当中的 SteamID64 其本身可被视作连续自然正整数,就看 Valve 愿意将哪个号段定义为玩家个人类型。所以不难推论,当 X = 0 的情况下,存量玩家们的 SteamID64 理论上应当是落在 0x0010000100000000 ~ 0x00100001FFFFFFFF 这个号段内的,将其转换成十进制便是 4503603922337792 ~ 4503608217305087。不过这样的做法在 64-bit 体系中显得毫无意义,原因还是要回到 SteamID 本身的定义上:根据官方文档,对于个人玩家而言,STEAM_X:Y:Z 其中的 Z 才是真正的 Account Number,即:玩家帐号,在 Instance 和 Type 均相同的情况下继续纠结 X 究竟应当等于 0 亦或是 1 这个问题无疑是对现有资源的浪费!换句话说,保留在 0 号宇宙中的玩家帐号的 Z 在 1 号宇宙中也不应该被他人占用!否则,官方令 STEAM_0:Y:Z = STEAM_1:Y:Z 将不再成立,这只是其一;其二,官方对外宣称的个人玩家帐号的 SteamID64 号段也是 76561197960265728 ~ 76561202255233023,即:X = 1,所以充要条件也有了,没必要纠结了。

      其实还有其三:如今 64-bit 宇宙所拥有的号量真的可用取之不尽形容,即使因历史原因而放弃原 0 号宇宙也压根没任何影响,要知道现在的 X 共 8 位,若 Valve 高兴的话可以最多开 256 个宇宙,更别谈 Valve 事实上在 1 号宇宙中也存在着公然铺张浪费的现象,这部分留待下一章节再细说。
 楼主| 发表于 2025-2-26 11:09 | 显示全部楼层

(三)、深度解析 SteamID

本帖最后由 imyz 于 2025-2-26 14:41 编辑

      上一节内容提到 Valve 将 X 取值由 0 变 1,其本质是将原有的帐号由 0 号宇宙迁移至 1 号宇宙的行为,不过前面章节的重点是围绕玩家个人帐号类型(Individual)的分析,也就是前文所说 “保真” 的这部分,然而这一说法实际上不严谨,究其原因在于,虽然绝大多数玩家日常能接触到的是个人帐号这一类型,可也有例外,比如:Anonymous Game Server(匿名游戏服务器)类型,即官方文档中帐号类型序号为 4、字母为 ‘A’ 那个。匿名游戏服务器类型帐号是 Valve 分配给玩家自搭建 Steam 组服务器(Dedicated Server)之用的,即俗称的“玩家私服”。从逻辑上讲,只要能获得并正确解析出该帐号,则这一类的服务器帐号也必然保真!那么要如何获取这一帐号呢?对有自建服务器的玩家而言很简单,直接在 Server Console 控制台中输入 “status” 指令并回车后即可见其真身,如下图:

02.ServerConsole.png

      既然这类帐号是分配给服务器的,那么显然对于无自建私服的普通玩家而言,若想直接获取该帐号显然是不可能的,但间接方式却是有的,以 CS:S(Counter-Strike: Source)这款游戏为例,玩家可以启动并进入自己的游戏客户端,然后点击 “寻找服务器”,再从出现的服务器列表中任选一个并加入,一旦成功进入服务器后,紧接着再按 ~ 即数字 1 左侧那个键以呼出游戏控制台,最后在控制台下方中输入 status 并回车提交即可显示出该服务器的基本信息,其中便有 SteamID,如下图中红框中冒号后面所示。注意:该方法并不适用于所有游戏,例如 L4D2 便不显示,不过好在理论上仅需知道一个服务器帐号便可举一反三。

03.ClientConsole.png

      上图中的 SteamID 分别显示了 SteamID3 和 SteamID64 两种格式,圆括号中的为后者。乍一看这两串东西感觉有点摸不着头脑,我一开始也这样,而有这种感觉其实是一般正常人的反应,虽然官方文档确实交待了 SteamID64 的来由,但 SteamID3 却说得相对隐晦,因为只讲了一半而另一半却只字不提!这事后面会再说到,还是先来讲相对简单的 SteamID64,请先看截图:
04.IDExample.png

      对于具备微机原理基础知识的盆友们相信应当很容易看懂这个示例。SteamID64 本质就是一个 64-bit (8 Bytes) 十六进制无符号整数,上图中间那串 “0101” 是其二进制形式,显然括号中的 “90257587859051544” 即为那台服务器 SteamID64 格式帐号的十进制形式。而 RegularID 那个 STEAM_X:Y:Z 格式与 SteamID64 之间的转换从上图中也能猜出个大概。可但是,“[A:1:1184846872:43212]” 这一 SteamID3 格式一眼看上去好像完全没逻辑对吧!?咱们还是先看官方文档唯一一处对该格式的简介,就是下图中箭头所指的那个,的确是简介没跑了:
05.SteamID3Format.png

      读下来好像明白了,但好像又没完全明白,W 后面不应当接字符 ‘]’ 就结束了吗?还有,它与括号中的 SteamID64 二者之间又是怎么相互转换的呢??的确这道题的解题过程有一点点绕,咱们首先得将那个 SteamID64 转换成十六进制,可得:0x0140A8CC469F5418,这样看可能还不太明显,接着再给它分个组:0x01  4  0A8CC  469F5418,再根据官方文档对其中各项的定义可得:X = 1, Y = 0, Z = 469F5418>>1 (右移一位) = 592423436, Type = 4, Instance = A8CC。现在应当能看出些东西了,比如:Type = 4 即对应类型字母 ‘A’,但余下有几个好像并不能直接代入对吧?这时官方文档中的计算公式 W=Zx2+Y 就派上用场了,将 Z 代入该公式即可得 W = 1184846872, 所以这个数字正好与图中 SteamID3 当中的对上了!可问题来了,图中那个 SteamID3 尾部的 “:43212” 又是个啥?这个问题的答案我在官方文档中是找遍了也找不着 —— 这便是我上面所说官方只字不提的那一半……噢,对不起,我这样讲确实也不严谨,因为得加上 “:1:” 之后才是严格意义上的一半。到这里必须得打断一下,现在新问题又来了,尤其是这个 “:1:” 中的 1 又代表啥呐?是 X 吗??假如它是,那么为啥官方不记作 [Letter:X:W] 或是 [Letter:X:W:Instance]???—— 针对这一点官方文档同样压根没交待,既然官方未给出正确答案,我们就先不纠结该问题,毕竟前面还有 Instance = A8CC 这个十六进制数还没用到,聪明的看官们必定想到了它大概率与 W 后面的 “:43212” 是等价的,因为我不会心算,只得老老实实用计算器来将其转换成十进制,果然得到 “43212”。

      在大致清楚了 SteamID64 与 SteamID3 之间的转换后,再来看 RegularID,那么很容易可得:STEAM_1:0:592423436。可此处这个 RegularID 是完全没有意义的,原因就在于我们若将 Type 换作 5、6、7 等帐号类型是可以得到完全相同的 RegularID。由此不难联想到:Valve 要么已准备放弃 RegularID 格式,要么就是又默不作声地对其进行了某些不为外人所知的改造…… 针对这点此处暂埋一个伏笔。至此,除这个伏笔和那个 “:1:” 来历尚未明确外,SteamID3 与另两种格式的转换已基本清楚了,并且还可以得出以下结论:
  • SteamID64 在 SteamID 宇宙中与自然正整数类似并且其本身是“连号的”;
  • RegularID(STEAM_X:Y:Z)因缺少 Type 与 Instance 俩基本元素,其本身若不作改造则仅适用于原 32-bit 体系;
  • SteamID3 还细分两种表示形式,[Letter:1:W] 适用于 Individual 类型,而 [Letter:1:W:Instance] 则适用除 Individual 外的其它类型。


      基于以上的结论可得,若暂抛开 RegularID 的伏笔不谈,三种格式相互转换当前仅余下 “:1:” 是否等于 X 这一问题,虽然官方并未正面给出答案,但并不妨碍我们利用已知条件来进一步审视与分析 [Letter:1:W:Instance] 这一格式:
  • 已知 Letter 代表 Account Type;
  • 已知 W = Z x 2 + Y;
  • 已知 Instance 代表服务器的实例号;


      归纳以上各项条件,组成一个 64-bit 帐号必要的 5 个基本元素当中,除 X 外其余均已确定。假如 “:1:” 之中的 1 不代表 X,显然 SteamID3 这一格式将因缺少必要元素而不适用于 64-bit 体系;同理,[Letter:1:W] 这一格式之所以能与 STEAM_X:Y:Z 相互转换,其中的 “:1:” 必然与 X 对应,这无疑相当于从反面/侧面证明了 “:1:” 逻辑上在 1 号宇宙中就必然是 X。很显然,我这个推理无论逻辑上如何完美都始终缺少一样证据,那么就直接上物证(这还得多谢 CS2):

06.cs2ds-invalid.png

      如此便又带来一个新的思考:之所以 Valve 将 SteamID3 格式定义为 [Letter:1:W] 而非 [Letter:X:W] 的真实意图,极有可能是想将其专用于 1 号宇宙,而在其它宇宙中则另有其它格式 —— 也只有如此才能合理地解释这个让人有些摸不着头脑的设定。另一方面,既然提到了帐号体系,再结合上面官方文档截图中 For 32-bit/64-bit system 的分类,将它与 [Letter:1:W], [Letter:1:W:Instance] 两种格式联系起来看,很显然前者因缺少 Instance 而仅适用于 32-bit 体系,因而作为其 32-bit 的表示形式,而后者则为其 64-bit 表示形式…… 现在是不是就彻底明白了官方文档这一表述背后的真实意思!再换句话讲:玩家帐号 [U:1:W] 其实也是 32-bit 的表示形式,那么它理论上还有 64-bit 表示形式,前面讲了官方定义它的 Instance = 1,严格上讲它应当长 [U:1:W:1] 这模样,而硬生生地将尾巴抹掉就显得很没道理对吧,现在若再结合我第(二)章节末尾那段再理解一下,是不是就能够从另一角度解释为什么我要用“弃用”、“公然铺张浪费”来形容?

----- 插播一条 -----
由此不得不再回到之前所说的“保真”一说,在清楚了 SteamID 三种格式之后应该不难理解,保真一说实际上是针对 RegularID 和SteamID3 二者,而 SteamID64 才应当是本尊。正因如此,SteamID64 理论上都是真的,保真与否在于 Valve 是否官宣启用。

----- 插播结束 -----

      既然 SteamID3 的格式尤其是针对服务器类型的已经能够确定,并且它包含了组成一个 64-bit 帐号的所有元素,从逻辑上讲它应当适用于其余帐号类型。可问题在于:诸如帐号类型为 ‘8’ 所给出的 “T / L / c” 这三个字母具体分属哪个号段呐?官方文档只提到 T = Mulit-user chats,L = Lobbies,c = Group(clan) chats,在 X, Y, Z, Type 均不变的情况下,欲在同一帐号类型下再细分号段,从数学上讲仅剩下 Instance 可用了,那么按照常理,要细分理应从高位下手,由于 Instance 是 20 bits,若仅取最高 4 bits 作标识位,理论上可以分为 0x00000, 0x10000, 0x20000, 0x40000, 0x80000 这 5 个大段,肯定够三个字母分,但具体要如何分呢?这又是官方只字未提的地方!不得已,只能自己找线索。

      但凡玩过 L4D2 这款游戏的玩家都应该知道它支持创建游戏大厅 (Lobby),这无疑是一个重要线索,也恰因我有这方面的需求,所以才注意到这个极少数人会去关注的一个极不起眼的细节:当游戏客户端创建好大厅并点击加入服务器时,在服务器端的控制台中仔细查找便可发现下图中 Reservation Cookie 处紧跟一个十六进制整数,即:箭头所指红框中的数字:

07.L4D2Lobby.png

      其本身已极不起眼了,这样定睛一看也还是不明显,那就再给它分个组:0x01  8  60000  03956b67,所以它就是一个采用十六进制数表示的 SteamID64 格式帐号,既然这个 Reservation cookie 是游戏客户端创建大厅后点加入服务器时出现的,我们就有理由相信它与 Lobby 密切相关,索性就暂时认为它就是该游戏客户端创建的那个大厅的 Lobby 号(我也没有证据),于是先锁定字母 ‘L’,再将其转换成 SteamID3 格式则为:[L:1:60124007:393216]。于是乎,基于目前所掌握的信息便可推导出以下推论:
  • 实例号 0x60000 最高位 ‘6’ 的二进制为 0110,则只可能归属于 0x40000 这个号段,其余均被排除;
  • 实例号 0x60000 与字母 ‘L’ 存在对应关系,并且极有可能专用于 L4D 系列(但不确定);
  • 基于以上,实例号高最 4 bits(即 6 所在位)应当为标识位;
  • 逻辑上 0x40000 才应当为分段的起始号,所以字母 ‘L’ 的起始号应当为 0x40000;
  • 基于避免铺张浪费的原则,0x40000 ~ 0x70000 这几段按理都应当是预留给 Lobby 的。


      貌似有点头绪了,于是就顺着这条线索继续深挖。进一步分析,若其成立,则预留给游戏大厅专用的仅有 4, 5, 6, 7 共四种类型,似乎太少!那么假如再多加 4 bits 则可得:4 x 2^4 = 64 种,这好像就有点合理了,若还不够还可再多加 4 bits 则有 64 x 2^4 = 1024!由此推测:Instance 的高 8 或 12 bits 应当是被用作实例的标识符,余下 12 或 8 bits 才应当是真正的实例序号。虽然字母 ‘L’ 已有着落,可余下的字母 ‘T’ 和 ‘c’ 的线索,我目前所能找到最早出现有关于它们的描述的就只有日期分别标注为 2009/11/07 和 2013/7/15 这两篇官方文档的历史记录,门牌号在此:

SteamID - 14:12, 7 November 2009

SteamID - 06:22, 15 July 2013

      显然这又侧面佐证了我在前面第(二)章节中对 Steam 帐号设计方面的猜测…… 言归正传:关于帐号类型 8 的定义最早于 2009 年出现且出现的唯一字母为 ‘T’,而在差不多 4 年后的 2013 年才同时增加了 ‘L’ 和 ‘c’。这样一来就为解题提供了充分条件,因为在不清楚未来的规划的情况下,号段最稳妥的划分方法就是先从最小开始而后递增,并且也符合常人的习惯。与此同时,考虑到早期从 32-bit -> 64-bit 的过渡,显然 Instance = 0 是兼容 [T:1:W] 这种 32-bit 形式的最佳号段,所以 ‘T’ 当初应该就是 0x01800000 这一段。基于该推理,帐号类型 8 下各字母的适用范围就暂被确定如下:
  • ‘T’ -> 0x0180000000000000 ~ 0x0183FFFFFFFFFFFF
  • ‘L’ -> 0x0184000000000000 ~ 0x0187FFFFFFFFFFFF
  • ‘c’ -> 0x0188000000000000 ~ 0x018FFFFFFFFFFFFF


      有一说一,因为这一理论没有官方文档的支撑或背书,所以该帐号类型的输出结果除 SteamID64 如假包换之外,其余 RegularID 和 SteamID3 两种我不敢说保真!!!与此同时,若有高人能提供线索助我补齐这一短板将不胜感激!

      接着再看类型 ‘7’ 即字母 ‘g’ 对应的帐号类型。该类型是指 Clan(战队) 即 Steam Group ID,就是由玩家创建的 “群组” 帐号。若自己就是群组的创建者或管理员,那该帐号的 ID 是可以直接取得的,方法就是启动并登录 Steam Client 客户端,点界面左上方菜单“社区”右侧自己的游戏帐户名会有下拉菜单,再点其中的 “群组 -> 编辑组资料” 会出现该组的详细信息,其中第一项 ID 便是。该 ID 的值事实上就是 W,将其代入格式 [g:1:W] 即可得到其 SteamID3 格式。但我这样讲与无凭无据信口开合没两样,因为官方从未这样讲过,那么举证只能靠自己了!所以,我从 Steam 社区官网找来了验证方法,门牌号在此:

How can you find your Steam Group 64 ID? [TUTORIAL]

08.MenuSteamGroup.png

      按其中的方法将自己的群组名字代入,并粘贴到浏览器地址栏后即可得到群组的 groupID64,详见下图中箭头所指红框中内容:

09.GroupID.png

      该 groupID64 就是 SteamID64 格式的十进制形式。前面已介绍过,先将其转换为十六进制后,再取其最低 32 bits(8 个十六进制数字) 即为 W 的十六进制形式,再将 W 转换回十进制后与上面所查到的 ID 对比,假如以上操作过程无误的话,对比结果必然是一致的。所以,我程序输出的 Group ID 这个类型的 SteamID3 格式的 32-bit 形式([g:1:W])理论上也保真!之所以这样说的原因在于:若玩家将自己查到的 groupID64 转换为十六进制后,应当无一例外地发现其必然是以 0x01700000 开头,而这也是为什么官方文档在该类型帐号的 SteamID64 identifier 位置上给出 0x0170000000000000 的原因(否则完全可以将其留空避免造成误导),而这也是官方文档在随后的示例中给出“Example: http://steamcommunity.com/gid/[g:1:4]”这个 32-bit 形式其背后的真实原因,显然官方的用意就是令 Instance = 0。如此一来,Instance 取值介于 0x00001 ~ 0xFFFFF 这一区间的帐号相当于被弃用了(或者被保留下来作今后扩展用)。也正是这个原因,我程序在“解锁”模式下输出该帐号类型的 SteamID3 格式的 64-bit 形式 [g:1:W:Instance] 也不敢说保真 —— 而我这样讲纯粹是依据以上的分析与推理,也举不出任何直接证据。在有人能够举证推翻我的推论之前,还是先不必过多纠结这一点,继续来解说余下的帐号类型。

      截至目前,我们已详细分析了 1 号宇宙中编号 1, 4, 7, 8 共四种帐号类型,虽然官方已注明编号第 0, 5, 9 三类不可用,但除第 9 类未给出对应的字母可直接不予理睬之外,尚余 0, 2, 3, 5, 6, 10。经过了上面对 SteamID3 格式的细致分析后,相信明眼人已经知道这余下几种类型的 SteamID3 格式应当如何构成了,我不和各位兜圈子,直接拉清单:

10.RangeSteamID3.png

      其中要解释一下类型 0,这一类型因为存在两个字母,而根据前面 CS2 服务器给出的信息得知大写 ‘I’ 对应 Instance = 0 这段,而小写 ‘i’ 则确实找不到直接的证据索性简单粗暴地如上图划分号段了。当然还有类型 10 也得交待下,官方定义它为匿名个人帐号类型,按理说应当与类型 1 一样将 Instance = 1 这一段定义给 32-bit 用,但我同样也找不到证据,姑且这样吧。此外,若大家细心则不难发现其中的共同特点:除类型 1 与 10(个人帐号)之外的其余类型,起始号段所采用的 SteamID3 格式均为其 32-bit 形式,而之所以如此也全是为了与类型 7 保持一致!

      还有一点,官方文档中提到了一个唤作“Cyber Café Accounts”的帐号,据官方表述,其专用于“Steam 网吧”(一个貌似与 SteamVR 有关的计划),并且与用户帐号均在同一宇宙中获取 Steam 帐号,并且官方正致力于将其转移至其专属宇宙…… 除此外我实在找不到任何与之有关且有用的信息,所以也暂不予理会。

      在解决了 SteamID3 格式之中力所能及能解决的困惑的同时保留仍未可知的困惑之后,若要实现三种格式在 0~5 已知各个宇宙中的相互无损转换,现在必须把前面埋下的伏笔给挖出来进一步讨论,即 RegularID 改造。咱们中医食疗法有“以形补形”的理论,就是俗称的“吃啥补啥”,既然 RegularID 缺少 Type 与 Instance 两个元素(以下分别简记作 “TN” 与 “IN”),我们不妨采用老祖宗的办法来帮它补齐,为确保兼容,具体我想到以下两种方案:
  • STEAM_X:Y:Z:TN:IN ;
  • STEAM_X:Y:Z:TN+IN ;


      第 1 种在实际使用中在我个人看来有一个小小的缺憾,就在于 TN 的表示上,若采用字母则必然将出现 STEAM_1:0:999:A:9999 的形式,开头已有字母而随后再在数字中间夹杂字母不是我喜欢的风格,而若改用数字则我的心态会好很多,如:STEAM_1:0:999:10:9999,可是一个帐号中出现 4 个冒号在感观上或多或少都有些“累赘”。综合考虑后,最终我选择了方案 2。以玩家个人帐号 STEAM_1:0:234 为例,已知 TN+IN = 0x100001,将其转换为十进制可得 1048577,所以其补齐后的模样应当是:STEAM_1:0:234:1048577,若按方案 1 则应为:STEAM_1:0:234:1:1,虽然眼下这个情景后者更清爽简洁,但前者则会让人看得不明就里而莫名产生敬畏感,感觉这就蛮对 Valve 的味!与前面 SteamID3 格式类似,我就暂且称 STEAM_X:Y:Z 为 RegularID 的 32-bit 形式,而 STEAM_X:Y:Z:TN+IN 则为其 64-bit 形式。

      至此,针对 SteamID 三种格式之间相互转换一事,若不纠结有无官方认证这事儿,则我们现在已经具备了充要条件,并且也细分了 RegularID 与 SteamID3 两种格式的 32-bit 和 64-bit 的两种表示形式。也正是基于此,我的程序区分“常态”与“解锁”两个模式,其默认为常态模式,即:默认 1 号宇宙(X = 1)并在最大限度内采用帐号格式的 32-bit 形式;而在“解锁”这一模式中,各类型的 RegularID 与 SteamID3 都将以 64-bit 形式出现,而类型 9 要问就是都不支持。所以,当见到下图中的输出结果时,虽然我也不敢说 100% 保真,但也请千万不要认为是程序出了 Bug。虽然这并非官方公布或经官方认证的,但的确是我目前能想到最合逻辑的,况且,即使今后官方给出标准答案与我的有出入我也完全不担心,既然能提到这点就表示显然已在我的考虑之中了,这也是我决定重写代码并将其标准化的用意之一,就等着官方说明来补全。

11.Style64-bit.png


针对 SteamID 转换一事的分析和推理至此也告一段落,接下来就该聊下转换程序本身。
 楼主| 发表于 2025-2-26 11:10 | 显示全部楼层

(四)、功能简介夹杂创作花絮

本帖最后由 imyz 于 2025-3-19 17:55 编辑

      前面章节已提到了程序支持“常态”与“解锁”两种模式,具体就是指程序针对 RegularID 与 SteamID3 这两个格式的输出在不同模式下有差异,再具体就是前面提到的 32-bit 与 64-bit 两种表示形式的不同,纯文字想表述清楚太费劲,还是详见下图的支持列表一目了然:

12.RangeUniverses.png

Modes.jpg

      相信看完上图就应当能充分理解程序的核心功能了。原则上讲,常态模式完全没必要存在例外,那个例外一严格讲也不算真正的例外,因为除 RegularID 外 SteamID3 与 SteamID64 均不受支持,这样做只是为了与 Valve 保持一致;而例外二也是没必要的,之所以决定破例完全是因为前面章节中 CS2 服务器的那张截图。此外,基于我在前面章节中的推理加上事实再来回顾下 Valve 对当前各宇宙的命名,就不难理解 Valve 将 1 号宇宙命名为“Public 公众”其背后的真正涵义了。显而易见的是,假如不对 STEAM_X:Y:Z 进行改造,那么它将仅适用于上图中玩家个人帐号那一号段(0x0110000100000000 ~ 0x01100001FFFFFFFF)。

功能特点:
  • 同时接受 RegularID, SteamID3, SteamID64 三种格式作为源字符串输入,程序将自行识别。
  • 若源字符串为包含两种或以上格式的组合字串,则以识别到的第一个为准,其余则舍弃。
  • SteamID64 格式作为源字符串为十进制与十六进制双持,若该字串不以十六进制标识符“0x”开头并且其中不含“ABCDEF”(含小写)中任一字符的则默认其为十进制。
  • 解锁模式下的输出尽数采用 64-bit 形式,相当于还原了 RegularID 及 SteamID3 格式在 64-bit 体系下其原本的样子,可以理解为“64-bit 原生模式”。
  • 常态模式如支持列表,相当于 32-bit 与 64-bit 共存的“混合模式”或“兼容模式”。
  • 未采用正则表达式(Regex)匹配源字符串,而是自己堆代码 —— 准确讲这不算特点而是难点,但真正的难点却又不是这个,放这里凑下数。


跨平台支持:
  • PC / Mac Intel;注:Mac 下编译采用的架构为 Standard(Apple Silicon, Intel),可手上暂无 Apple Silicon 电脑而不能确定能否运行。
------ 2025/03/19 更新 ------
  • PC / Mac (Apple Silicon & Intel)
------ 更新完毕 ------

系统要求:
  • macOS 不低于 10.15。
  • Windows 仅限安装了 .Net Framework 4.8.1(或以上)的 64 位 (x86_64) 版。


分发形式:
  • macOS:仅提供一个独立 App。
  • Windows:由主程序(.exe) + 转换库(.dll) 两个文件组成。
  • 因为 macOS App GUI (Objective-C) 与转换库(C++) 均为原生代码,所以转换库采用静态库(.a)方式生成,再与 GUI 直接链接打包为一个 App;而 Win GUI 采用了 CLI 托管代码而转换库则是原生 C++,在这种混编模式中,CLI 代码要调用原生代码生成的静态库(.lib) 只能是采用 CLI 写一套封装类作为中间层调用原生代码并暴露接口,再将其生成动态库(.dll) 供 CLI 调用…… 看到没,最终还得是 .dll,我的确尝试过该方法,虽然程序可以正常运行,但感觉舍近求远了,因为 C++/CLI 可以直接调用原生代码动态库 .dll。显然,不论哪种方式 Win GUI 都得拖一个 .dll,所以转换库就采用原生 C++ 代码执行效率反倒更高。


已知问题
  • 因个人能力有限暂不支持 Linux GUI。
  • RegularID 格式的 64-bit 形式(STEAM_X:Y:Z:TN+IN)纯属我个人臆测,主要用于完成三种格式之间无损转换之用,不代表官方。
  • 程序针对帐号类型 Type 2, 3, 6, 8, 10 的 SteamID3 格式输出结果仅在逻辑上正确,因未找到实际例子而无法确保与官方的一致。


      由于程序本身所实现的功能较单一,所以也没过多可介绍的,可若这一章就这样结束似乎显得有些敷衍,所以就强行给自己加戏,将一些创作花絮也加上:
      对于已看明白前面章节内容的大佬而言,这一节的内容其实没有实际意义了,自己动手或者让 AI 来编码估计也不是什么难事。而我属于喜欢自我挑战,就喜欢自己纯手工堆码,可悲的是,等我把这一切都想明白之后,发现第一版代码果然绝大部分都得死,于是心一横真就推倒重来了,这无异于生生地又给自己上强度…… 纯手工堆码过程的确很辛苦,可一旦思路清晰之后效率比之前可谓有成倍提升,反倒感觉整体过程并没那么枯燥,有时甚至有种我的手指有它们自己的想法的那种感觉,也得亏这只是个小小工程我才敢这样讲。这当中唯一的难点在于对类的架构设计,要找到三种帐号格式中的共性部分并将其抽象出来分层次构建,再充分利用纯虚函数重载进一步将代码和功能标准化、接口化,一来为提高代码复用度,二来是为今后保留一定可扩展能力,代码品质也会有保障,可以这样总结:对各个类的分层次构建设计及其初始化过程才是我程序打磨过程中最核心也是最耗时的部分。当然了,标准化的代价也是有的,这直接导致要处理任意一种格式,哪怕“源=目标”都必须按规定动作完成,对于有需要上强度大批量转换的场景下,执行效率层面显然会拖些后腿,但好在对日常使用场景而言几乎没有影响。而关于编程语言的选择方面,我本身作为 C/C++ 受害者,再加上开篇便提到考虑到转换库要跨平台,很自然首选的 ISO C++,而 GUI 的语言则没什么好选的,macOS 没有采用最新的 Swift 而使用 Objective-C + Storyboard 故事板,主要也是考虑 Objective-C 与 C++ 混编更方便些,而 Windows GUI 则是 C++/CLI(托管)与 C++(原生)混编。可喜的是,这几套代码分别在三个平台下均做到了编译与链接 0 错误 + 0 警告通过。以下是所使用的编程语言清单:
  • 转换库:ISO C++17
  • macOS GUI: Objective-C + Storyboard
  • Windows GUI: C++/CLI
  • Linux:暂无 GUI,命令行 CLI 为 ISO C++


      本着对自己的作品负责任的态度,我也担心那个老生常谈的内存安全问题,C++ 虽然不能算作内存安全的语言,但我认为语言永远不会是决定性因素,所以我极尽可能地用标准库函数和数据类型,旦凡涉及指针,除接口调用函数返回不得不采用 extern C 声明而无法采用智能指针(码农应该懂)之外,其余尽数使用智能指针 const std::unique_ptr 与 const std::shared_ptr 来防止内存泄漏,大家没看错,连 unique_ptr<> 我也用 const 限定,同时,转换库代码唯一一处使用 new 创建对象的接口调用也必然配对 delete 坚决予以事后销毁。与此同时,对于所有的类成员变量及成员函数,除极个别临时变量外,也悉数加 const 修饰符防止被意外修改,包括函数返回值以及所有无须修改成员变量的成员函数也尽数用 const 来限定其返回值并将其限定为常量成员函数,即:const string Method(…) const;,再就是类型转换也有必要的越界检查…… 虽然不敢确保 100% 内存安全,但在防止内存泄漏这方面多少还是有些信心。为说明这一点,直接上强度,先循环一个小目标数(1 亿次)看看其表现:

13.Loop.png

      测试环境就直接用的开发机,其为 ESXi 主机上开的一台 Win11 虚拟机,分配 4 核 + 8GB RAM。因测试不必赶时间所以就开单线程,测试内容由上图可知,在 for 循环中创建一个 dllDelegate 局部委托对象来调用封装好的转换库 .dll,再用一个全局变量接收其返回值,每次调用结束后便自动释放资源,即:

创建委托对象 -> 读取并加载 .dll 库 -> 调用 .dll 入口函数创建转换对象 -> 转换并返回值 -> 释放转换对象与 dll 库 -> 接收返回值 -> 释放委托对象…… 如此循环 1 亿次。

      因为这只是个测试程序,所以代码中 “int count(stoi(argv[1]))” 这句类型转换图省事没有放异常判断和处理代码,还请明眼人轻喷!在程序运行过程中,由以上截图中任务管理器的读数可直观看到 dlltest.exe 这个进程的资源占用情况,它在执行全过程基本上就稳定在图中那个状态,即:CPU 19~20%,RAM 0.4MB —— 这样基本可以说明程序代码在循环执行过程中没有发生内存泄漏的问题,而系统整体性能页面也能看到 CPU 与 RAM 的占用一直稳定在一个均值小幅变化,最终的结果显示整个过程耗时约合 12.9 小时,虽然调用过程是一亿次,可它背后的工作量可能是成百上千倍,所以耗时的确较长,毕竟单线程,所以出现下图中“一核有难、三核围观”的场景也就不足为奇了,也请大佬们轻喷:

14.Performance.png
15.ALittleTarget.png

      可能有人会提出,上面的测试若不创建委托对象而直接调用 .dll 效率上肯定会更好!没错,但我的程序支持“常态”与“解锁”两种模式,在调用方法上有细分,为了使主程序不必了解调用细节则需要对该过程进行封装,包括上面提到的接口调用采用了 new 创建对象,而其销毁 delete 工作也正是由委托来完成以实现调用过程“标准化”,同时也确保了主程序代码简洁明了。虽然上面那个 dlltest.exe 实际上仅使用了一种模式并且是 C++ 原生代码原则上是不必委托的,之所以仍然使用委托而不直接调用的用意是为了模拟 GUI 托管代码的调用过程。类似的,macOS 系统也编译了其对应的 .dylib 动态库,同样采用上述命令行方式循环调用/释放 50 万次并用 Instruments 工具检测代码执行过程中是否存在内存泄漏,如下图所示 Leak Checks 一路绿勾通过:

16.Instruments-LeaksCheck-s.png

      程序中唯一的短板应当就属于我力排 Regex 正则表达式库而自己写的那堆解析源字符串的部分,每种格式的均不到 200 行,三种合计也不超 600 行,就我目前的测试程序中所包含的各种示例字符串而言,它们都还能很好地应付,希望正式发布之后也能有好的表现。为尽可能防止意外情况,我还专门写了自动测试程序针对上面支持列表中 0~5 宇宙的各个号段的边界值做过通过测试,理论上讲,只要是我写的那不超 600 行源字串解析代码不出 Bug,程序输出应当是不会出差错的。假如真有 Bug,届时再有劳各位另行反馈吧。还有,程序 Logo 的制作全程都是用 PowerPoint 完成的,虽然和专业 PS 出图效果没得比,但大体上看效果也还行,我估计应当有不少人不会想到 PPT 还能干这活吧!?
(正文完)

      还是老规矩,程序采用了 7-Zip 压成唤作 SteamIDConverter.exe 的自解压包,字节数大小为 1,024,555 Bytes(macOS 与 Windows 均显示一致) ,双击自解压后将得到以下目录结构所示各文件,因 Mac 版的 App 在 Windows 下显示为一个目录,所以我将它单独再 zip 了一下,所以还需要进一步解压才能得到可执行程序本体:
.
├─ Mac
│   └── SteamIDConverter-Mac.zip
└─ Win
    ├── SteamIDConv.dll
    └── SteamIDConverter.exe

SteamIDConverter.exe
https://www.alipan.com/s/oZQJoSFD5Mb
提取码: u98d
发表于 2025-2-26 14:41 | 显示全部楼层
楼下看懂了吗?宝宝我没看懂
发表于 2025-2-26 14:43 | 显示全部楼层
开篇用 100 字以内介绍一下你的程序和这个区别在哪, 我觉得观感会好一些 =,=
https://www.steamidfinder.com/
发表于 2025-2-26 14:47 | 显示全部楼层
看了半天不知道解决了什么问题?
发表于 2025-2-26 14:48 | 显示全部楼层
分析的挺有意思的,但是我选择 https://steamrepcn.com
 楼主| 发表于 2025-2-26 14:58 | 显示全部楼层
xy. 发表于 2025-2-26 14:43
开篇用 100 字以内介绍一下你的程序和这个区别在哪, 我觉得观感会好一些 =,=
https://www.steamidfinder.co ...

感谢提醒!

我写这程序的原意并没有打算与您给出的这类网站进行比较,我刚也大致看了下那个网站,基本功能也就是 Valve 官方文档中直接找得到的玩家个人帐号类型的转换,其它诸如游戏服务器的 ID:90257587859051544,[A:1:1184846872:43212] 这种就格式就无法识别了。而这个仅仅是我程序 “常态” 模式所完成的一部分工作。

真要直接对比的话,就以我第四章中的 “支持列表” 为例,您提供的那个网站的功能就是我表中 “常态” 模式那一列中的 “帐号类型 1” 玩家个人帐号这一部分吧。具体您可以根据我提供的那个清单中的各个号段去对比一下
 楼主| 发表于 2025-2-26 15:00 | 显示全部楼层
fjxyx 发表于 2025-2-26 14:47
看了半天不知道解决了什么问题?

的确是个非常小众的需求
发表于 2025-2-26 15:13 | 显示全部楼层
同为L4D2玩家,你的钻研精神值得我学习。🙂
发表于 2025-2-26 15:52 | 显示全部楼层
牛逼,这种钻研精神属实难得
发表于 2025-2-26 16:09 | 显示全部楼层
十分严谨,佩服。
发表于 2025-2-26 16:30 | 显示全部楼层
任何能为官方文档填坑的行为,都令人敬佩,在官方微不足道的省略一些东西,往往能让外部人员苦苦挣扎。
发表于 2025-2-26 16:40 | 显示全部楼层
太长了,这是干啥的?
发表于 2025-2-26 16:47 来自手机 | 显示全部楼层
TLDR

概括下:所有大公司的代码历史都是屎山
 楼主| 发表于 2025-2-26 17:28 | 显示全部楼层
terryhux 发表于 2025-2-26 16:40
太长了,这是干啥的?

哈哈哈哈哈,看不明白也正常,说明没需求压根不关注这事。
发表于 2025-2-26 20:44 | 显示全部楼层
看起来很高级,就是没看懂。

能有人总结概括一下吗
 楼主| 发表于 2025-2-27 09:07 | 显示全部楼层
nickybaby 发表于 2025-2-26 20:44
看起来很高级,就是没看懂。

能有人总结概括一下吗

哈哈哈哈哈,不要慌,没看懂其实很正常。

要想真正看懂其实本身是有一定的门槛的,假如某位大佬在从未(打算)深入了解过 SteamID 这东西是如何构成的情况下也能看懂的话,这人肯定是个天才!
发表于 2025-2-27 09:12 来自手机 | 显示全部楼层
佩服楼主。

不知楼主能否满足一下好奇心,steamid为什么需要转换,说实话,楼主发这贴之前我都没想过哪里需要steamid
发表于 2025-2-27 09:15 | 显示全部楼层
钦佩楼主钻研精神
发表于 2025-2-27 09:17 | 显示全部楼层
虽然用不到,但是支持一下。说不定以后就用到
 楼主| 发表于 2025-2-27 09:29 | 显示全部楼层
本帖最后由 imyz 于 2025-2-27 09:39 编辑
shiangyeh 发表于 2025-2-27 09:12
佩服楼主。

不知楼主能否满足一下好奇心,steamid为什么需要转换,说实话,楼主发这贴之前我都没想过哪里 ...


恭喜!问这个问题说明您入坑 Steam 还不深!!!可得小心别被我带沟里了

要说为什么 SteamID 需要转换,说到底还是 Valve 搞出来的花花肠子,比如你的 Steam 好友只知道自己的 ID 是 STEAM_1:0:234,而你又想查下他/她的 Steam Community 社区信息,这时你就需要将该格式转换为下图中黄色高亮的 URL 再用浏览器去访问:

Use.png


另外,其实我在文章中也提示过一个需要转换的场景:CS:S 与 L4D2 两款游戏分别采用了不同的格式来显示玩家 ID,假如你是服务器管理员,就不得不去了解二者的互换关系,以防你有需要对该 ID 的玩家进行一些相应的管理操作。

所以,绝大多数人是没有这类需求的。
发表于 2025-2-27 09:54 | 显示全部楼层
imyz 发表于 2025-2-27 09:29
恭喜!问这个问题说明您入坑 Steam 还不深!!!可得小心别被我带沟里了  

要说为什么 SteamID 需要转换 ...

已经CS2了啊,CS:S后面还有个CS:GO
发表于 2025-2-27 10:02 | 显示全部楼层
Steam 登录账户名不让改一直是个遗憾
发表于 2025-2-27 10:03 | 显示全部楼层
个人爱好码农+个人爱好网安=实际上小破公司的打杂的表示,楼主人才啊

回头看了眼自己的steam。。。。好友数为0.。。。。。
 楼主| 发表于 2025-2-27 12:10 | 显示全部楼层
Gone 发表于 2025-2-27 10:02
Steam 登录账户名不让改一直是个遗憾

可不,我也愁这事
 楼主| 发表于 2025-2-27 12:14 | 显示全部楼层
Junh@wk 发表于 2025-2-27 09:54
已经CS2了啊,CS:S后面还有个CS:GO

可能一开始习惯了 CS:S 的风格,CS:GO 一下改得让我不太适应,所以一直闲置着直到某天它变成了 CS2

如今的 CS2 因为核显还不太能跟得上,期待 890M 能再降降价,独显我现在也完全没兴趣,加上年龄也上来了,再不像以前年轻时那么有激情了
发表于 2025-2-27 12:15 | 显示全部楼层
楼下看懂了吗?宝宝我没看懂
发表于 2025-2-27 19:24 来自手机 | 显示全部楼层
imyz 发表于 2025-2-27 09:29
恭喜!问这个问题说明您入坑 Steam 还不深!!!可得小心别被我带沟里了  

要说为什么 SteamID 需要转换 ...

懂了,想了下自己确实没有这种需求。

steam好友都是朋友,也没怎么玩steam上面的联机。
发表于 2025-2-27 20:47 | 显示全部楼层
没看懂干嘛的。。
粗看了一眼代码,41行dlg初始化构造了count次, 明显可放在循环外
您需要登录后才可以回帖 登录 | 加入我们

本版积分规则

Archiver|手机版|小黑屋|Chiphell ( 沪ICP备12027953号-5 )沪公网备310112100042806 上海市互联网违法与不良信息举报中心

GMT+8, 2025-4-27 18:37 , Processed in 0.019856 second(s), 6 queries , Gzip On, Redis On.

Powered by Discuz! X3.5 Licensed

© 2007-2024 Chiphell.com All rights reserved.

快速回复 返回顶部 返回列表