Unity中扩展GameObject类

今天看代码时看到一个之前不知道的技巧,可以扩展Unity的GameObject类,为GameObject添加自己定义的方法:

using UnityEngine;
using System.Collections;

public static class GameObjectEx  {

    public static T MakeSureComponent<T>(this GameObject gameObject) where T : Component
    {
        T t = gameObject.GetComponent<T>();
        if (t == null)
        {
            t = gameObject.AddComponent<T>();
        }
        return t;
    }

}

这个类添加在工程中后,所以的gameObject上都可以直接调用MakeSureCompoent这个方法,真是超级便捷.

this.m_footstepHandler = base.gameObject.MakeSureComponent<FootstepHandler>();

同理,Unity自带的其它类应该也是可以进行扩展的。

查找了下是哪个天才想到的这个办法,google找到最早的一篇是这个:

https://forum.unity3d.com/threads/howto-add-method-to-the-gameobject-class-ie-add-custom-variables-to-every-instance.89791/

手机上的聊天

手机上的聊天:有语音SDK,可以语音文本互转。也有语音SDK直接支持自建语音频道。

有文本翻译API,可以翻译为多国语种文字:https://www.microsoft.com/en-us/translator/home.aspx

各种翻译,目前已知的商业API有微软的,百度的,行云的,另外还它一些商业API提交翻译功能。

微软的 MicrosoftTranslatorAPI  可以检测出使用的语种。

记一次排查服务器被控制

一个朋友联系我说服务器被当做肉鸡了,在 /etc/init.d 目录有几个脚本无法删除,删除后自动生成。

联系云服务器技术客服,回复说是被当做肉鸡了。

我连上服务器查看了下那个脚本:

#chkconfig: 12345 90 90
#description: acdnfhruvx
#BEGIN INIT INFO
#Provides: acdnfhruvx
#Required-Start:
#Required-Stop:
#Default-Start: 1 2 3 4 5
#Default-Stop:
#Short-Description: acdnfhruvx
#END INIT INFO
case $1 in
start)
/bin/acdnfhruvx
;;
stop)
;;
*)
/bin/acdnfhruvx   
;;
esac

感觉没有任何有用的线索。

查看 conrtab -e ,也仅有一个正常的业务逻辑脚本。

本来以为他是常驻内存的进程来定时检测文件是否被删除,但查看history, ps 等也没有得到任何有用的线索。

打开 /etc/crontab 脚本时,发现异常了:

SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/

# For details see man 4 crontabs

# Example of job definition:
# .---------------- minute (0 - 59)
# |  .------------- hour (0 - 23)
# |  |  .---------- day of month (1 - 31)
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# |  |  |  |  |
# *  *  *  *  * user-name command to be executed

*/3 * * * * root /etc/cron.hourly/gcc4.sh

这个 gcc4.sh 是什么鬼,而且每3分钟执行一次,如此高频率就不仅仅是可疑,简单就是在自己脸上贴上我是木马。

打开 /etc/cron.hourly/gcc4.sh 后就很明了了:自动执行一个二进程代码文件。

把gcc4.sh 文件备份后修改名字,再去 /etc/init.d 目录下清除可疑的自启动脚本,删除后没有重新创建出来。

再去 修复 /etc/crontab ,把最后一行删除。把 gcc4.sh 删除,把里面提到的 so 文件删除。

OK,结束。

自己学习写的第一个shader,画个圆


学习到如果需要显示一个圆型的图片,需要自己来写shader,这里是我学习写的第一个shader。

以后会边学习边将写的shader记录下来,也可以不断补充自己学习能力。

