分类 技术 下的文章

class Graph():#定义类
    nodes=list()
    edges=dict()#属性,分别创建空列表和字典并赋值
    def insert(self, a, b):
        if not(a in self.nodes):
            self.nodes.append(a)
            self.edges[a]=list()
        if not(b in self.nodes):
            self.nodes.append(b)
            self.edges[b]=list()
        #如果节点列表没有该节点则存入节点,并在字典中为其对应一个列表
        self.edges[a].append(b)
        self.edges[b].append(a)
        #为字典里节点对应列表存入相邻节点

with open('graph.txt','r') as f:
    txt = f.readlines()
f.close()
#打开文件按行读取并存入列表txt中,随手关门

graph=Graph()
for line in txt:
    a,b=line.split()
    graph.insert(a,b)
#对txt的元素进行遍历,将'a b'以空格为分隔符切开成a和b,再传入类的函数形成邻接字典

with open('result.txt','w') as f:
    f.close()
#只写打开文件再关闭,以此来清空文件内容

def printf(path):
    with open('result.txt','a') as f:
        for i in path:
            if (i == path[-1]):
                print(i, file=f)
            else:
                print(i, end="->", file=f)
    f.close()
#打印路径的函数,每次输出列表函数用箭头间隔,加入判断在最后一个元素输出时不加箭头

def findAllPath(graph, start, end, path=[]):
#定义寻找路径的函数
    path.append(start)
#将开始节点存入路径
    if start == end:
#递归的终止条件
        printf(path)
#抵达终点,打印路径
        path.pop()
#将最新进入的元素弹出栈
        return
#返回,不再执行剩下的语句

    for node in graph[start]:
#遍历开始节点的所有相邻节点
        if node not in path:
#同时这个节点不在路径上
            findAllPath(graph, node, end, path)
#递归调用函数,使该相邻节点做开始节点找路径
    path.pop()
#循环结束后,所有的相邻节点都遍历过一遍,该开始节点弹出

start=input("start:")
end=input("end:")
findAllPath(graph.edges,start,end)
#传入起点和终点,调用函数

前言

因为有放上一个看板娘的需要,我从某鸽子画师那里借来了一个live2d的cmoc3文件。由于cmoc3文件不能直接在网页上放出来,并且像网络上的插件都或多或少有些瑕疵,不满足需要。当然,如果只是一般的需求,则网络上的插件基本能实现了,但由于本人强迫症,对于不显示表情、动作表现不全、没有随即加载动作、定位不准、模糊等瑕疵很在意,于是便有了这几天的折腾过程。
由于本篇并非一步到位法,而是属于自我折腾范畴,故仅限于闲的没事的来报错。
本篇折腾过程全部基于live2d2.0,如果想要寻找关于live2d3.0的教程可以移步至参考资料。


文件结构

在进行魔改之前,我们先认清一个放在网页上的一般模型的文件结构。
参阅Live2DViewerEX的例子(这是个跨平台动态壁纸解决方案,与我们需要用的不同):live2d配置例子
最基本的只含有moc文件和材质文件,贴图格式是png。moc文件相当于提供骨架和其它数据,而表现出来还要联系材质文件。同一人物,相同动作的换装也是依靠切换材质文件。当然,如果只是最基本的模型的话,没有动作的话,太显得单调了。因此将最基本的模型通过软件稍稍处理,就会得到下面的例子,含动作文件夹motions:

model.json //对模型各种文件的关系配置,即引用关系。
model.moc//3d骨架,格式是moc(live2d2.0)。
physics.json//物理效果,比如头发随动作的摆动。
pose.json//部件置换的姿势效果。
textures //文件夹,存放材质文件,往3d骨架上贴的,有时候一个模型加载需要几个材质文件。

a.png
b.png
...

motions //文件夹,存放mtn动作文件,这些动作由于json中的引用,会在不同的事件中表现出来。

jump.mtn
dance.mtn
...

expressions //文件夹,命名各异,存放表情文件,但是在部分插件表情文件会被忽略。

f00.exp.json
f01.exp.json
···

sound //文件夹,存放声音文件,可以在点击事件中引用。

