news 2026/9/4 12:53:09

从零构建TrinityCore:C++大型项目实战与游戏服务器架构解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从零构建TrinityCore:C++大型项目实战与游戏服务器架构解析

这次我们来看一个对游戏开发者和C++学习者都很有价值的项目——TrinityCore。这是一个开源的《魔兽世界》服务端模拟器,完全由C++编写。如果你对大型多人在线游戏(MMO)的服务器架构、网络通信、数据库设计,或是想通过一个真实的大型C++项目来提升自己的编程能力,那么TrinityCore是一个绝佳的研究对象。它不是一个玩具,而是一个功能相对完整、持续维护的复杂工程。

最值得关注的点在于,它提供了一个完整的、可编译运行的“魔兽世界”私服环境。这意味着你可以:

  1. 研究游戏服务器核心逻辑:从玩家登录、地图加载、战斗计算到任务系统,源码即文档。
  2. 深入学习C++在大型项目中的应用:涉及面向对象设计、模板、多线程、网络编程、内存管理等核心知识。
  3. 实践数据库设计与优化:使用MySQL,需要理解大量表结构及其关联。
  4. 搭建可交互的测试环境:可以自己运行服务器,创建角色,体验并调试游戏功能。

本文将带你从零开始,完成TrinityCore服务端的编译、部署和基础运行。重点不是教你搭建一个可玩的私服(这涉及复杂的资源文件配置),而是将其作为一个C++项目进行研究和学习。我们会关注环境准备、编译过程、服务启动、数据库配置以及如何通过简单的修改来验证你对代码的理解。整个过程对硬件要求不高,但需要一定的耐心和命令行操作基础。

1. 核心能力速览

能力项说明
项目类型开源MMO游戏服务端模拟器(Emulator)
开源团队TrinityCore 开发团队
编程语言C++ (核心),辅以少量其他语言脚本
数据库MySQL / MariaDB
主要功能模拟《魔兽世界》游戏服务器逻辑,包括认证、世界服务器、角色、战斗、任务、副本等
推荐硬件现代CPU,4GB以上内存,足够的磁盘空间(约30GB用于源码、编译和数据库)
显存/GPU非必需。服务器端是纯逻辑计算,不涉及图形渲染。集成显卡即可。
支持平台Windows (Visual Studio), Linux (gcc/clang), macOS (理论上支持)
启动方式命令行启动多个独立进程(Authserver, Worldserver)
是否支持API支持通过REST API或TCP Socket进行有限的管理和查询(需额外配置或修改源码)。
是否支持批量任务服务端本身处理海量玩家请求即是“批量任务”。可通过数据库脚本或GM命令批量操作游戏内数据。
适合场景C++高级学习、游戏服务器架构研究、数据库应用实践、自定义游戏逻辑实验

2. 适用场景与使用边界

适合谁?

  • C++中级及以上开发者:想通过大型项目巩固设计模式、内存管理、网络编程。
  • 游戏服务器后端工程师:希望研究经典MMO的服务器架构设计。
  • 计算机专业学生:寻找有挑战性的课程设计或毕业设计项目。
  • 《魔兽世界》技术爱好者:对游戏运行机制有浓厚兴趣,想知其所以然。

能解决什么问题?

  1. 学习难题:提供了一个超过百万行代码的、结构清晰的大型C++工程实例。
  2. 实践难题:将网络、数据库、多线程、脚本等理论知识在一个具体项目中串联起来。
  3. 研究难题:可以直观地看到游戏中的技能、怪物AI、地图切换等是如何通过代码实现的。

不适合什么场景?

  • 寻求“一键安装”的纯游戏玩家:TrinityCore需要编译和配置,不是解压即用的客户端。
  • 低配置或纯图形化界面用户:整个过程主要在命令行和代码编辑器中进行。
  • 希望用于商业运营:这不仅涉及复杂的运维和优化,更关键的是法律风险。暴雪娱乐拥有《魔兽世界》的完整知识产权,未经授权公开运营服务器属于侵权行为。