Shader "Custom/Circle2" {
	Properties{
		_Color("Color", Color) = (1,0,0,0)
	}
	SubShader{
 
		Tags{ "Queue" = "Transparent" "RenderType" = "Transparent" "IgnoreProjector" = "True" }
		Pass{
			ZWrite Off
			Blend SrcAlpha OneMinusSrcAlpha

			CGPROGRAM

			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"

			fixed4 _Color; // low precision type is usually enough for colors

			struct fragmentInput {
				float4 pos : SV_POSITION;
				float2 uv : TEXCOORD0;
			};

			fragmentInput vert(appdata_base v)
			{
				fragmentInput o;

				o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
				o.uv = v.texcoord.xy - fixed2(0.5,0.5);
 
				return o;
			}

			fixed4 frag(fragmentInput i) : SV_Target{
				float distance = sqrt(pow(i.uv.x, 2) + pow(i.uv.y,2));
		
				if (distance > 0.5f) {
					if (distance < 0.51f) {
						return fixed4(_Color.r* distance, _Color.g* distance, _Color.b* distance, 0.6f);
					}
					else {
						return fixed4(0, 0, 0, 0);
					}
				}
				else {
					return fixed4(_Color.r * distance, _Color.g * distance, _Color.b * distance,1);
				}
			}
			ENDCG
		}
	}
}

开源java recast navmesh寻路库

自己之前写的在java服务器上使用导航网格寻路的库。

底层使用c++提供接口,java层通过jni调用c++接口。

https://github.com/zhukunqian/unity_navmesh_for_java

更多信息直接在github上交流吧。

unity官方出的内存查看工具

https://bitbucket.org/Unity-Technologies/memoryprofiler

Cannot open Eclipse Marketplace 错误

国内网络环境果真复杂。

今天使用eclipse遇到这个问题,推测这个问题只出现在国内。

http://blog.csdn.net/cashcat2004/article/details/43819517

按国内同僚的解决方法:

在eclipse.ini中添加

找来找去没找到解决办法,在stackoverflow中终于看到描述,在eclipse.ini中增加
 -Djava.NET.preferIPv4Stack=true

重启eclipse后顺利连上。

c/c++ 与 lua之前互调的性能测试

完整测试代码如下:

测试目标主要是看看c与lua之前互调的性能如何。

测试结论:c调用lua与lua调用c基本只有一个数量级的性能损失。

从c中调用lua,使用缓存ref的方式,可以提升30%的性能。

#include <lua.h>
#include <lauxlib.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/time.h>
#include "skynet.h"

// 取当前毫秒值
static int
ltime(lua_State *L) {
	struct timeval tv;
	gettimeofday(&tv,NULL);
	lua_pushinteger(L,tv.tv_sec*1000+tv.tv_usec/1000);
	return 1;
}

// 供lua调用,内部无业务逻辑
static int
ltest1(lua_State *L) {
        return 0;
}

// 供lua调用, 内部int相加并返回
static int
ltest2(lua_State *L) {
	int a1=luaL_checkinteger(L,1);
	int a2=luaL_checkinteger(L,2);
	lua_pushinteger(L,a1+a2);
	return 1;
}
// 内部调用lua中方法
static int
ltest3(lua_State *L) {
	lua_getglobal(L,"global_test_func1");
	lua_call(L,0,0);
	return 0;
}
// 内部调用lua中方法,并取得lua中返回值
static int
ltest4(lua_State *L) {
	lua_getglobal(L,"global_test_func2");
	lua_pushinteger(L,1);
	lua_pushinteger(L,2);
	lua_call(L,2,1);
	int sum = (int)lua_tointeger(L, -1); 
	lua_pop(L, 1); 
	lua_pushinteger(L,sum);
	return 1;
}
// 内部调用lua方法10000次
static int
ltest5(lua_State *L) {
	int sum=0;	

	for(int m=0;m<10000000;m++){
        	lua_getglobal(L,"global_test_func2");
        	lua_pushinteger(L,1);
        	lua_pushinteger(L,2);
        	lua_call(L,2,1);
        	sum=(int)lua_tointeger(L, -1);
		lua_pop(L, 1); 
	}

        lua_pushinteger(L,sum);
        return 1;
}
// 和test5一起对比
static int
ltest6(lua_State *L) {
        for(int m=0;m<10000000;m++){
                lua_getglobal(L,"global_test_func2");
                lua_pushinteger(L,1);
                lua_pushinteger(L,2);
                lua_call(L,2,1);
                lua_pop(L, 1);
        }
        lua_pushinteger(L,3);
        return 1;
}
// 和test5一起做对比
static int
ltest7(lua_State *L) {
	int func2_handler;
	lua_getglobal(L,"global_test_func2");
	func2_handler=luaL_ref(L,LUA_REGISTRYINDEX);

	for(int m=0;m<10000000;m++){
		lua_rawgeti(L,LUA_REGISTRYINDEX,func2_handler);
		lua_pushinteger(L,1);
		lua_pushinteger(L,2);
		lua_call(L,2,1);
		lua_pop(L,1);
	}
	
	//luaL_unref(L,LUA_REGISTRYINDEX);
	lua_pushinteger(L,3);
	return 1;
}