normal_01.mp3
normal_02.mp3

出于多种原因,绝大部分制作师发布时只会发布导出后的模型文件(moc或moc3)。如果获得源文件(cmox或cmo3),就能通过软件自定义一些动作和表情,同时也能轻松地解决点击事件的区域问题,这一点接下来会说明。
当然,具体的命名方式要依情况而定。比如有些插件规定要将配置文件命名为index.json;又比如有些插件规定要将moc文件命名为name.model.moc,这个时候就要编辑配置文件,更改一下相关的路径。因此,接下来介绍模型设置model.json。
这是一个扒自OkYes个人博客的看板娘的例子。原因是他上次嘲笑我看板娘错位了。

{
    "version":"Sample 1.0.0",
    "model":"seifuku.moc",
    "textures":[
        "seifuku.1024/L2DMSR_U_00.png",
        "seifuku.1024/L2DMSR_U_01.png",
        "seifuku.1024/L2DMSR_U_02.png"
    ],
    "lip_sync": "false",
    "layout": {
        "center_x":0.0,
        "center_y":-0.05,
        "width":2.0
    },
    "hit_areas_custom":{
        "head_x":[-0.3, 1.12],
        "head_y":[0.26, 0.56],
        "body_x":[-0.41, 0.58],
        "body_y":[0.46, -1.12]
    },
    "motions":{
        "flick_head":[
            {
                "file":"seifuku.motions/motion1.mtn"
            },
            {
                "file":"seifuku.motions/motion10.mtn"
            },
            {
                "file":"seifuku.motions/motion11.mtn"
            },
            {
                "file":"seifuku.motions/motion12.mtn"
            },
            {
                "file":"seifuku.motions/motion2.mtn"
            },
            {
                "file":"seifuku.motions/motion4.mtn"
            },
            {
                "file":"seifuku.motions/motion5.mtn"
            },
            {
                "file":"seifuku.motions/motion6.mtn"
            },
            {
                "file":"seifuku.motions/motion7.mtn"
            },
            {
                "file":"seifuku.motions/motion8.mtn"
            }
        ],
        "tap_body":[
            {
                "file":"seifuku.motions/motion1.mtn"
            },
            {
                "file":"seifuku.motions/motion10.mtn"
            },
            {
                "file":"seifuku.motions/motion11.mtn"
            },
            {
                "file":"seifuku.motions/motion12.mtn"
            },
            {
                "file":"seifuku.motions/motion2.mtn"
            },
            {
                "file":"seifuku.motions/motion4.mtn"
            },
            {
                "file":"seifuku.motions/motion5.mtn"
            },
            {
                "file":"seifuku.motions/motion6.mtn"
            },
            {
                "file":"seifuku.motions/motion7.mtn"
            },
            {
                "file":"seifuku.motions/motion8.mtn"
            }
        ],
        "talk":[
            {
                "file":"talk/DK_NOZOMU_0041.mtn"
            },
            {
                "file":"talk/DK_NOZOMU_0061.mtn"
            },
            {
                "file":"talk/DK_NOZOMU_0067.mtn"
            }
        ],
        "idle":[
            {
                "file":"seifuku.motions/motion3.mtn"
            },
            {
                "file":"seifuku.motions/motion9.mtn"
            }
        ]
    },
    "expressions":[
        {"name":"f01.exp.json","file":"expressions/f01.exp.json"},
        {"name":"f02.exp.json","file":"expressions/f02.exp.json"},
        {"name":"f03.exp.json","file":"expressions/f03.exp.json"},
        {"name":"f04.exp.json","file":"expressions/f04.exp.json"},
        {"name":"f05.exp.json","file":"expressions/f05.exp.json"},
        {"name":"f06.exp.json","file":"expressions/f06.exp.json"},
        {"name":"f07.exp.json","file":"expressions/f07.exp.json"},
        {"name":"f08.exp.json","file":"expressions/f08.exp.json"}
    ],
    "physics":"physics.json",
    "pose":"seifuku.pose.json"
}

关键的参数有以下几个:

路径(model&textures&expressions&physics&pose):

依次为相应文件对应的路径。