法律与合规边界

  • 仅供学习与研究:请在私人网络环境运行,勿公开访问。
  • 使用正版客户端资源:你需要拥有合法版本的《魔兽世界》客户端,并从其中提取必要的数据文件(DBC, Maps, VMaps等)。严禁分享这些受版权保护的数据文件。
  • 尊重开源协议:TrinityCore基于GPLv3协议开源,任何基于它的修改和分发也需遵守该协议。

3. 环境准备与前置条件

在开始编译之前,请确保你的系统满足以下条件。以下以Windows 10/11 + Visual StudioUbuntu 22.04 LTS两种主流环境为例。

3.1 通用准备

  1. 磁盘空间:至少准备30GB可用空间,用于存放源码、编译中间文件、数据库和客户端资源。
  2. 网络环境:需要稳定连接以下载源码、依赖库和数据库更新包。

3.2 Windows 环境 (Visual Studio 2022)

  • IDE/编译器:安装 Visual Studio 2022 ,在安装时务必勾选“使用C++的桌面开发”工作负载。CMake会用到MSVC编译器。
  • Git:安装 Git for Windows 。用于克隆代码库。
  • CMake:安装 CMake (版本 3.24 或更高)。安装时选择“Add CMake to the system PATH”。
  • OpenSSL:TrinityCore需要OpenSSL。推荐使用预编译版本。你可以从 slproweb.com 下载适合你系统的Win64 OpenSSL安装包(如Win64 OpenSSL v3.x.x)。安装后,记住安装路径(例如C:\Program Files\OpenSSL-Win64)。
  • MySQL:安装 MySQL Community Server 8.0 或 MariaDB 。安装过程中记住你设置的root用户密码。同时安装MySQL WorkbenchHeidiSQL用于图形化操作数据库。

3.3 Linux 环境 (Ubuntu 22.04)

打开终端,依次执行以下命令安装基础工具和依赖:

# 1. 更新系统包列表 sudo apt update && sudo apt upgrade -y # 2. 安装编译工具链、Git、CMake sudo apt install -y build-essential clang cmake git # 3. 安装必需库 sudo apt install -y libssl-dev libcurl4-openssl-dev libreadline-dev libncurses-dev libboost-all-dev mysql-server libmysqlclient-dev # 4. 安装MySQL (如果未安装) 并设置root密码 # 安装过程中会提示设置密码,请务必牢记。 sudo apt install -y mysql-server sudo systemctl start mysql sudo systemctl enable mysql # 5. (可选但推荐) 安装图形化数据库工具 sudo apt install -y mysql-workbench

4. 安装部署与启动方式

整个过程分为四个主要步骤:获取源码、生成编译配置、编译项目、配置数据库。

4.1 获取源代码

在你想存放项目的目录(例如D:\Dev~/dev)打开命令行或终端,克隆官方仓库。

# 克隆 TrinityCore 主仓库 git clone https://github.com/TrinityCore/TrinityCore.git cd TrinityCore

4.2 使用 CMake 生成构建文件

这一步会根据你的系统环境,生成 Visual Studio 的.sln解决方案文件或 Linux 的Makefile

Windows (在 TrinityCore 目录下打开 PowerShell 或 CMD):

# 创建一个构建目录并进入 mkdir build cd build # 运行 CMake,指定源码目录(..)和生成器(Visual Studio 17 2022),并指定OpenSSL路径 # 请将 `-DOPENSSL_ROOT_DIR` 的值替换为你实际的 OpenSSL 安装路径 cmake .. -G "Visual Studio 17 2022" -A x64 -DOPENSSL_ROOT_DIR="C:\Program Files\OpenSSL-Win64"

如果一切顺利,你会在build目录下看到TrinityCore.sln文件。

Linux (在 TrinityCore 目录下):

mkdir build cd build # 使用 Clang 编译器(推荐)或 GCC cmake .. -DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=/usr/bin/clang++ -DWITH_WARNINGS=1 # 或者使用 GCC # cmake .. -DWITH_WARNINGS=1

