一个新的可能

昨天,或者说今天早些时候,写完之前那篇博客之后,没想到竟然通了个宵。

主要在做的还是完整的看完了云风的两个系列文章,开发笔记 和 那些日子

这种感觉确实很久没有了啊,想起大学的时候,在期末考试前期,花了4天看完了Matrix67的所有博客。

终于,我也是到了可以左45°角望天长叹:“唉,大学的时候啊……”的年纪了。

看完到大概7点,囫囵睡了一觉,中午醒来去对面吃了个豆浆油条,哎,油条还是好吃。

回来就正式开始看网络编程部分。

系统性的方法还是很久以前就感觉如果还是要自己搞定网络部分,不得不看的《网络游戏核心技术与实战》,确实很少有这种针对游戏的网络编程书,日本人写的,粗看还是靠谱的。

看一看就深感自己还是实在欠缺,套接字通讯基本只有计算机网络课上学的一点概念而已。书上的代码是类似C的伪代码,于是我边看边用Python实现,接口当然是比较一致,但是具体的问题还是令人非常困扰,把底层完全搞懂看来还是需要花一大把精力和时间——正是我现在缺的。不得已还是用老办法,先搞清楚概念,然后硬怼一个上层方案来。

本来还是想先用Python的,原因前面也说了,但是突然灵光一闪,我其实还有另一个可行的选择。

.Net Core 2.0

前后端统一,跨平台,完美的语言,完美的IDE。

除了略微担心不好招人,主要还是这坑实在是太新了,新的技术一般都是理论上美好,实际上……要命的是这还是微软的新技术……又不是第一次坑了。(但是万一出问题还有后备方案可以用Mono应急……)

所以,继续验证方案。

程序员三大浪漫之一

我写博客吧,好像就正经不起来。总会夹杂点杂七杂八的东西。

先说正题吧。

