旧工程最麻烦的地方是:
东西都在,但没人记得“为什么这样写”“哪里还在用”。
想接着开发或者二开,第一步就是把它系统化梳理一遍。

下面我按三个部分来讲:
1)资源怎么梳
2)代码怎么梳
3)协议怎么梳

中间会加一些我自己常用的小脚本和思路。


一、先梳理资源:目录、引用关系、冗余

1. 先搞清楚资源目录的“真实结构”

一般旧的 Cocos 工程资源目录大概这样:

res/
  ui/
  font/
  audio/
  anim/
  particles/
  config/

但实际情况是:

  • 有些目录已经废弃

  • 有些资源被移走但引用没改

  • 有些是早期测试残留

我建议第一步做的很简单:
把资源目录完整列一遍,并输出到一个文件里,后面好对比。

用个简单脚本:

# 把资源文件列出来存到 res_list.txt
find ./res -type f > res_list.txt

或者用 Python:

import os

with open("res_list.txt", "w", encoding="utf-8") as f:
    for root, dirs, files in os.walk("./res"):
        for name in files:
            path = os.path.join(root, name)
            f.write(path.replace("\\", "/") + "\n")

这一步听起来很简单,但后面排查“资源没用到”“引用路径错误”的时候非常有用。


2. 查资源是否真的被代码引用

旧工程常见问题:

  • 资源很多,但真正用到的只有一部分

  • 有些 UI 图是旧版本遗留

  • plist、json、音效等可能已经没人用

做法很直接:
一边扫描代码里的字符串引用,一边对比 res_list。

比如在 Cocos2d-js 里,资源引用很常见:

cc.spriteFrameCache.addSpriteFrames("res/ui/main_ui.plist");
cc.textureCache.addImage("res/bg/login_bg.png");
cc.audioEngine.playEffect("res/sound/click.mp3");

可以写个粗暴一点的脚本,把代码里的字符串全抓出来,对比是否存在对应文件。

示意脚本(简化版):

import os, re

code_paths = ["./src", "./res"]  # 代码可能散在 src / res/config 里
res_files = set()

# 统计资源文件
for root, dirs, files in os.walk("./res"):
    for name in files:
        res_files.add(os.path.join(root, name).replace("\\", "/"))

# 简单抓字符串(只做演示)
pattern = re.compile(r'"(res/[^"]+)"')

used_res = set()

for base in code_paths:
    for root, dirs, files in os.walk(base):
        for name in files:
            if not name.endswith((".js", ".json", ".plist", ".csd")):
                continue
            path = os.path.join(root, name)
            with open(path, "r", encoding="utf-8", errors="ignore") as f:
                text = f.read()
            for m in pattern.finditer(text):
                used_res.add(m.group(1))

unused_res = res_files - used_res

with open("unused_res.txt", "w", encoding="utf-8") as f:
    for p in sorted(unused_res):
        f.write(p + "\n")

作用就是:

  • 先统计所有 res 下的文件

  • 再从代码里抓出所有 "res/xxx" 的引用

  • 做个集合差集,得到**“疑似未使用资源列表”**

当然不是 100% 准(比如资源名拼接、通过表配置),
但能帮你找出一大批明显没用的东西。


3. 资源命名和分类顺手整理一下

既然已经在梳理了,可以顺带做两件事:

  1. 调整目录结构(不改名的前提下先理清层级)

    • ui 按模块拆:ui/login/ui/hall/ui/room/

    • 配置单独一个目录:res/config/

    • 公共资源单独放:res/common/

  2. 梳理图集与散图的关系
    看哪些 png 应该打到 plist 里,哪些散图其实已经在图集中重复了。

这一步做完,你对“资源这一块究竟有多乱”心里就有数了。


二、梳理代码:入口、模块、依赖关系

旧 Cocos 工程最普遍的问题:结构不清晰

1. 先找到项目真正的“入口链路”

一般 Cocos2d-js 工程入口大致是:

  • main.js

  • project.json / settings.js

  • AppDelegate.cpp(原生端)

你先看 main.js 里干了什么:

cc.game.onStart = function(){
    cc.view.adjustViewPort(true);
    cc.view.setDesignResolutionSize(1136, 640, cc.ResolutionPolicy.SHOW_ALL);
    cc.view.resizeWithBrowserSize(true);
    cc.LoaderScene.preload(g_resources, function () {
        cc.director.runScene(new LoginScene());
    }, this);
};
cc.game.run();

从这里你就能顺着找下去:

  • 第一个 scene 是谁

  • UI 层级是怎么搭的

  • Manager 之类的全局单例在哪里初始化

梳代码的顺序建议是:入口 → 全局管理类 → 核心逻辑模块

比如常见的几类:

  • XXXManager.js(UserManager、NetManager、UIManager…)

  • XXXScene.js(LoginScene、HallScene、GameScene…)

  • XXXLayer.js(各种界面层)

  • config/XXXConfig.js(配置类)

先做一张简单的“调用关系草图”就行,不用太精美:

main.js
  └── LoginScene
        ├── UI_LoginLayer
        ├── NetManager.login()
        └── ConfigManager.load()

这玩意儿画在纸上也行,关键是你要能一眼说出来:
“项目启动的完整流程是:加载资源 → 初始化配置 → 连接服务器 → 进大厅”。


2. 用简单工具看一下“代码引用图谱”

如果工程很大,单靠肉眼看会很痛苦。
我通常会至少做两件小事:

  1. 统计一下 src 目录下代码行数、文件分布

find ./src -name "*.js" | xargs wc -l > code_stat.txt