4.3 编译源代码

这是一个耗时较长的过程,取决于你的CPU性能。

Windows:

  1. 用 Visual Studio 2022 打开build/TrinityCore.sln
  2. 在顶部工具栏,将解决方案配置从Debug切换到Release
  3. 在“解决方案资源管理器”中,右键点击解决方案TrinityCore,选择“重新生成解决方案”。
  4. 等待编译完成,成功后在build/bin/Release/目录下会生成authserver.exeworldserver.exe等关键文件。

Linux:

# 在 build 目录下,使用多核编译以加快速度。-j 后面的数字是你的CPU核心数 make -j $(nproc) # 或者直接 make (单核编译) # make

编译成功后,可执行文件位于build/bin/目录下。

4.4 配置数据库

这是最关键也最容易出错的一步。TrinityCore 使用一个复杂的数据库结构来存储所有游戏数据。

  1. 创建数据库用户和空库: 使用 MySQL Workbench、HeidiSQL 或命令行,登录你的 MySQL 服务器,执行以下SQL语句(密码请自定义):

    CREATE USER 'trinity'@'localhost' IDENTIFIED BY 'trinity'; CREATE DATABASE auth CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE DATABASE characters CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE DATABASE world CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; GRANT ALL PRIVILEGES ON auth.* TO 'trinity'@'localhost'; GRANT ALL PRIVILEGES ON characters.* TO 'trinity'@'localhost'; GRANT ALL PRIVILEGES ON world.* TO 'trinity'@'localhost'; FLUSH PRIVILEGES;
  2. 导入基础数据库结构: 在TrinityCore/sql/目录下,有创建基础表的SQL文件。

    • 先导入base目录下的文件:按顺序执行auth_database.sql,characters_database.sql,world_database.sql到对应的数据库中。
    • 然后,你需要获取并导入TDB (TrinityCore Database)文件。这是一个包含游戏世界数据(物品、NPC、任务等)的巨大SQL文件。你需要从 TrinityCore 的 官方发布页面 或相关社区找到与你源码版本号匹配的TDB_full_*.sql文件,并将其导入到world数据库中。这是让世界“有内容”的关键一步。
  3. 更新数据库sql/updates目录下存放了增量更新文件。TrinityCore 提供了自动化工具来应用这些更新。编译后生成的bnetserverworldserver在第一次运行时,也会尝试自动应用缺失的更新。

4.5 提取客户端数据文件

要让服务器认识游戏世界的地图、地形、DBC(游戏数据表),你需要从合法的《魔兽世界》客户端中提取这些文件。

  1. 将你的魔兽世界客户端放在一个路径不含中文和空格的目录。
  2. 在编译输出的bin/Release(Win) 或bin/(Linux) 目录下,你会找到一些提取工具,如mapextractor,vmap4extractor,vmap4assembler等。
  3. 运行这些工具,按照提示指向你的客户端目录,它们会生成dbc,maps,vmaps,mmaps等文件夹。
  4. 将这些生成的文件夹复制到你的服务器运行目录(即authserverworldserver所在的目录)。

5. 功能测试与效果验证

编译和配置完成后,我们启动服务并进行基础验证。

5.1 启动服务端进程

服务端由两个主要进程组成:

  • authserver:认证服务器,处理账号登录。
  • worldserver:世界服务器,处理游戏内所有逻辑。

你需要为它们准备配置文件。在运行目录下,通常会有.dist后缀的配置示例文件(如authserver.conf.dist,worldserver.conf.dist)。将它们复制一份并去掉.dist后缀。

# 假设你在编译输出目录 /build/bin/Release (Windows) 或 /build/bin (Linux) cp authserver.conf.dist authserver.conf cp worldserver.conf.dist worldserver.conf

重点配置worldserver.conf用文本编辑器打开worldserver.conf,找到并修改以下关键配置(其他保持默认即可):

LoginDatabaseInfo = "127.0.0.1;3306;trinity;trinity;auth" WorldDatabaseInfo = "127.0.0.1;3306;trinity;trinity;world" CharacterDatabaseInfo = "127.0.0.1;3306;trinity;trinity;characters"