激活自动对口型功能(lip_sync):

在这里用不上的东西,可以直接删去。

布局(layout):

layout的center_x字段和center_y字段用于偏移显示模型,日后若有显示错位可以修改此处的值。width定义缩放。

自定义HIT_AREA的方法(hit_areas_custom):

此处是Jad大佬用来解决问题而自定义的方法,如果你使用的插件是基于Jad大佬提供的js修改的版本,这个参数就能实现接下来的功能。但是接下来因我要从live2d-widget.js引用,这个参数将无意义。
用来设置头部和身体的点击区域,设置过后就能确定头部和身体在的位置,配置motions点击过后做出相应的动作和声音。头身体都是正方形区域,head_x是头左上角定点坐标,head_y是头部右下角定点坐标,身体和头相同。

怎么获取坐标?
在live2d.js中搜索DEBUG_MOUSE_LOG,将值改为1,这样控制台就会显示你点击的坐标值,这样就可以设置了。

触发区域名(hit_areas):

官方的web只定义了头部和身体的点击区域。其中id为制作模型时定义的区域id值,如下所示,可以自动地定义点击区域。
如果你没有源文件的话,就不知道id,只能通过上面的参数来手动设置区域。

"hit_areas": [
        {
            "name": "head",
            "id": "D_PSD.55"
        },
        {
            "name": "body",
            "id": "D_PSD.16"
        }
    ]

如何获取部件ID?
在拥有源文件的前提下,在Cubism 3 Editor中打开源文件,点击相应部件,在左下角窗口的属性中,即可查看部件ID。
【图】

动作(motion):

根据我接下来要进行接头霸王的而引用的js文件中显示:
可配置的只有这几个:"idle","sleepy","tap_body","flick_head","shake"。
依次对应为“待机时动作”、“闲置时动作”、“点击body时动作”、“点击head时动作”、“摇动时动作(限支持重力感应功能的设备使用)”。
尽管如此,有些动作,由于不同插件的定义问题,是不显示的。通常会在网页live2d上显示的的动作有"idle","tap_body","flick_head"。而我需要显示的也只是这几个动作,因此足够了。当然,由于版本问题,存在更多的动作,根据js内容可能会显示,比如其中的"talk"(对话)。
在关键词其后面的参数file是动作文件路径,依据实际情况来更改,是必须指明的。
除此之外,关键词后的参数还可以包含"pinch_in","pinch_out","sound",依次对应为“淡入”、“淡出”、“声音文件路径”。

将源文件转换成我们所需要的文件

在获得鸽子画师提供的源文件(cmo3)后,如果想要将之放在网页上,还需要一些必经的处理。
接下来会使用的工具有:Cubism 3 EditorLive2D Viewer

将模型格式由v3转v2

准备工作

cmo3是v3格式的模型文件,但是我们此次基于live2d2.0,因此选择将模型文件由v3转为v2。
我们进入Cubism 3 Editor,打开cmo3文件。因为模型材质图的分辨率高达8192px,因此我们只能使用专业版来操作。不过专业版有42天的试用时间,试用期间功能与正常版本无异,足够满足暂时的需求了。这里我们采用另外一个模型来演示。

如果42天后仍想白嫖,可移步至参考资料查看方法(不建议)。

【图】

删除和修改部件

如上图所示,如果要把天依放在网页上,有一些部件是不需要的,有两种方法来解决。
一是将目标区域的材质图修改为透明,那么在显示时自然就会消失;
二是删除目标区域部分的模型。为了减少模型文件大小和减轻运算量,推荐使用第二种方法。当然第一种方法并不是不可以,在无法接触到模型的源文件时,这也是唯一的方法。
在主界面内点击想要删除的部件,出现红框即代表此部件被选中,然后按下Del键删除。
或者在左下角的菜单中,选中三个背景,按下Del键删除,更加简单利索。如图所示。
【图】
如果想对显示结果中的部分区域做修改,可以选择导出材质图,用图像处理软件进行修改注意不要对材质图进行任何的移动或裁剪。之后再将材质图导入软件中即可(也可以在导出后的textures文件夹中直接修改)。
如果想进行更加精细的操作,可以在建模-纹理-编辑纹理中实现。如修改分辨率来降低文件大小(同时这样也避免了高分辨率需要专业版进行编辑的尴尬),如将无用纹理删除。如下面两张图演示。
【图】
【图】

