前天复习了下Python,目的如下:

  • 分析/cocos2dx项目根/tools/cocos-console/文件夹下的Python脚本
  • 整合TexturePacker至新的脚本之中,例如etcocos.py
  • 整合渠道分包apkpacker至新脚本之中

做这些主要是为了方便工作,提高效率。


环境说明

  • cocos2dx 3.0
  • OS X 10.9.4
  • Python 2.7

工具目录结构

贴上cocos-console文件夹下的文件结构:

1
cocos2d-console/
├── README.md
├── bin
│   ├── cocos
│   ├── cocos.bat
│   ├── cocos.py
│   ├── cocos2d.ini
│   ├── cocos_project.py
│   └── install.py
└── plugins
    ├── plugin_clean.py
    ├── plugin_dist.py
    ├── plugin_jscompile[+]
    ├── plugin_update.py
    ├── plugin_version.py
    ├── project_compile
    │   ├── __init__.py
    │   ├── build_android.py
    │   ├── build_web[+]
    │   ├── project_compile.py
    ├── project_deploy.py
    ├── project_new
    │   ├── __init__.py
    │   ├── env.json
    │   ├── project_new.py
    │   └── ui.py
    └── project_run
        ├── __init__.py
        ├── __init__.pyc
        ├── bin
        │   └── ios-sim
        └── project_run.py

由于对Python不太熟悉,所以找出了这些文件的Python的公共的类库:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# Python 公共类库
from Queue import *
from SimpleHTTPServer import SimpleHTTPRequestHandler
from argparse import ArgumentParser
from collections import OrderedDict
from contextlib import contextmanager
from core import create_platform_projects
from optparse import OptionParser
from queue import *
from tarfile import TarFile
from threading import Thread
from xml.dom import minidom

import BaseHTTPServer
import ConfigParser
import getopt
import httplib
import inspect
import json
import os
import platform
import re
import shutil
import subprocess
import sys
import threading
import time
import urllib
import webbrowser

# win32
import _winreg

# ui.py
# 这里是一个图形化界面
# 这里就不作分析啦
from Tkinter import *

from tkFileDialog import *
from tkMessageBox import *
from tkinter import *
from tkinter.filedialog import *
from tkinter.messagebox import *

```

## 工具分析

自然是先贴出入口函数啦:

```py
if __name__ == "__main__":
if not _check_python_version():
exit()

plugins_path = os.path.join(os.path.dirname(__file__), '..', 'plugins')
# 引入插件模块
sys.path.append(plugins_path)

if len(sys.argv) == 1 or sys.argv[1] in ('-h', '--help'):
help()

try:
# 解析可用插件,返回可用插件列表
# 主要是解析bin/cocos2d.in中的配置
# 这里主要是用到了ConfigParser
plugins = parse_plugins()
command = sys.argv[1]
argv = sys.argv[2:]

# 这里主要是run_plugin的实现
# 主要功能当然是运行相应插件
if command in plugins:
run_plugin(command, argv, plugins)
else:
if len(sys.argv) > 2:
command = sys.argv[1] + '_' + sys.argv[2]
argv = sys.argv[3:]
if command in plugins:
run_plugin(command, argv, plugins)
else:
# 一些错误处理
else:
# 一些错误处理

except Exception as e:
# 一些异常捕获处理

在讲run_plugin的实现之前,我觉得有必要说说CCPlugin

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#
# cocos-console的所有插件必须是CCPlugin的子类
#
class CCPlugin(object):

# 自然是运行命令
# 涉及到subprocess这个公共库
# 这个东西生成出来便是为了取代os.system等东西
# 10.01前写篇文章分析下一些Python的公共类库
def _run_cmd(self, command):
CMDRunner.run_cmd(command, self._verbose)

def _output_for(self, command):
return CMDRunner.output_for(command, self._verbose)

@staticmethod
def _log_path():
log_dir = os.path.expanduser("~/.cocos2d")
if not os.path.exists(log_dir):
os.mkdir(log_dir)
return os.path.join(log_dir, "cocos2d.log")

@staticmethod
def depends_on():
return None

# 返回插件的类型和名字
# 这两个方法必须实现
# 在parse_plugins中需要用到这两个字符串
@staticmethod
def plugin_category():
return ""

@staticmethod
def plugin_name():
pass

@staticmethod
def brief_description(self):
pass

def __init__(self):
pass

def init(self, args):
self._verbose = (not args.quiet)
self._platforms = cocos_project.Platforms(self._project, args.platform)
if self._platforms.none_active():
self._platforms.select_one()

# 运行插件=。=
# 自然是插件的核心
# 所有子类必须实现该方法
def run(self, argv):
pass

def _add_custom_options(self, parser):
pass

def _check_custom_options(self, args):
pass

# 这里主要是Python中的argparse公共库中ArgumentParser的使用
# 感觉贴上来所有代码显得有点臃肿,所以这里就省去了这段代码
def parse_args(self, argv):
# 此处略去=。=

parse_plugins主要做了两件事情:

  1. 读取cocos2d.ini配置文件
  2. 根据配置文件,将插件加载到列表里面,做一些检查之后返回该列表

这里不贴上parse_plugins的代码,但是附上cocos2d.ini的主要内容:

1
2
3
4
5
6
[plugins]
project_new.CCPluginNew
project_compile.CCPluginCompile
project_run.CCPluginRun
project_deploy.CCPluginDeploy
plugin_jscompile.CCPluginJSCompile

现在,看了cocos2d.ini主要内容之后,再结合根目录下的目录结构和parse_plugins的实现。

可以知道cocos-console这个工具是通过插件的类型project,插件的名字new,和对应的类CCPluginNew做两种事情:

  1. 加载plugins/project_new__init__.py文件。
  2. 直接加载plugins的下的plugin_clean_.py文件。

若你只需要从CCPlugin继承过来,实现其接口,那就直接保存成一个文件。否则你需要新建一个同名文件夹,然后再文件夹下在加入一个__init__.py文件。这样做的目的主要还是保证插件的封装性。

至于这个__init__.py文件,就很简单的引入CCPluginXXXXX

1
from project_new import CCPluginNew

总结

若要在cocos-console下自定义一个新的插件只需做两件事:

  1. plugin文件夹下按照要求实现你所需要的功能
  2. cocos2d.ini中加入你插件的配置信息

接着就可以欢快的使用自己的插件啦~~~~


xxhash

xxhash – Android防重编译