这告诉服务器如何连接你之前创建的数据库。

启动顺序:

  1. 首先启动authserver。在命令行中运行它,看到它监听在3724端口且无报错即可。
  2. 然后启动worldserver。这是主进程,启动时会加载DBC、地图数据,并应用数据库更新。首次启动会较慢,请耐心等待直到看到World initialized.之类的日志,并出现TC>的命令行提示符。

5.2 创建游戏账号与连接测试

worldserver启动后,你可以在它的控制台里使用命令。

  1. 创建账号: 在worldserver的控制台输入:

    account create test 123456

    这创建了一个用户名为test,密码为123456的账号。

  2. 提升账号权限(否则无法在游戏中使用GM命令):

    account set gmlevel test 3 -1
  3. 修改游戏版本(可选): 为了让你的客户端能连接,可能需要修改服务器允许的客户端版本号。在worldserver.conf中搜索Game.Build.Version,将其修改为你的客户端版本号(需自行查询)。

  4. 修改客户端连接地址: 找到你的魔兽世界客户端目录下的realmlist.wtf文件,用记事本打开,将其内容修改为:

    set realmlist 127.0.0.1
  5. 启动游戏客户端,使用账号test和密码123456登录。如果一切配置正确,你将能看到服务器列表(只有一个你的服务器),并成功进入角色创建界面。

5.3 基础功能验证

进入游戏后,你可以通过GM命令来验证服务器功能是否正常:

  • 刷物品.additem [物品ID](例如.additem 25刷一把损坏的长剑)
  • 学习技能.learn all学习所有技能
  • 传送.tele [地名](例如.tele stormwind传送到暴风城)
  • 刷怪.npc add [生物ID]
  • 修改等级.levelup 80

这些命令的成功执行,证明服务器的核心逻辑(物品系统、技能系统、地图系统、生物系统)是正常工作的。

6. 接口 API 与批量任务

TrinityCore 本身是一个TCP游戏服务器,其原生接口是游戏客户端协议。但对于管理和自动化,可以通过以下方式扩展:

6.1 内置的SOAP与REST API(部分版本支持)

一些版本的 TrinityCore 编译时可以通过-DSOAP=1-DREST=1CMake选项启用SOAP和REST服务。启用后,可以在worldserver.conf中配置端口。

  • SOAP:基于XML的远程调用,可以执行GM命令。
  • REST:提供HTTP JSON接口,查询服务器状态、玩家信息等。

启用后,你可以使用curl或编写脚本进行调用:

# 示例:通过REST API查询在线玩家(假设端口8085) curl http://127.0.0.1:8085/api/players

6.2 通过数据库进行“批量任务”

最直接的批量操作方式是直接操作数据库。例如,你想给所有玩家发送邮件或物品:

  1. 使用MySQL Workbench连接到你的characters数据库。
  2. 编写SQL语句,操作mailitem_instance等表。操作前务必备份数据库,并充分理解表结构。

6.3 自定义脚本与模块

TrinityCore 支持通过Eluna Lua Engine或自定义C++模块(Module)来扩展功能。你可以编写Lua脚本或编译独立的动态链接库(DLL/so),实现定时任务、复杂事件或新的HTTP API接口。

  • Eluna:在worldserver.conf中启用,然后将.lua脚本放入指定目录,服务器会自动加载。
  • C++ Module:需要按照 TrinityCore 的模块开发规范编写代码,重新编译生成模块文件,放入modules目录。

7. 资源占用与性能观察