更改尺寸

现在我们看到,天依处于画面右方,且多出来许多空白画面,会影响到看板娘的显示。因此我们需要更改尺寸和裁剪。
如果觉得天依太大了,可以在文件-模型尺寸中按比例缩小。这里我设置为50%。
为了裁剪画布多余的空白区域,如下图所示,在文件-画布设置中,
【图】
我们设置画布的大小。注意选择区域。这里因为缩小后天依处在靠画布正上方的位置,我们需要先将画布从正上方裁剪。我给定的数值裁剪效果会不好,之后再重复步骤,直到天依显示在画面正中央且没有过多多于画布即可。
【图】
想要看看此时模型的实际大小,可以点击下方的1:1按钮显示原始尺寸。当然,裁剪之后我们应该点击产生随机动作,来检查模型做动作时是否会超出画布。之后在从建模-参数-恢复默认设置中恢复默认姿态。
【图】

转换部件ID

由于v3格式与v2的部位ID不同,直接导出的话会出现不跟随鼠标动作等问题,需要把v3格式的部位ID转为v2格式,编辑器已经包含了这个功能:
在主窗口中依次点击建模-转换模型ID打开ID转换窗口。保持默认,点击OK即可。
【图】

解决小问题

再进行最后一步的导出工作前,我们来检查一下不同版本到底产生了哪些问题,并尽量改过来。以下是我遇到的问题和解决方案。

天依的闭眼和睁眼反了
从上方的演示图以及在开启随机动作后不难发现,天依的闭眼和睁眼动作反了过来。为了防止误操作,我们可以点击坐上方两个按钮,锁定绘画部件和变形器。之后,在左下角窗口参数中找到控制睁眼闭眼的参数。点击参数后面的数据,在接下来显示的列表中先选择参数,再点击反转即可。
【图】
鸽子画师的模型脸整没了
这里是不透明度和绘图顺序的问题。找出遮住脸的黑幕,原来是后发部分。如果设置完全透明的话,后发会消失。因此我们改变其绘图顺序,将之放在脸这一图层的下方即可。
【图】

导出模型

经过测试后,如果一切基本上没有问题了,则导出模型。在文件-导出嵌入式数据-导出moc文件(2.1用)导出。导出的文件应该包含textures文件夹、moc文件和model.json配置文件。
同时,为了接下来的工作需要,我们还通过文件-保存为2.1所用模型(cmox),另存一个2.1版本的源文件。
在导出模型时,可以根据需要选择分辨率。在网页上显示的话,我才用1024px就足够了。
【图】

增加动作

导出后的模型,理论上已经可以在插件中使用了,但是因为缺乏动作、表情、物理效果等文件,会呆呆地站在那里。在这一步中,我们为其加入动作。

如果已经有动作文件(can3)

在打开了模型的前提下打开动作文件。画布尺寸没有必要调。
在窗口左侧的场景中可以看到总共录了一个动作,名称为“= =”。
【图】
同时和上面所说一样,这里也出现了闭眼睁眼反了的毛病。我们展开下方的Live2D参数,找准控制睁闭眼的参数对应的几个关键帧,将参数移至睁眼。
【图】
整理点小问题后,接下来选择文件-导出嵌入式数据-导出动作数据,根据不同需要进行调整,注意勾选导出为2.1格式(mtn)。因为只有一个场景,所以我只导出了选中场景。为了应对在后期测试时发现动作有问题的情况,建议在文件-另存为中将修改后的动作另存为can3。
【图】

如果没有动作文件(can3)

没有动作文件的话,我们需要自己录制。在Cubism 3 Editor中,点击右下角的录制,便可自行设计动作。具体方法可以参照官网的说明。最后将动作导出为2.1格式(mtn)。

增加表情

