unity命令和打包。

针对不同的平台(android/ios/pc),unity会对不同平台进行针对性优化。

因此如果要针对不同平台打包,最好针对每个平台将项目目录复制出来一份。这样可以避免unity发现平台转化了,对资源进行重新优化。当然了,如果做的游戏小,这点时间是可以忽略不计的。可惜我们的项目转一次资源就得半小时-.-!!。

vs2013下将文件使用unix结束符保存

There are inconsistent line endings in the ‘Assets/Scripts/ui/Mail/MailPrefab.cs’ script. Some are Mac OS X (UNIX) and some are Windows.
This might lead to incorrect line numbers in stacktraces and compiler errors. Many text editors can fix this using Convert Line Endings menu commands.

原因是因为vs下使用 “CR LF”结尾(Windows平台), unity下默认使用”LF”结尾(Unix平台)。

vs下想改为使用LF结尾,打开需要修改的文件,然后“文件->高级保存选项” 行尾选择“Unix (LF)”保存。

对于我们工程数十个文件来说,这不是很优雅的解决方式,幸好早有先人提供更好的方案。

http://www.grebulon.com/software/stripem.php

这个vs插件,可以将项目中所有文件以 LF 结束符保存。

jenkins将mac os 建立为slave节点

我们手游项目,需要支持android/ios,android支持在linux下打包。ios必须要mac上进行打包。

持续集成我们使用了jenkins,找了一台mac mini做为slave。

一开始使用的是java web start。结果试了各种方法得到结论,java web start特别方便,最好不要在mac上使用,因为担心java的安全问题,mac上的java web start根本无法使用。

参考了文章:https://blog.samsaodev.com/how-to-setup-a-jenkins-slave-running-mac-osx-for-ios-projects-part-1/

在ssh-add那一步如果遇到:SSH_AGENT_FAILURE 错误,可以先执行下 eval $(ssh-agent) 试试能否解决问题。

使用ssh建立slave节点。

在mac os 上一直无法使用username/password模式登陆,发现原来mac os因为安全原因,禁止了没有交互的ssh登陆。这里只能使用rsa private key 进行登陆。

在master server上生成key。

然后将public key 复制至slave server。

登陆slave时失败了,查看slave server上的/var/log/secure:sshd[12053]:  Address 10.234.49.36 maps to localhost, but this does not map back to the address – POSSIBLE BREAK-IN ATTEMPT!

是因为:是因为DNS服务器把 10.234.x.x 的地址都反向解析成 localhost ,而DNS服务器不是自己的,不能改。 解决的办法就是,编辑 ssh 客户端的 /etc/hosts 文件,把出问题的IP 地址和主机名加进去,就不会报这样的错了。

两台机器之间使用ssh key登陆,默认使用本地当前的用户名,如果不是,则需明确指定用户名。

在jenkins上使用ssh key登陆时,密码必须为空。同时指定private key 所在路径。

OK,添加jenkins子节点成功。

测试配置数据占用的内存大小

游戏中一直不是很清楚配置数据占用了多少内存,现在是使用json转c#对象,转化使用时间也不清楚。

scriptableobject和json相比也不知道谁的性能更优。

现在使用的是dictionary来存储的数据,和hashtable相比谁更快,不知道。现在使用的key是string,使用int是否更快。

以上都需要测试结果:

1、先测试占用的内存。

打一个空场景。

占用的内存如图:

  • total 44.6
  • unity 13.8
  • mono 0.7
  • gfxdriver 17.0
  • fmod 252
  • profiler 12.2
  • assets 19.7
  • other 9.8
  • builtin resources 243.6
  • not saved 26.7
  • scene memory 8.7

原来的工程场景和资源太多了,打包一次太费时间,这里重新建一个工程

内存占用如图:

  • total 18.6
  • unity 2.7
  • mono 0.5
  • gfxdriver 3.3
  • fmod 310k
  • profiler 12.1
  • assets 1.5
  • other 2.1
  • builtin resources 231.1k
  • not saved 145.6k
  • scene memory 15.5k

log_config配置文件大小1M,json未压缩。使用resource.load导入内存增加:1.1M和原文件基本相同。多次使用Resources.load只会增加一份内存。(在assets中显示为text asset)

感觉消耗的内存由other移至assets中。再测试一次,unity死掉了。再重启测试一次,果真如此,other中asset0的东西没有了,assets中多了一个textasset名为log_config。

TextAsset text=Resources.Load(“log_config”) as TextAsset;
TextAsset text2 = Resources.Load(“log_config”) as TextAsset;

连续两行,内存也没有多少变化,TextAsset可能都是引用。果真只是引用。

神奇了。使用Resources.unload后,TextAsset log_config被释放内存。但是other中没有增加内存!!!

我把json中的字符串放入textbox中,内存消耗变的巨大:

主要是other中的managedHeap.usedSize变为了71M,在simple界面中可以看到mono也同步变为了71M。

测试结果,使用Resources.load 加载后,然后使用unload释放掉对象内存,但是好像该对象还可以继续使用 -.-!!。难道是因为内存区还保留着数据导致的?unloadAssets,如果被引用对象再次被使用,会从被加载的地方重新被加载。所以,一个对象完全不被使用后,再unloadAssets。

在这里,我们的配置文件被转化为了c#对象,所以可以直接unload掉,释放内存。

minijson中有个东西占用了内存,转换申请了6M内存,一直没有被释放。如果再转换一个小json比如“{}”就会将内存释放掉。

使用json进行转换,中间产生了8M内存占用,既使将引用对象设置为null,不调用GC.collection()也不会回收内存。

text asset转为json消耗2秒,json存入dictionary消耗1.5秒。

开始测试scriptableobject。

没有测试protobuf,scriptableobject比未压缩json容量仅为20%,加载时间仅为10%,内存消耗仅为20%。完全可以替代json。

另外,字符串可以考虑7z压缩,这样可以使用更小的内存,仅多消耗一点CPU。

scriptableobject无法定义为泛型类。

 

unity3d 动态给按钮添加事件

UIEventListener.Get(bt1).onClick = click;

bt1 是按钮的gameobject

 

游戏登陆场景掉祯排查

我们游戏中场景经常出现掉祯的现象。

fps会突然从30降至15。

原来一直没有找到原因,最近学习unity,使用profiler看运行时的情况,看到我的手机上,掉祯出现时,cpu usage会突然飙升,同时gpu usage会也同步飙升。

cpu上升显示是camera.render使用率大量增加。

gpu上升定位至是RenderForwardOpaque.Render占用时间大量增加导致的。

 

 

 

 

unity3d 中捕获所有的异常

void Start () {
// System.AppDomain.CurrentDomain.UnhandledException +=new System.UnhandledExceptionEventHandler(  _erroHandler);
//Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
AppDomain.CurrentDomain.UnhandledException += new System.UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
// Application.Run(new Game());
Application.RegisterLogCallback(_erroHandler);
Application.RegisterLogCallbackThreaded(_erroHandler);
}

private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
}

private static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
{
Debug.Log(“Application_threadException”);
}

void _erroHandler(string name,string stack,LogType type)
{
}

svn服务器安装

mkdir -p /archive/download
mkdir -p /opt/compile

yum install apr apr-devel apr-util apr-util-devel gcc openssl openssl-devel


cd /opt/compile
tar xvfz /archive/download/httpd-2.2.21.tar.gz
cd httpd-2.2.21
LDFLAGS=”-L/lib64 -L/usr/lib64″ ./configure –prefix=/opt/apache2 –with-mpm=worker –enable-static-support –enable-module=rewrite -enable-dav -enable-so
#-enable-maintainer-mode
make
make install
cp /opt/apache2/bin/apachectl /sbin


tar xvfz /archive/download/subversion-1.7.9.tar.gz
cd subversion-1.7.9
yum install unzip
./get-deps.sh
./configure –prefix=/opt/subversion –with-apxs=/opt/apache2/bin/apxs –with-ssl –with-zlib=/usr/local/zlib
make
make install


vi httpd.conf
LoadModule dav_svn_module modules/mod_dav_svn.so
LoadModule authz_svn_module modules/mod_authz_svn.so
<Location /svn>
DAV svn
SVNParentPath /opt/svnroot/repository
AuthzSVNAccessFile /opt/svnroot/repository/authgroup
AuthType Basic
AuthName “Subversion Repository”
AuthUserFile /opt/svnroot/repository/authpass
Require valid-user
</Location>

mkdir -p /opt/svnroot/repository

svnserve -d -r /opt/svnroot

创建密钥文件、初始帐号
htpasswd  -c /opt/svnroot/repository/authpass yan
New password:

新增帐号
htpasswd  -b /opt/svnroot/repository/authpass newuser newpasswd

设置权限
vi /opt/svnroot/repository/authgroup
[groups]
admin=yan
test=tan

[/]
@admin = rw

[test:/]
@test = rw

—-

创建新的 project newApp
svnadmin create /opt/svnroot/repository/newApp


客户端
svn checkout http://192.168.1.x/svn/newApp

进入 newApp 目录,新建目录:
trunk
branches
tags
svn add/commit 准备好基础结构。

重新checkout
svn checkout http://192.168.1.x/svn/newApp/trunk
即可进入正常开发,以后根据需要为trunk目录增加branch、tag。

 

注:如果遇到以下问题

/usr/local/lib/libsvn_subr-1.so.0: undefined symbol: apr_hash_clear

这是因为httpd和subversion编译使用的apr和apr-util使用的库不相同造成的。

可以在编译httpd时指定–with-par 和 –withd-par-util参数来指定使用subversion相同的apr和apr-util来编译httpd.