作为一个游戏服务器,其性能消耗主要在CPU和内存,与显卡无关。

  • CPU占用:在无玩家或玩家很少时,worldserver的CPU占用很低(<1%)。当有大量生物(NPC)需要计算AI,或玩家密集施法、战斗时,CPU占用会显著上升。单核性能是关键。
  • 内存占用worldserver进程的内存占用是主要部分。启动后,加载了DBC、地图数据,内存占用可能在1-2GB。随着游戏内实体(玩家、NPC、游戏对象)增多,内存会线性增长。authserver内存占用很小(几十MB)。
  • 数据库负载:游戏运行时,会频繁读写characters数据库(保存角色数据)。world数据库主要是只读查询。数据库性能是支撑在线人数的关键。
  • 网络IO:每个玩家连接都会占用一个Socket。服务器需要处理大量的小数据包。

观察方法:

  • Windows:使用任务管理器查看authserver.exeworldserver.exe的CPU、内存、网络占用。
  • Linux:使用tophtop命令查看进程资源使用情况。使用netstat -an | grep :8085(或其他服务端口) 查看网络连接数。

优化方向:

  • worldserver.conf中调整UpdateUptimeInterval,GridCleanUpDelay等世界更新频率参数。
  • 优化MySQL配置,增加缓冲区大小。
  • 使用更快的存储(SSD)存放数据库和地图文件。

8. 常见问题与排查方法

问题现象可能原因排查方式解决方案
CMake 失败,找不到 OpenSSLOpenSSL 未安装或路径未正确指定。检查CMake错误信息。Windows:确保-DOPENSSL_ROOT_DIR指向正确的安装目录。Linux:确保已安装libssl-dev
编译时出现大量错误源码版本、依赖库版本或编译器版本不兼容。查看第一个报错信息。确保完全按照官方Wiki的指南操作,使用推荐的稳定版本组合(如特定版本的VS、CMake、Boost)。
数据库连接失败worldserver.conf中的数据库连接信息错误;MySQL服务未启动;用户权限不足。查看worldserver启动日志。1. 核对配置中的IP、端口、用户名、密码、数据库名。
2. 确保MySQL服务正在运行 (sudo systemctl status mysql)。
3. 确认数据库用户有远程或本地连接权限。
worldserver启动时卡在“Loading DB2 storage...”或地图数据DBC或地图文件缺失、路径错误或版本不匹配。检查日志中加载文件的路径。1. 确认dbc,maps等文件夹已正确放置在worldserver同级目录。
2. 确认这些文件是从对应版本的客户端提取的。
客户端无法连接,显示“已断开连接”认证服务器 (authserver) 未运行;客户端版本号不匹配;防火墙阻止。1. 确认authserver进程在运行并监听3724端口。
2. 对比服务器和客户端版本号。
1. 先启动authserver
2. 修改worldserver.conf中的Game.Build.Version
3. 检查防火墙是否放行了3724(认证)和8085(世界)等端口。
游戏内延迟高或卡顿服务器所在机器性能不足;数据库查询慢;网络问题。观察服务器进程的CPU/内存占用。在游戏内使用.server info命令查看性能数据。1. 减少worldserver.conf中的PlayerLimit
2. 优化数据库,为常用查询字段建立索引。
3. 确保服务器在性能较好的机器上运行。
GM命令无效账号权限等级不够;命令拼写错误;命令在当前上下文不可用。worldserver控制台使用account onlinelist查看账号权限。1. 使用account set gmlevel 账号 等级 -1提升权限(3级为管理员)。
2. 使用.help查看命令列表和正确格式。

9. 最佳实践与使用建议

  1. 版本管理:使用git切换到特定的稳定分支(如master)进行学习,而不是最新的开发分支,以避免不稳定的代码。
  2. 目录规划:建立清晰的工作目录。例如:
    /TrinityDev/ /source/ # 存放克隆的源码 /build/ # 编译目录 /server/ # 运行目录,存放配置文件、数据文件和可执行文件 /client/ # 合法的游戏客户端
  3. 数据库备份:在对数据库进行任何重大修改(如导入TDB、运行自定义脚本)前,务必使用mysqldump工具备份auth,characters,world数据库。
  4. 增量学习:不要试图一下子理解整个代码库。从一个小功能点入手,比如“一个火球术伤害是如何计算的”,通过日志、断点调试(GDB或VS),追踪代码调用栈。
  5. 善用工具
    • 调试器:VS Debugger 或 GDB 是理解代码执行流程的神器。
    • 代码搜索:在源码目录下使用grep -r “SpellDamage” .来搜索相关代码。
    • 文档与社区:TrinityCore 的 官方Wiki 和 GitHub Issues 是解决问题的宝库。
  6. 合规与道德:始终牢记这是学习工具。不要尝试破解、修改客户端,或搭建公开服务器侵害版权。你的学习成果应该是深入理解的C++工程能力和服务器架构知识,而不是一个可游玩的私服。