因为兼容性问题,我们用2.1的办法来增加表情和物理效果。
打开Live2D Viewer,引入2.1格式的源文件。如图所示,已经给出了一些例子,另外基本的表情参数也能在官网上找到。在设置时自行调试就行。当然,局限于模型的精细度,一些参数没用上的话,例子也可能并不奏效。
在鼠标按右键保存后,需要更改格式为json。
【图】

增加物理效果

和上一步一样,软件已经给出了头发的物理效果模型。加入即可。之后可以在窗口右边观察更改后模型的情况。

将模型组装起来

根据之前对json的介绍,我们来依样画葫芦。在之前导出模型的操作中,我们已经得到一个json文件,现在用文本编辑器编辑。
将原来的内容:

{
    "type": "Live2D Model Setting",
    "name": "Model[洛天依]",
    "model": "Model[洛天依].moc",
    "textures": [
        "Model[洛天依].1024/texture_00.png"
    ]
}

考虑到尽量避免中文命名和相关的需求,进行相应地修改:

{
    "type": "Live2D Model Setting",
    "name": "luotianyi",
    "model": "model.moc",
    "textures": [
        "textures/texture_00.png"
    ],
    "layout": {
        "center_x":0.0,
        "center_y":-0.05,
        "width":2.0
    },
    "hit_areas":[
        {"name":"head","id":"D_PSD_01"},
        {"name":"body","id":"D_PSD_17"}
    ],
    "motions":{
        "idle":[
            {
                "file":"motions/abaaba.mtn"
            }
        ],
        "flick_head":[
            {
                "file":"motions/= =.mtn"
            }
        ]
    },
    "expressions":[
        {"name":"zhengyan.json","file":"expressions/zhengyan.json"},
        {"name":"biyan.json","file":"expressions/biyan.json"}
    ],
    "physics":"physics.json"
}

此时,模型的文件结构如下:

expressions

zhengyan.json
biyan.json

motions

= =.mtn
abaaba.mtn

textures

texture_00.png

model.json
model.moc
physics.json

进行模型的检查

此时可以在本地服务器上放上看板娘,来检查有无问题。这里选择直接使用保罗大佬的Pio插件来检查。
【图】
显示模型没有问题。
而这时,通过这个插件会出现一些麻烦。
其一,控制台报错:

l2d.js:1 Uncaught TypeError: Cannot read property '0' of undefined
    at o.r.hitTestSimpleCustom (l2d.js:1)
    at o.hitTestCustom (l2d.js:1)
    at o.tapEvent (l2d.js:1)
    at p (l2d.js:1)
    at g (l2d.js:1)

这个是因为我们没有写上hit_areas_custom属性,也因此导致了点击事件没有识别区域,故点击事件全部木大的效果。如果要使用这个插件,有关解决方法在此:看板娘插件文档
其二,表情不加载,需要修改l2d.js来解决。
其三,在缩放中定位出现偏差:即使填写了hit_areas_custom属性,但在拥有源文件的情况下如此这般一则定位可能不准,二则该插件在手机上干脆取消了点击事件。
其四,鸽子画师总是喜欢哔哔赖赖,说自己的模型十分高清,显示出来却一片模糊,岂可修。
如果你使用另一个版本的话,则可以解决第一个和第四个问题,但在解决第四个问题的同时会使得第三个问题更加严重。因此,由于特殊需要,我决定进行缝合,寻找万恶之源的衍生万恶之源

将看板娘放在网页上

引入脚本

无论是保罗大佬的插件还是FGHRSH的一条龙服务,都不能满足鸽子画师和我的需求,因此我找到了上文所说的万恶之源。
百度上有很多关于这个看板娘的教程,但都是告诉添加L2Dwidget.min.js这个脚本,然后使用。关于 L2Dwidget.min.js 这个脚本的源码怎么来的,却没有说明。以至于一开始我这个菜鸟直接下载万恶之源却发现用不了,以为是万恶之源遗漏了L2Dwidget.min.js文件,以至于去其演示页F12偷取,真是贻笑大方。
在此之前,应该准备些什么?在本地或云服务器上安装nodeJs以及cnpm,才能进行编译操作,这一部分的详细情况在参考资料中。
之后,将项目git下来(感谢@叉鸡临时给我补习我Linux的操作)。L2Dwidget.min.js脚本是需要编译生成的。