LDFLAGS=”-L/lib64 -L/usr/lib64″ ./configure –prefix=/opt/apache2 –with-mpm=worker –enable-static-support –enable-module=rewrite -enable-dav -enable-so –with-apr=/opt/compile/subversion-1.7.9/apr –with-apr-util=/opt/compile/subversion-1.7.9/apr-util

在网上找到一个阿里云建VPN的一键脚本

#!/bin/bash

function installVPN(){
	echo "begin to install VPN services";
	#check wether vps suppot ppp and tun
	
	yum remove -y pptpd ppp
	iptables --flush POSTROUTING --table nat
	iptables --flush FORWARD
	rm -rf /etc/pptpd.conf
	rm -rf /etc/ppp
	
	arch=`uname -m`
	
	wget http://www.hi-vps.com/downloads/dkms-2.0.17.5-1.noarch.rpm
	wget http://wty.name/linux/sources/kernel_ppp_mppe-1.0.2-3dkms.noarch.rpm
	wget http://www.hi-vps.com/downloads/kernel_ppp_mppe-1.0.2-3dkms.noarch.rpm
	wget http://www.hi-vps.com/downloads/pptpd-1.3.4-2.el6.$arch.rpm
	wget http://www.hi-vps.com/downloads/ppp-2.4.5-17.0.rhel6.$arch.rpm


	yum -y install make libpcap iptables gcc-c++ logrotate tar cpio perl pam tcp_wrappers
	rpm -ivh dkms-2.0.17.5-1.noarch.rpm
	rpm -ivh kernel_ppp_mppe-1.0.2-3dkms.noarch.rpm
	rpm -qa kernel_ppp_mppe
	rpm -Uvh ppp-2.4.5-17.0.rhel6.$arch.rpm	
	rpm -ivh pptpd-1.3.4-2.el6.$arch.rpm

	mknod /dev/ppp c 108 0 
	echo 1 > /proc/sys/net/ipv4/ip_forward 
	echo "mknod /dev/ppp c 108 0" >> /etc/rc.local
	echo "echo 1 > /proc/sys/net/ipv4/ip_forward" >> /etc/rc.local
	echo "localip 172.16.36.1" >> /etc/pptpd.conf
	echo "remoteip 172.16.36.2-254" >> /etc/pptpd.conf
	echo "ms-dns 8.8.8.8" >> /etc/ppp/options.pptpd
	echo "ms-dns 8.8.4.4" >> /etc/ppp/options.pptpd

	pass=`openssl rand 6 -base64`
	if [ "$1" != "" ]
	then pass=$1
	fi

	echo "vpn pptpd ${pass} *" >> /etc/ppp/chap-secrets

	iptables -t nat -A POSTROUTING -s 172.16.36.0/24 -j SNAT --to-source `ifconfig  | grep 'inet addr:'| grep -v '127.0.0.1' | cut -d: -f2 | awk 'NR==1 { print $1}'`
	iptables -A FORWARD -p tcp --syn -s 172.16.36.0/24 -j TCPMSS --set-mss 1356
	service iptables save

	chkconfig iptables on
	chkconfig pptpd on

	service iptables start
	service pptpd start

	echo "VPN service is installed, your VPN username is vpn, VPN password is ${pass}"
	
}

function repaireVPN(){
	echo "begin to repaire VPN";
	mknod /dev/ppp c 108 0
	service iptables restart
	service pptpd start
}

function addVPNuser(){
	echo "input user name:"
	read username
	echo "input password:"
	read userpassword
	echo "${username} pptpd ${userpassword} *" >> /etc/ppp/chap-secrets
	service iptables restart
	service pptpd start
}

echo "which do you want to?input the number."
echo "1. install VPN service"
echo "2. repaire VPN service"
echo "3. add VPN user"
read num

case "$num" in
[1] ) (installVPN);;
[2] ) (repaireVPN);;
[3] ) (addVPNuser);;
*) echo "nothing,exit";;
esac

注:这个脚本最后一步进行iptables转发时,会指向为阿里云的内网地址,需要手工操作一下,修改为公网IP。

nginx 日志切割

#!/bin/bash
## 零点执行该脚本
## Nginx 日志文件所在的目录
LOGS_PATH=/usr/local/nginx/logs
## 获取昨天的 yyyy-MM-dd
YESTERDAY=$(date -d "yesterday" +%Y-%m-%d)
## 移动文件
mv ${LOGS_PATH}/access.log ${LOGS_PATH}/access_${YESTERDAY}.log

tar cvfz ${LOGS_PATH}/access_${YESTERDAY}.log.tar.gz ${LOGS_PATH}/access_${YESTERDAY}.log

## 向 Nginx 主进程发送 USR1 信号。USR1 信号是重新打开日志文件
kill -USR1 $(cat /usr/local/nginx/logs/nginx.pid)