所谓程序员三大浪漫嘛,编译原理,图形学,操作系统(不是我说的,逃

这次说的是图形学。

我好想有个坏毛病,发现个什么好玩的,自己其实根本不懂就喜欢拽着人乱说。

最过分的一次是表彰大会上大礼堂给全学院人讲信息安全(当时到底怎么想的简直不要脸

所以还是继续不要脸一次。

如果现在有人问我,怎样开始喜欢上编程,写点什么项目可以获得最大的成就感。答案肯定是写光线追踪。

唉,自己过去对图像以及显卡的了解真是太 Naive 了……简直等于什么都没有啊。

先上文

用 JavaScript 玩转计算机图形学(一)光线追踪入门

光线追踪的js实现,总共500行代码不到,循序渐进。

最神奇的地方在于,超简单的原理带来了超乎想象的效果。

如果有一点 3D 软件的使用经验和游戏开发经验的话,原理非常直白(当然还要懂点数学和物理,我这种渣水平就够)

但是效果实在是,出人意料。光看图感觉不到,自己敲完代码跑出来,太神奇了(或者是我太无知了 = =)

上图,为了帮助理解,自己改了 3x SSAA ,抗锯齿效果杠杠。

(下图分别是 1x,2x,3x, 反射都是3次追踪。为什么没有 4x ?因为 4x 跑了5分钟然后浏览器跪了……)

附上改的渣代码,确实就是 super-simpling 而已。

function rayTraceReflection(scene, camera, maxReflect) {

        scene.initialize();
        camera.initialize();

        var ssaa = 1; //抗锯齿等级
        var rawPixels = new Array();
        for (var i = 0; i < h * ssaa; i++) {
            rawPixels[i] = new Array();
        }

        for (var y = 0; y < h * ssaa; y++) {
            var sy = 1 - y / (h * ssaa);
            for (var x = 0; x < w * ssaa; x++) {
                var sx = x / (w * ssaa);
                var ray = camera.generateRay(sx, sy);
                rawPixels[y][x] = rayTraceRecursive(scene, ray, maxReflect);
            }
        }

        var i = 0;
        for (var y = 0; y < h * ssaa; y += ssaa) {
            for (var x = 0; x < w * ssaa; x += ssaa) {
                var color = Color.black;
                for (var yi = 0; yi < ssaa; yi++) {
                    for (var xi = 0; xi < ssaa; xi++) {
                        color = color.add(rawPixels[y + yi][x + xi])
                    };
                };
                pixels[i++] = color.r / (ssaa * ssaa) * 255;
                pixels[i++] = color.g / (ssaa * ssaa) * 255;
                pixels[i++] = color.b / (ssaa * ssaa) * 255;
                pixels[i++] = 255;
            }
        }
        ctx.putImageData(imgdata, 0, 0);
    }

接下来是希望实现正交相机,融合光线,用其他语言(比如C井)实现玩玩这样……

期待什么年代游戏可以 real-time ray tracing ,那会是怎样一番光景啊……(看看现在 tone tracing 的效果都已经如此惊艳了)

说到游戏,不得不提下一个话题。

Ori And The Blind Forest

这个游戏跟 ray tracing 没什么关系,这是一个2D游戏。

与其说游戏,不如说是艺术。第一眼看上去以为是个设计作品,类似可交互动画这样。

结果分分钟打脸,手残党被虐哭……

分分钟成为自己最喜欢的游戏。

和我一起呐喊,软人希!

(Steam平台有售,强烈推荐体验。这个主题只说了这么几句不是没话说,恰是因为实在有太多话说了)

这就是本周的Sean Talk,我们下周见!(设么鬼……什么时候有这个系列了,不要说得好像要开每周专栏了一样好吧><)

完了,书单又多了一本,PBRT……

新年新主机

趁着过年放假,把主机迁移啦

从Conoha迁移到了Vultr,Conoha试用快到期了,速度还是差强人意的,只是ssh实在不友好,一直都只能用pycharm内置的ssh连上,实在是太奇葩了。

之前就准备到期以后试试Vultr,一直用的sssis.com的Linode 50ms ping一直很眼馋呀,今天试了一下Vultr的ping,我去30几ms,果断迁移。

之前配置文件备份的都比较齐全,所以边写脚本边弄,也就几个小时搞定。期间收到了鲍鲍童鞋的巨额捐款,实在受宠若惊,改DNS,关闭Conoha,OK一切正常,无痛迁移。

Vultr暂时用起来实在是不错,速度快(电信,家里联通150+的ping谁都救不了了……),性价比高,

对啦,打个广告 http://www.vultr.com/?ref=6821242 如果想用Vultr VPS的可以注册哦。如果只是想要个空间放个项目什么的也可以直接跟我联系,当然,Shadowsocks就更没问题啦~

最后呢,祝我生日快乐喵~ XD

 

批量修改git中已提交Commit中的Author和Email

实际项目中,因为项目成员有时候会换电脑,所以git的author以及email信息不一定保持一致,结果导致在提交记录中同一个人会有不同的名字……简直不能忍啊……

找了一下,这个方法看上去是靠谱的

#!/bin/sh

git filter-branch --env-filter '

an="$GIT_AUTHOR_NAME"
am="$GIT_AUTHOR_EMAIL"
cn="$GIT_COMMITTER_NAME"
cm="$GIT_COMMITTER_EMAIL"

if [ "$GIT_COMMITTER_EMAIL" = "[email protected]" ]
then
    cn="Your New Committer Name"
    cm="Your New Committer Email"
fi
if [ "$GIT_AUTHOR_EMAIL" = "[email protected]" ]
then
    an="Your New Author Name"
    am="Your New Author Email"
fi

export GIT_AUTHOR_NAME="$an"
export GIT_AUTHOR_EMAIL="$am"
export GIT_COMMITTER_NAME="$cn"
export GIT_COMMITTER_EMAIL="$cm"
'

跑起来,慢是慢了点……0.5s一个commit吧,当前项目1000多个commits是要跑一段时间的,不过确实有效~
干干净净真开心!强迫型人格障碍患者福利~


啊啊 被坑了啊!!!

进行这样的操作以后,之前所有的Commit都变成双份了,hash值都不一样,我不清楚是我操作的问题还是什么问题……反正这种方案暂且存疑T T

 

Nginx

发生了什么


这个博客现在是通过我的VPS上Nginx反向代理访问的,等于自带翻墙+加速。
本来页面是通过七牛云镜像加速的,所以访问还可以,但是仪表盘就一定要翻墙,不然速度实在是不能接受。
尝试过加速服务,但是国内的加速服务全部都要备案……好麻烦……

缘由


起因是这样的,公司最近Google的VPN完全跪了,完全访问不了,这……你让我怎么活……
于是找到了一个超级好用的服务www.sssis.com,好用到什么程度呢,好用到我刚打开页面就给作者捐了10块……
用着用着,我就在思考这是怎么实现的……
想了半天都没找出一个可行的方案。
于是问宣酱,答曰:

Nginx反向代理。

没错,好主意呢!

不过既然Google已经有人提供服务了,而且Google如果想反向代理那一定是要走ssl的太麻烦,所以不如先反向一下博客。
OK,放假最后一天就这样过吧~

Nginx的安装


yum源里正常是没有Nginx的,而且VPS里正常都会有Apache httpd占用80端口,所以这两个问题要首先解决。

  1. 新增Nginx的官方yum源,新建 /etc/yum.repos.d/nginx.repo 源配置文件,输入如下内容:
    [nginx]
    name=nginx repo
    baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
    gpgcheck=0
    enabled=1
    
  2. 更新系统到最新状态:
    yum -y upgrade
    

    如果不想升级内核可以用如下参数:

    yum --exclude=kernel* update
  3. 安装、启动Nginx,关闭Apache httpd
    # 安装Nginx
    yum -y install nginx
    
    # 配置开机启动
    chkconfig --add nginx
    
    # 取消Apache httpd开机启动 
    chkconfig --del httpd
    
    # 关闭Apache httpd服务
    service httpd stop
    # 或
    /etc/init.d/httpd stop 
    
    # 启动 Nginx
    /etc/init.d/nginx start 
    

    好啦,到这一步位置,使用ip地址或者域名访问你的VPS,应该已经可以看到Nginx欢迎页面了~

  4. 配置Nginx
    Nginx的配置文件都在 /etc/nginx/ 目录下其中,nginx.conf 是主配置文件,我们可以暂且不用管它,直接进入 /etc/nginx/conf.d/ 目录。
    按照 nginx.conf 中的默认配置,Nginx会自动加载本目录中的所有配置文件,所以大家放心大胆的直接新建文件就好啦~不知道大家的习惯是怎样修改VPS配置文件的,ssh vi当然没问题,不过不停的修改再更新也是有些麻烦的,所以我一般喜欢用filezilla通过sftp协议22端口登陆,直接用sublime text打开文件,当filezilla发现本地临时文件被修改了之后会自动提示是否更新,更新后即会自动上传覆盖远端文件了,这时候在ssh中重启服务就额可以了,十分方便。OK,那我们就来试一下,首先在 /etc/nginx/conf.d/ 中新建配置文件,文件名随意,后缀名用 .conf就好了。比如我们新建一个 findix.conf 的配置文件。内容如下:

    ## Start www.findix.cn ##
    server {
        listen 80; #监听的端口
        server_name   blog.findix.com; #访问的域名
    
        access_log  logs/findix.access.log  main; #log位置,注意/etc/nginx/ 下默认是没有logs目录的,需要自己mkdir新建,不然编译conf的时候会警告的。
        error_log  logs/findix.error.log;
    
        index  index.html index.htm index.php; #默认index文件名
    
        ## send request back to apache ##
        location / {
            proxy_pass  http://fengxiang23.0fees.us; #反向代理最重要的啦,表示代理url,以 协议://域名:端口 的形式给出
    
            #Proxy Settings
            proxy_redirect     off;
            proxy_set_header   Host             $host;
            proxy_set_header   X-Real-IP        $remote_addr;
            proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
            proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
            proxy_max_temp_file_size 0;
            proxy_connect_timeout      90;
            proxy_send_timeout         90;
            proxy_read_timeout         90;
            proxy_buffer_size          4k;
            proxy_buffers              4 32k;
            proxy_busy_buffers_size    64k;
            proxy_temp_file_write_size 64k;
        }
    
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/share/nginx/html;
        }
    }
    ## End www.findix.cn ##

    该注意的地方注释里都写出来了,按照自己的情况配置即可。
    配置完成之后,reload或者restart Nginx服务即可

    /etc/init.d/nginx restart
    

    注意一下编译结果,没问题的话……那就没问题了。

  5. 最后,把你的域名指向这台VPS就可以啦~
    立即生效!
  6. 没有啦~~快去访问一下看看。
    从这个博客上来看,在设置了反向代理之后的速度,啧啧,简直快得吓人啊,再也不用翻墙写博客了T T
    Over,今天就是这样喵

使用disunity拆解Unity3d制作的游戏获取资源

@凤翔FindiX

听说Windows Live Writer写博客很好用所以我来试一试……
声明:本教程使用所有工具全部来自Github,请不要恶意商业使用版权资源,作为开发者+创意工作者,让我们一起维护自己良好的版权环境。

0. Overview

在产品原型阶段,不可避免的会使用一些他人的素材以及原画缩短开发周期。而在产品风格尚未明朗的情况下,在众多游戏中获取灵感,也是一个“偷懒”的好方法。
过去Cocos-2dX流行的时代,拆解是一个很容易的工作。
而现在越来越多的游戏使用了Unity3D游戏引擎开发,由此带来的问题就是,再也不能右键解压缩对付那些apk了。
本来以为,Unity开发的项目,应该是不能拆了,结果,几经摸索,竟然发现了这么个好东西

DISUNITY
使用Java编写的自动化Unity资源分析器。

废话少说,让我们来看看这是如何使用的吧。

1 .获得Disunity

首先,点击链接下载最新的发行版
直接解压,为了方便,可以把该目录放进环境变量中。
然后在cmd中尝试输入disunity
如果该命令存在,说明已经部署完成。

2. 拆解

同样,还是右击解压apk项目(ipa也可以,只是apk相对比较容易获得)
(对了, 这个网站可以通过Google Play应用地址获得apk下载链接直接下载apk,非常实用向大家推荐)

在项目的libarmeabi-v7a目录下,如果能看到libunity.solibmono.so文件,说明该项目是使用Unity3D开发的,OK,我们可以继续下去了。
下面我们要寻找的,是形如*.unity3d*.assetsff910c990f6ec42858669c600434f140这样一长串符号但是没有后缀名的文件们。
一般来说,他们都位于
assetsbinData
AssetBundlesAndroid
等位置,大家可以自己找找看啦。
找到了以后,事情就简单了。
比如说吧,我们找到在assetsbinData目录下面有很多这样的文件。
我们就可以用这样的命令

C:UsersSeanDocumentsunityassetsbin> disunity Data*

执行完毕之后,你就会发现Data文件夹里,每一个文件都会对应生成一个文件夹,打开他们吧,成果都在里面了!

3. 分类

文件都拆解开了,但是你会发现,他们都是杂乱堆在一起的
难道要我们一个个找出来么?
不,当然不是啦~
有两种方法解决这个问题
一种是把所有文件全部取出来,然后根据拓展名排序即可
还有一种则是通过搜索功能,找出对应拓展名的文件
我一般使用的是第一种
在说明方法之前,先简要介绍一下拆解出来后文件的格式

类型 扩展名 状态
音频片段 .mp3.wav.ogg Ok
字体 .ttf.otf Ok, but wrong file extension for OpenType fonts
Mesh Unity 4 and uncompressed only
TextAsset .txt Ok
Shader .shader Ok
Texture2D .tga Missing support for PVR, ATC and some exotic color formats
Cubemap .obj Wrong texture flags
SubstanceArchive Ok
MovieTexture Ok

有一个需要特别解释的是,最重要的图片素材,是以.tga格式析出的,这种文件可以直接通过Photoshop打开,也可以使用格式工厂之类软件转换为别的格式如.Png等。
知道了扩展名,搜索的方法应该很容易了,不表。
第一种方法主要问题是如何从文件夹中拷贝所有文件出来。
我自己是写了一个Python脚本

# -*- coding: utf-8 -*-

import xlrd
import os
import os.path
import shutil

#需要遍历的目录
fromDir='.'
#文件汇总到的目录
toDir='..result'
list_dirs = os.walk(fromDir)
for root, dirs, files in list_dirs:
    for f in files:
        print os.path.join(root, f)
        shutil.copy(os.path.join(root, f),  toDir+f)
print "All Done"

得到所有文件后,选取需要的,或者分类也都不是问题了

4. GUI

自己是Linux重度使用者
(主要是服务器,桌面用Linux我只能说真的是蛋疼,虽然用着没问题,但是美工模式的时候连Ps都没有你让我凭什么混饭吃……)
shell下工作很顺手,但是也许有些纯美工盆友也需要使用这个工具吧。
(美工:我们才不要呢,我们可以自己画,哼)
有个GUI,可能会方便一些。
OK,这里还真的有人基于.Net写了一个GUI,点击链接下载发行版,直接解压粘贴到disunity目录中,双击打开即可食用,哦不,是使用- –


基本上就是这样喵,如果有什么不清楚的地方可以留言啦~
本来这篇想写的欢快一点的,没想到技术文写的这么严肃……唉真是的。

Facemesh

The Social Network 社交网络

这部电影从我看第一遍起就狂热的喜欢。

大卫芬奇真的拍的非常好。

我这个人呢,总有个习惯。

当一个东西电影电视动漫什么最火的时候,总是不看。

等到过去了,偶然的时候,翻出来看看,哎,还真是不错。

社交网络也是有如此。

看了真是非常非常多遍,推荐到团队,也成了很长期的梗(最经典莫过于,0.03%的股份……)

电影中,节奏感最强的一段,就是Mark在分手夜,微醺的时候,一边写博客,一边侵入学生公寓服务器,下载了全部学生的照片,做出了Facemesh成功的挂掉了Harvard的网络。

我呢,酒倒是有,只是分手之夜也没这机会了,再说有Mark的前车之鉴,我也不敢真做这么个网站把自己搞出个处分来。

上次看教学管理系统的时候,玩到后来没意思了,也在考虑下载全部照片看看,但是呢,毕竟人家是教学管理系统嘛,还真是挺周全的。查询条件不仅有学号,还有一个PID,随机字符。

这个可就没辙了,研究了很久还是放弃了。

昨晚,机缘巧合在另一个地方发现了能拿到全部的数据,比我想要的更多……

(……我还是觉得我这个时候写博客完全是在作死,no zuo no die……)

后面的就简单了。

拉到的是一个xml,包含全部信息,这种时候当然是Python上了,最方便。

# -*- coding: utf-8 -*-

import xlrd
resultFile = open("./info.txt", "w")
fname = "./info.save.xls"
data = xlrd.open_workbook(fname)
table = data.sheets()[0]
nrows = table.nrows
ncols = table.ncols
for i in range(nrows):
if i==0:
continue
sno = table.cell(i, 0).value
if(len(sno)==8):
resultFile.write(sno+'n')
resultFile.close()
print "All Done"

 

脚本简单的从xml中拉出了所有学号,省得遍历。

下面是实际下载用的脚本了,其实更短。
(具体地址隐去)

# -*- coding: utf-8 -*-

import urllib
infoFile = open("./info.txt", "r")
for sno in infoFile.readlines():
sno=sno[0:-1]
print sno
urllib.urlretrieve("http://210.35.95.97/dlyq/StudentPhotos/"+sno+".jpg", "./photo/"+sno+".jpg")

搞定。
下一步可以再按照男女分类啊,什么的……
Facemesh看来是一个还挺麻烦的事情,现在还真没这闲工夫,而且……确实是对同学不太尊重(T T)因为我真的很想把我一卡通的证件照换一张啊!!!

很简单就搞定了男女分类嘛,Python果然好用~

# -*- coding: utf-8 -*-

import xlrd
import os
import os.path
import shutil

fname = "./info.save.xls"
dic=dict();
data = xlrd.open_workbook(fname)
table = data.sheets()[0]
nrows = table.nrows
ncols = table.ncols
for i in range(nrows):
if i==0:
continue
sno = table.cell(i, 0).value
gender = table.cell(i,2).value
# print sno+' '+gender
dic[sno]=gender

list_dirs = os.walk('./photo/')
for root, dirs, files in list_dirs:
for f in files:
# print os.path.join(root, f)
if dic[f[:-4]].encode('utf-8')=='男':
print f[:-4]+' '+dic[f[:-4]]
shutil.copy('./photo/'+f, './photo/male/'+f)
elif dic[f[:-4]].encode('utf-8')=='女':
print f[:-4]+' '+dic[f[:-4]]
shutil.copy('./photo/'+f, './photo/female/'+f)
print "All Done"

好吧,可以说结果了……
结果就是
我们一整层楼的人像蛇精病一样笑了一个晚上直到1点钟啊!!!!!!!!!!!!!!!!!!!
真的是证件照毁三观啊!!!!!!!!!!!!!!!!!!!!
所有美女全部现原形啊啊啊啊!!!!!!!!!!!!!!!!!
很熟的同学愣是看了十几次都没认出来啊!!!!!!!!!!!!
太恐怖了啊!!!!!!!!!!!!!!!!!!!!!!!!!
我觉得如果真的写了个Facemesh发到网上去,肯定会被全体女生集体围攻致死……切成一条一条的……
算了吧还是小命要紧,只是,再也无法直视同学们了T T

最后再免费附赠我用来识别教学管理系统验证码的Tampermonkey脚本吧……

// ==UserScript==
// @name SHIEP教学管理系统登录验证码识别
// @namespace com.find1x.js.shiepTeachingManagement
// @version 0.1
// @description 自动填写教学管理系统验证码
// @match http://210.35.95.65:7777/schoolmanager/*
// @match http://210.35.95.65:7777/schoolmanager/
// @copyright 2014+, FindiX Studio
// ==/UserScript==

window.onload = function() {
var image = document.getElementsByTagName('img')[8]; //如果要用在greasemonkey脚本里,可以把下面的代码放在image的onload事件里
var canvas = document.createElement('canvas');
var ctx = canvas.getContext("2d");
var numbers = [
//模板,依次是0-9十个数字对应的明暗值字符串
"1100011100100100111000011100001110000111000011100001110010010011100011111111111111110000000",
"1110011100001111100111110011111001111100111110011111001111100111000000111111111111110000000",
"1000011011100111110011111001111100111100111100111100111100111110000001111111111111110000000",
"1000001011110011111001111001100001111110011111100111110001110011000011111111111111110000000",
"1111001111000111100011101001101100101110010000000111100111110011111001111111111111110000000",
"0000000011111101111110000011111100111111001111100111110001110011000011111111111111110000000",
"1100001100111010111110011111001000100011000011100001110010011001100001111111111111110000000",
"0000000111110011110011111001111001111100111100111110011110011111001111111111111111110000000",
"1000001001110000111000001001100001110000010011000001110000111001000001111111111111110000000",
"1000011001100100111000011100001100010001001111100111110001110011000011111111111111110000000"
];
var captcha = ""; //存放识别后的验证码
canvas.width = image.width;
canvas.height = image.height;
document.body.appendChild(canvas);
ctx.drawImage(image, 0, 0);
for (var i = 0; i < 4; i++) {
var pixels = ctx.getImageData(9 * i + 3, 3, 7, 13).data;
var ldString = "";
for (var j = 0, length = pixels.length; j < length; j += 4) {
ldString = ldString + (+(pixels[j] * 0.3 + pixels[j + 1] * 0.59 + pixels[j + 2] * 0.11 >= 140));
}
var comms = numbers.map(function(value) { //为了100%识别率,这里不能直接判断是否和模板字符串相等,因为可能有个别0被计算成1,或者相反
return ldString.split("").filter(function(v, index) {
return value[index] === v;
}).length;
});
captcha += comms.indexOf(Math.max.apply(null, comms)); //添加到识别好的验证码中
}
document.querySelector("input[name=validateCode]").value = captcha; //写入目标文本框
};