根据需求进行修改

刚Git下来的目录,是没有 lib和 node_modules目录的。
【图】
接下来我们安装依赖和编译项目,在当前目录打开命令窗口,输入如下命令:

cnpm install

这一步安装依赖和编译项目后,若成功,node_modules目录就生成了。之后,我们执行脚本,编译项目:

cnpm run build:dev

成功后,将生成lib目录,其中的L2Dwidget.min.js和L2Dwidget.0.min.js脚本成功生成。
不过在cnpm run build:dev 运行后,一直不退到输入界面,在成功后需要直接关闭。
当一切看起来完美无缺时,我们按照步骤在网页上插入以下部分:

  <script src="lib/L2Dwidget.min.js"></script>
  <script type="text/javascript">
    L2Dwidget.init();
  </script>

这个时候加载出的是默认配置,可以通过src/config/defaultConfig.js查看到:

  const defaultConfig = {
  model: {
    jsonPath: 'https://unpkg.com/live2d-widget-model-shizuku@latest/assets/shizuku.model.json',
    scale: 1,
  },
  display: {
    superSample: 2,
    width: 200,
    height: 400,
    position: 'right',
    hOffset: 0,
    vOffset: -20,
  },
  mobile: {
    show: true,
    scale: 0.8,
    motion: true,
  },
  name: {
    canvas: 'live2dcanvas',
    div: 'live2d-widget',
  },
  react: {
    opacity: 1,
  },
  dev: {
    border: false
  },
  dialog: {
    enable: false,
    script: null
  }
}

同时,可以定义的部分在src/index.js文件中也有注释。具体的解释请参考官方文档
在引入的时候,为了显示出我需要的模型,需要更改一下模型配置文件的路径:

L2Dwidget.init({
    "model": {
        "jsonPath": "www.example.com/name/model.json"
    }//省略了别的参数,省略部分将加载默认配置
});

当一切准备就绪后,在网页上显示出了人物模型,定位问题也完美的解决了,也通过定义超采样等级使模型清晰起来。但是遗憾的是,并没有满足需求。虽然能够切换表情了,但是冒出了一些更奇怪的问题。比如点击头部只会发生切换表情的事件,再比如多个动作时每次加载只会执行其中一个动作,除非刷新页面等。另外叉鸡还很不稀罕自带的对话框,始终想着FGHRSH大佬的对话框,又美观、功能又多,因此还要继续做修改。

随机的动作

修改cModel.js的第369行开始的if语句:

if (this.motions[name] == null)
{
    this.loadMotion(name, this.modelHomeDir + motionName, function(mtn) {
        motion = mtn;

        thisRef.setFadeInFadeOut(name, no, priority, motion);

    });
}
else
{
    motion = this.motions[name];


    thisRef.setFadeInFadeOut(name, no, priority, motion);
}

修改成:

if (this.motions[motionName] == null)
{
    this.loadMotion(motionName, this.modelHomeDir + motionName, function(mtn) {
        motion = mtn;

        thisRef.setFadeInFadeOut(name, no, priority, motion);

    });
}
else
{
    motion = this.motions[motionName];


    thisRef.setFadeInFadeOut(name, no, priority, motion);
}

切换表情

我的需求是点击头部的时候会切换表情,也会反应点击事件,因此修改cManager.js的第89行:

this.models[i].setRandomExpression();

改成:

this.models[i].setRandomExpression();
this.models[i].startRandomMotion(cDefine.MOTION_GROUP_FLICK_HEAD,
        cDefine.PRIORITY_NORMAL);

如果将思路拓展开来,其它的需求也能通过类似的方法满足。

编译

当我们将所要做的修改工作完成后,再次编译。

cnpm run build:dev

此后新的js文件将替换成原文件。在清除缓存后,这两个问题就能解决,基本满足了需求。可谓舍近求远、南辕北辙、绕道前行的大成功。

将对话框缝合

如果你不需要缝合对话框,到此处的配置便已经满足需求了,只需要在L2Dwidget.init();中修改配置,就能轻松地达成效果。