// 和test5一起做对比一下
int add(int a,int b){
	return a+b;
}
static int
ltest8(lua_State *L) {
	for(int m=0;m<10000000;m++){
		add(1,2);
	}
	return 0;
}


// full userdata

// light userdata

int
luaopen_perf(lua_State *L) {
        luaL_checkversion(L);
        luaL_Reg l[] = {
		{ "time",  ltime  },
                { "test1", ltest1 }, // 从lua中直接调用c,内部无逻辑
                { "test2", ltest2 },
		{ "test3", ltest3 },
		{ "test4", ltest4 },
		{ "test5", ltest5 },
		{ "test6", ltest6 },
		{ "test7", ltest7 },
		{ "test8", ltest8 },
                { NULL, NULL}
        };
        luaL_newlib(L,l);

        return 1;
}

lua代码:

require "common"

local perf = require "perf"


function global_test_func1()
--	print("global_test_func1")
end
function global_test_func2(a,b)
	return a+b
end
local t1
local t2

t1=perf.time()
for i=1,10000000 do
	perf.test1()
end
t2=perf.time()
print("test1:"..(t2-t1))

t1=perf.time()
for i=1,10000000 do
	perf.test2(1,2)
end
t2=perf.time()
print("test2:"..(t2-t1))

t1=perf.time()
for i=1,10000000 do
	perf.test3()
end
t2=perf.time()
print("test3:"..(t2-t1))

t1=perf.time()
for i=1,10000000 do
	perf.test4()
end
t2=perf.time()
print("test4:"..(t2-t1))

t1=perf.time()
perf.test5()
t2=perf.time()
print("test5:"..(t2-t1))

t1=perf.time()
perf.test6()
t2=perf.time()
print("test6:"..(t2-t1))

t1=perf.time()
perf.test7()
t2=perf.time()
print("test7:"..(t2-t1))

t1=perf.time()
perf.test8()
t2=perf.time()
print("test8:"..(t2-t1))

运行结果:

test1:470
test2:777
test3:1619
test4:1941
test5:1490
test6:1437
test7:675
test8:40

jni错误 UnsatisfiedLinkError

很久没写过jni了。这次项目中用到,准备使用vs2015生成dll,供java调用。我用premake5生成了vs2015项目,但生成出来的dll,无法在java中调用,报以下错误:

Exception in thread "main" java.lang.UnsatisfiedLinkError: RecastLib.hello()V
    at RecastLib.hello(Native Method)
    at RecastLib.main(RecastLib.java:22)

使用vs2015中的工具 dumpbin 查看dll中的方法:

          1    0 00001200 ?Java_RecastLib_hello@@YAXPEAUJNIEnv_@@PEAV_jobject@@@