你能一眼看到:

  • 哪些文件超大(几千行那种)

  • 哪个目录最大(重点模块在哪)

  1. 简单搜关键字看耦合情况

比如你怀疑 NetManager 到处被直接调用,可以 grep 一下:

grep -R "NetManager" ./src > net_ref.txt

多看几个典型 Manager 的引用次数,你就大概知道这套工程写得“散不散”。


3. 找出“配置驱动”的部分,和“写死”的部分

旧项目一般会有一堆这样的配置文件:

  • res/config/*.json

  • res/config/*.plist

  • res/config/*.csv(可能导出来的)

核心问题是:
哪些逻辑是被这些配置驱动的,哪些是直接写死在 JS 里的。

做法也不复杂:

  • 搜某个配置 key 在代码里出现多少次

  • 看 UI/玩法/功能是跟配置绑定还是写死

举个例子(示意):

// 配置驱动
var conf = GlobalConfig.get("room_list");
for (var i = 0; i < conf.length; i++) {
    this.addRoomItem(conf[i]);
}

// 写死
this.addRoomItem({id: 1, name: "初级场"});
this.addRoomItem({id: 2, name: "中级场"});
this.addRoomItem({id: 3, name: "高级场"});

如果你后面要做二开重构,这个阶段顺便做个标记:

  • 哪些地方是“可配置”的

  • 哪些是“写死不易改”的


三、梳理协议:消息 ID、结构、收发流程

很多人对旧工程最头疼的其实是协议,尤其是:

  • 文档不全

  • 服务端有人改过

  • 前端只是照着抄

1. 先把“协议相关的所有文件”搜出来

一般协议涉及几个地方:

  1. 协议常量定义(cmd、msgId)

  2. 消息结构(protobuf / json)

  3. 实际收发代码(NetManager / SocketManager)

你可以先搜一下几个关键词:

grep -R "send" ./src/Net* ./src/*Net* > send_log.txt
grep -R "onMessage" ./src/Net* ./src/*Net* > recv_log.txt
grep -R "CMD_" ./src > cmd_log.txt
grep -R "msgId" ./src > msgid_log.txt

目的就是先粗略把“和网络相关的代码”集中出来,方便统一看。


2. 建一个简单的“协议总表”

哪怕是旧工程,我也建议你建一个自己的协议表,就一个 xlsx / markdown 都可以,比如:

CMD / MsgId 方向(C2S/S2C) 功能模块 数据结构说明 备注
1001 C2S 登录 account, token 登录请求
1002 S2C 登录 result, userInfo 登录返回
2001 C2S 心跳 timestamp ping
2002 S2C 心跳 timestamp pong

然后你在看代码时,顺手往里补。

比如某个地方看到:

NetManager.send(1001, {
    account: acc,
    token: tk
});

你就往表里登记一条。

这件事看起来有点“体力活”,但后面你会很感谢当时的自己。


3. 看清楚“封包 / 解包流程”

老工程一般都会有一层网络封装,比如:

NetManager.send = function(cmd, body){
    var buf = Packet.encode(cmd, body);
    socket.send(buf);
};

socket.onmessage = function(event){
    var data = event.data;
    var msg = Packet.decode(data);
    NetManager.dispatch(msg.cmd, msg.body);
};

你需要重点搞清楚几个点:

  1. 包头结构:

    • cmd 占几个字节

    • length 怎么算

    • 是否有序列号 / 校验位

  2. 包体结构:

    • 是 json / protobuf / 自定义二进制

    • 有没压缩 / 加密

  3. 心跳机制:

    • 心跳间隔

    • 超时重连策略

简单示例(仅示意):

Packet.encode = function(cmd, body){
    var bodyStr = JSON.stringify(body);
    var bodyBuf = stringToUtf8(bodyStr);
    var totalLen = 4 + bodyBuf.length;
    var buf = new Uint8Array(totalLen);
    buf[0] = (cmd >> 8) & 0xff;
    buf[1] = cmd & 0xff;
    buf[2] = (bodyBuf.length >> 8) & 0xff;
    buf[3] = bodyBuf.length & 0xff;
    buf.set(bodyBuf, 4);
    return buf;
};

把这部分看明白之后,协议层基本就算摸清了。


4. 和服务端对一下,看看有没有“私自修改过”

很多旧项目的真实情况是:
服务端后来被人改过,但前端工程还是旧的。

典型症状:

  • 登录报错,但前端看不出原因

  • 某些消息收不到返回

  • 某些 cmd 改了业务含义

这里建议你做两件事:

  1. 抓一份真实线上数据(如果条件允许)
    用 tcpdump / wireshark / 或服务端日志,抓一下真实包头、包体格式。

  2. 写一个小测试客户端,只跑“网络 → 协议”这一块
    不带 UI,单纯连上去发登录 / 心跳 / 几个典型请求,看返回结构。

这样你至少可以确认:
“现在跑的这套前端协议定义,到底和服务端对不对得上。”


四、最后做一份自己的“工程地图”

资源、代码、协议三块都梳一遍后,建议你整理一份简单的“工程说明”,哪怕很简陋也没关系,内容大概包括:

  • 目录结构说明(哪些目录是核心)

  • 资源说明(图集、配置、音效大概怎么分类)

  • 启动流程(从 main.js 到第一个场景)

  • 网络流程(连接 → 登录 → 心跳 → 收发)

  • 协议总表位置(xlsx / markdown)

这份文件是给未来的你看的,半年后再打开工程,你起码还能很快接上手,不用重新挖一遍历史。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