样式问题和亲爱的F12

简化并引用

引用高清涩图和路径问题

测试效果和评估完成度

参考资料

搜索页显示文章数量

说明:显示当前分类下或者搜索结果的文章数量。getTotal()方法在Typecho的/var/Widget/Archive.php

<?php echo '共'.$this->getTotal().'篇';?>

搜索结果页搜索框显示关键字

说明:判断搜索框所在页面是否是搜索页,是则输出搜索的关键字。<?php $this->archiveTitle(' » ', '', ''); ?>处理当前页标题。

<input type="text" id="s" name="s" class="text" <?php if($this->is('search')): ?> value="<?php $this->archiveTitle(' &raquo; ', '', ''); ?>"<?php endif; ?> />

参考资料

[1]主机迷
[2]一极乐

说明:新建归档页面,按年输出所有文章,并显示该年份下总文章数。
演示:归档

  <?php
    Typecho_Widget::widget('Widget_Contents_Post_Recent', 'pageSize='.
    Typecho_Widget::widget('Widget_Stat')->publishedPostsNum)->to($archives);
    $date_y=0;$date_m=0;$output = '';$huan=0;
    while($archives->next()){
      $date_t = explode(",", date('Y,m,d', $archives->created));
      if($date_y > $date_t[0]){
        $date_m  = 0;
        $article_nums[] = $article_num;
        $output .= '</ul></li></ul>';
      }
      if($date_y != $date_t[0]){
        $date_y  = $date_t[0];$article_num=0;
        $article_flag[] = $tmp_flag = 'archives_'.$huan++;
        $output .= '<h2>'.$date_y.' <span>×'. $tmp_flag .'</span></h2><ul>';
      }
      $output .= '<li><time>'.$date_t[1].'.'.$date_t[2].'</time> <a href="'.$archives->permalink.'">'.$archives->title.'</a> <sup><a href="'.$archives->permalink.'#comment">'.$archives->commentsNum.'</a></sup></li>';
      $article_num++;
    }
    $article_nums[] = $article_num;
    $output .= '</ul></li></ul>';
    echo str_replace($article_flag, $article_nums, $output);
  ?>

首先,火山鸽的DreamCat就像是一个病危的年青人一样,虽然发展潜力可能很大,但是现在只能躺在病床上半死不活地打吊针,严重耽误了我的外交活动。虽然我几次督促废物火山鸽进行起码地整活,但火山鸽最近沉迷于吃鸡无法自拔,因而如果想让DreamCat在目前版本能勉强使用的话,作为一个只会东拼西凑的人不得已地被迫参考网上众多大神的记录进行如下修改。这篇文章主要记录了对火山鸽DreamCat模板的整活手术过程。

  • DreamCat版本:X1.3-200331
  • 操作所需技术水准:0
  • DreamCat下载地址:Github

我来写代码了

1.侧边栏不显示独立页面问题

由于火山鸽鸽了,侧边栏没有显示独立页面。这就像是长了一只手却没有手掌一样,非常火山。必要地,需要显示独立页面。

<!-- 页面 -->
        <div class="mdui-collapse-item  mdui-collapse-item-dense">
                <div class="mdui-collapse-item-header mdui-list-item">
                        <i class="mdui-list-item-icon mdui-icon material-icons mdui-text-color-theme-text">layers</i>
                        <div class="mdui-list-item-content mdui-text-color-theme-text">页 面</div>
                        <i class="mdui-collapse-item-arrow mdui-list-item-icon mdui-icon material-icons mdui-ripple mdui-text-color-theme-text">keyboard_arrow_down</i>
                </div>
                <div class="mdui-collapse-item-body" style="">
                    <ul class="mdui-list mdui-list-dense" for="show-category-button">
                       <?php $this->widget('Widget_Contents_Page_List')->to($pages); ?>
                        <?php while ($pages->next()): ?>
                            <li class="mdui-list-item mdui-ripple">
                                <a href="<?php $pages->permalink(); ?>" class="mdui-list-item-content mdui-text-color-theme-text" title="<?php $pages->title(); ?>">
                                    <?php $pages->title(); ?>
                                </a>
                            </li>
                        <?php endwhile; ?>
                    </ul>
                </div>
            </div>