Z = ?Java_RecastLib_hello@@YAXPEAUJNIEnv_@@PEAV_jobject@@@Z (void __cdecl Java_R
ecastLib_hello(struct JNIEnv_ *,class _jobject *))
          2    1 00001220 ?_Java_RecastLib_hello@@YAXPEAUJNIEnv_@@PEAV_jobject@@
@Z = ?_Java_RecastLib_hello@@YAXPEAUJNIEnv_@@PEAV_jobject@@@Z (void __cdecl _Jav
a_RecastLib_hello(struct JNIEnv_ *,class _jobject *))

发现 vs2015 编译的方法名全部被添加上了@后缀。

正确的应该是:

    ordinal hint RVA      name

          1    0 00011091 Java_RecastLib_hello = @ILT+140(Java_RecastLib_hello)

这是因为 vc++中的 Name Mangling:

	JNIEXPORT void JNICALL Java_RecastLib_hello
		(JNIEnv *, jobject);

如果要导出的cpp中使用了c++特性,即使指定为 extern “C” 也受Name Mangling的影响。

这里可以定义一个  java.def 文件也解决。定义如下:

LIBRARY recastDll
EXPORTS
  Java_RecastLib_hello

然后在vs2015的链接器中定义:

这样导出的函数即不会受name mangling 的影响。

除此之外,还可以使用  RegisterNatives 的方式将函数入口注入java vm(两种试并无性能差异)。

如下:

static JNINativeMethod s_methods[] = {
	{ "jniHello", "()V", (void*)Java_RecastLib_hello },
	{ "jniLoad",  "(Ljava/lang/String;)I", (void*)Java_RecastLib_load },
	{ "jniFind",  "(FFFFFF)Ljava/util/List;", (void*)Java_RecastLib_find }
};
JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM *vm, void *reserved)
{
	JNIEnv* env = NULL;
	if (vm->GetEnv((void**)&env, JNI_VERSION_1_8) != JNI_OK)
	{
		return JNI_ERR;
	}
	jclass cls = env->FindClass("LRecastLib;");
	if (cls == NULL)
	{
		return JNI_ERR;
	}
	int len = sizeof(s_methods) / sizeof(s_methods[0]);
	if (env->RegisterNatives(cls, s_methods, len) < 0)
	{
		return JNI_ERR;
	}
	return JNI_VERSION_1_8;
}

一个hashmap算法

阅读云风开源的AOI实现时,看到里面有一个hashmap算法实现。

https://github.com/cloudwu/aoi

这里记录下分享下其实现

map内部存储是使用数组实现即  map_slot,初始分配16个。容量不足时,以翻倍容量增加,并将对象重新进行分配至新的内存空间。

这里画图举例时以初始容量为8进行原理说明:

1、初始状态,所有slot处于未分配

2、插入A,使用hash算法计算出应该分配在哪个slot上(注:可以考虑添加扰动函数避免比较差的hash算法,这里针对aoi的情况,直接使用了对size取模)

假设对A取模后将其放入第三个slot

3、继续插入B和C,其中B和A取模后 不在相同的slot中。

然后是取模后分配到相同的slot的情况:

实际上两个对象不会存在相同的slot中。

这里如果出现分配的slot中已经存在对象了,比如此时,C分配的第三个slot已经存在A了。

则从数组最尾部向前查找第一个为空的slot,将C放入,并将A.next指向C所在的slot

 

4、继续插入一个和A相同slot的对象时,继续从尾部向前查找一个空的slot,并将A.next指向新分配的slot,新分配的slot.next指向原A.next ( 即C)

5、如果遇到分配的slot被其它slot的对象占用如何处理。

比如,我这里想分配E,取模后应该分配在第七个格子,但第七个格子已经被D占用。

这里采用的方式,是将D取出( 因为D取模不应该分配在第七个格子,只是因为第三个格子被占用了,所以才从尾部查找的一个空闲的格子放D),取出D后将E放后,如下图:

 

这里D被取出应该如何处理,再执行一个第1步,将D放hashmap即可。