10. 总结与下一步

TrinityCore 作为一个开源的大型C++项目,其价值远超一个“游戏服务器”。它为你打开了一扇门,让你能直接审视一个工业级、高并发、状态复杂的服务端系统是如何构建的。

最值得尝试的点

  • 编译成功并启动服务:这是第一步,也是验证你开发环境是否正确的关键。
  • 追踪一个简单游戏事件:比如,在代码中找到玩家发送聊天消息的处理函数,并添加一行日志,看是否能在控制台输出。这能帮你建立源码与游戏行为的直接联系。
  • 修改一个简单的游戏规则:比如,将所有的经验值获取改为双倍。这需要你找到经验计算相关的代码并修改。

最容易踩的坑

  • 环境配置:OpenSSL、Boost、MySQL客户端库的版本和路径问题是最常见的拦路虎。严格按照官方指南操作。
  • 数据库配置:连接信息错误、忘记导入TDB数据,会导致世界空空如也。
  • 客户端兼容性:服务器版本和客户端版本必须匹配,否则无法连接。

后续方向

  1. 深入核心系统:研究Map,Grid,Cell系统如何管理游戏世界;Battleground(战场)和Instance(副本)的加载与管理机制。
  2. 研究网络层:分析WorldSessionAuthSession如何处理客户端数据包,协议是如何序列化和反序列化的。
  3. 研究脚本系统:学习如何使用SmartAIEluna为生物编写更复杂的AI行为。
  4. 性能分析与优化:学习使用性能分析工具,找出服务器在大负载下的瓶颈。

将 TrinityCore 作为一个严肃的C++项目来研究和学习,你收获的将不仅仅是关于一款游戏的知识,更是应对复杂软件系统的分析、调试和开发能力。建议收藏本文,在搭建过程中遇到问题时,可对照第8节的排查清单逐一检查。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/4 12:51:44

5 分钟给 Node 应用加满安全响应头:从 0 到生产级

5 分钟给 Node 应用加满安全响应头&#xff1a;从 0 到生产级 【免费下载链接】nodebestpractices ✅ The Node.js best practices list (July 2026) 项目地址: https://gitcode.com/GitHub_Trending/no/nodebestpractices 登录页被 iframe 套壳&#xff1a;一次真实的安…

作者头像 李华
网站建设 2026/9/4 12:49:34

51单片机实现433MHz遥控信号通用解码与学习功能实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/4 12:49:10

BMS Simulink模型构建:从SOC估算到主动均衡的完整仿真实践

简介&#xff1a;本资源是一套面向电动汽车电池管理系统&#xff08;BMS&#xff09;研发与教学的完整Simulink建模实践方案&#xff0c;适用于高校电化学/车辆工程专业师生、BMS算法工程师及Matlab/Simulink进阶学习者&#xff0c;聚焦SOC高精度估计、主动均衡策略实现与系统级…

作者头像 李华
网站建设 2026/9/4 12:48:20

等离子体刻蚀技术原理、工艺开发与设备维护实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/4 12:48:07

单片机毕设选题推荐:基于多传感器融合的水体 PH - 浊度智能监测控制系统设计 基于 STM32 或 51 单片机的 LCD1602 水质参数显示与阈值报警系统(021506)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于嵌入式单片机&#xff0c;Java、小程序技术领域和毕业项目实战 ✌️…

作者头像 李华
网站建设 2026/9/4 12:48:06

WPS高级应用实战:从宏与插件到自动化办公流程设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华