通过复制粘贴,将以上代码放进header.php侧边栏里你想要显示的地方即可。如此即可在侧边栏显示出独立页面。
效果:
效果图1

2.侧边栏默认显示非常火山

由于火山鸽的审美与我不一样,我觉得DreamCat的侧边栏默认是显示这一点非常火山。

<header>
    <div class="mdui-drawer mdui-color-grey-50 mdui-drawer-close" style="background: linear-gradient(135deg,#ECEFF1 0,#FAFAFA 60%);" id="main-drawer">
      <div class="mdui-list DreamCat-List-01" mdui-collapse="{accordion: true}" style="margin-bottom: 50%;">
            
      <div class="mdui-card DreamCat-List-02" style="overflow: inherit;">
        <div class="DreamCat-menu-bg" style="background: url(<?php $this->options->themeUrl('src/img/brand.jpg'); ?>);">
            <img class="DreamCat-List-headimg mdui-shadow-6" src="//q2.qlogo.cn/headimg_dl?dst_uin=<?php $this->author->mail();?>&spec=640">
              <div class="mdui-card-media-covered">
                <div class="mdui-card-primary">
                  <div class="DreamCat-menu-author font-weight: 400; mdui-valign"><?php $this->author(); ?></div>
                </div>
              </div>
        </div>
      </div>

通过复制粘贴,将以上代码替换掉header.php对应部分即可。如此即可默认隐藏侧边栏。不过,侧边栏直接调用了QQ头像,这点可能需要在之后的版本按需选择。就现在来讲,解决方案可以参照第7条所写。
效果:
效果图2

3.文章页在手机端浏览时上方留白过多

手机端浏览时,由于火山鸽写死了,文章页距离顶部太远了。

@media screen and (max-width: 760px){
.DreamCat-content-header {
    min-height: auto;
}
}

通过复制粘贴,将以上代码粘贴在post.php<style>间对应部分即可。如此即可将就着用了。
效果图3

4.文章页字数统计和最后编辑时间BUG

字数统计问题据称已经在最新版本得到解决。最后编辑时间仍然显示为发表时间,表明这项功能毫无作用。

function art_count ($cid){
$db=Typecho_Db::get ();
$rs=$db->fetchRow ($db->select ('table.contents.text')->from ('table.contents')->where ('table.contents.cid=?',$cid)->order ('table.contents.cid',Typecho_Db::SORT_ASC)->limit (1));
$text = preg_replace("/[^\x{4e00}-\x{9fa5}]/u", "", $rs['text']);
echo mb_strlen($text,'UTF-8');
}

通过复制粘贴,将以上代码替换掉functions.php对应部分即可。用以正确地显示文章字数。

<?php echo date('Y 年 m 月 d 日' , $this->modified); ?>

用以输出最后编辑文章的时间。替换掉functions.php对应部分即可。

5.根本没有写页面的问题

作为一个已经发布0.1版本的Typecho模板,火山鸽果然将页面部分直接鸽掉了。建议枪毙。
鉴于火山鸽的POST页面并没有调用分类、标签之类文章才有的代码,直接通过复制粘贴将修改过后的post.php粘贴到page.php即可。

6.评论栏没有对齐的问题

这个据称已经在最新版(但还没有发布,据称在5月3日发布)解决。故此处略去过程,建议直接下载最新版。

7.404页面侧边栏头像无法显示问题

同2,这个问题非常火山。直接调用QQ头像泄露QQ,不愧是你啊,火山。
在火山鸽还没写出设置来放头像的情况下,注意到DreamCat的外观设置还是照搬默认模板的,不妨:

<img class="DreamCat-List-headimg mdui-shadow-6" src="<?php $this->options->logoUrl() ?>">

复制以上代码替换掉header.php对应部分,然后在后台的外观设置中设置站点 LOGO 地址即可。其它但凡直接调用QQ头像的部分也可以这样替换掉。
这样就避免了直接调用QQ头像泄露QQ号,同时也解决了404页面侧边栏无法显示头像的问题,效果如下:
效果图4