??xml version="1.0" encoding="utf-8" standalone="yes"?>
我们先看下构造函数的规则
构造参数量: 0表示没有构造函? 1表示有构造函?个参?/p>
本类构?/th> | 父类构?/th> | 处理Ҏ |
---|---|---|
0 | 0 | 不处?/td> |
1 | 0 | 调本cctor |
0 | 1 | 调父cctor |
1 | 1 | 调本cctor, 本类ctor调父cctor |
2 | 1 | 调本cctor, 本类ctor调父cctor |
1 | 2 | 报错, 手动调父cctor |
2 | 2 | 报错, 手动调父cctor |
实际只用考虑最典型的一U行? 实例化子c? 转ؓ父类调用Ҏ, q个时?/p>
如果Ҏ是override, 调用的是子类
如果Ҏ是virutal或者不指明, 调用的是父类
整个重蝲q程, 子类l对不会隐式调用父类的行?/p>
构造函数的优点
构造函数的~点
其实我们对初始化函数的需求只?? 自定?/p>
所? 可以理解Golang不加入构造函数的设计是正的
? ? 清晰, 有规?/p>
在每个protoc-gen-lua生成的lua文g? 都有一?/p>
local protobuf = require "protobuf"
本n按照官方出的没问? 但是在ulua的目录里, L报protobuf找不到的错误. 前后Ҏ了下我生成的lua和ulua官方生成的代码里
发现居然他修改了地址改ؓ?/p>
local protobuf = require "protobuf/protobuf"
好吧, 只有修改生成器代码protoc-gen-lua\plugin\protoc-gen-lua中第412行改?/p>
lua('local protobuf = require "protobuf/protobuf"\n')
在LuaFramework\ToLua\Lua\protobuf\protobuf.lua?39行添?/pre>message_meta._member.Descriptor = descriptor在消息里可以通过msg.Descriptor获得此消息的反射信息׃proto文g定义的内容过多导致的lua local过限制的警?/h2>
q个错误真是让我哭笑不得, protoc-gen-lua的可用性再一ơ被怀?/p>
我们的协议好歹分成了接近100? 每个里面消息和数据是混合? 更别说有些童鞋喜Ƣ把一个项目的协议全写在一个文仉, 那生成的local数量直是酸爽
后记
搜烦protoc-gen-lua? 无意间又搜到3q前自己的博?a title="http://www.shnenglu.com/sunicdavy/archive/2013/04/24/199693.html" href="http://www.shnenglu.com/sunicdavy/archive/2013/04/24/199693.html">http://www.shnenglu.com/sunicdavy/archive/2013/04/24/199693.html
记得那个时候准备在服务器用lua, q好没这么干, 转了go, 否则后果不堪设想
lua上用pb其实q不Ҏ, 云风的pbc写的不错, 但怕有? sproto直接不兼容现有项? 风险大于易用性所以果断弃?/p>
因此, 看来有必要自己写一个支持良好的lua pb?/p>
]]>
Action[] a = new Action[3];
for (int i = 0; i < 3; i++)
{
a[i] = ( ) => { Console.WriteLine(i); };
}
for (int i = 0; i < 3; i++){
a[i]();
}
C#打印l果? 3 3
Golang的例?/p>
a := make([]func(), 3 )
for i := 0; i < 3; i++ {
a[i]= func( ){
fmt.Println(i)
}
}
for _, s := range a {
s()
}
Golang打印l果? 3 3
最后是Lua的例?/p>
a = {}
for i = 1, 3 do
table.insert( a, function()
print(i)
end
)
end
for _, v in ipairs(a) do
v()
end
Lua打印l果? 2 3
差异在于, C#和Golang变量捕获到闭包内时, 均用引用方? 卛_最后开始调用用变量时, ׃变量已经l束循环, 所以是最l?/p>
但是Lua捕获方式是值捕? 因此比较Ҏ理解, 是多就是多?/p>
?a title="http://code.google.com/p/protobuf/" >http://code.google.com/p/protobuf/下蝲protobuf-2.5版本
预备知识: 已经使用qprotobuf, 熟练应用protobuf序列化在各语a间交互信?/p>
目标: 获取proto内容而无需手动解析proto文g
为proto文gd更多的meta信息, q在q行期获?
protoc~译器准?/strong>
通过protobuf-2.5的源码或者从官网下蝲, 可以获得protoc的protobuf~译? q个~译器由C++~写, 官方支持完整的protobufҎ? ~译器默认支持C++, python和java 三种语言的代码生? 如需生成更多的语a, 可以通过官网的第三方面获取.
protoc插g原理
但我们在日常使用? 可能需要提取proto信息, 例如: 所有的枚D,消息{信? 字段名称和导出号. 自己~写词法解析器来做是费力不讨好的. 官方推荐的方法是使用protoc外挂插g来实?
protoc的插件设计比较独? 不用动态链接库或者java的jar包导入方? 而是直接使用了命令行来交换数?查看protobuf源码我们可以发现q样一个文?
protobuf-2.5.0\src\google\protobuf\descriptor.proto
q个文g描述了一个proto文g的格? 消息l成及枚丄完整信息. q是一U自我描q的Ҏ.
在找到这样一个文?/p>
protobuf-2.5.0\src\google\protobuf\compiler\plugin.proto
q样一个文件描q? 插g如何与protocq行交互的协?/p>
protoc~译器在l定指定proto文g及搜索\径后, 各U信息填充ؓdescriptor.proto描述的结构后通过CodeGeneratorRequest消息pd化ؓ二进制流后输出到命o? 插g只用捕获protoc命o行输出的二进制流, 序列化化回CodeGeneratorRequest卛_获得解析后的proto文g内容
q里需要注意的? 插g可执行文件很有讲I? 必须为protoc-gen-$NAME, 而且输出文g名参数必Mؓ--${NAME}_out
看一个栗?
protoc.exe foo.proto --plugin=protoc-gen-go=..\tools\protoc-gen-go.exe --go_out foo.go --proto_path "."
q个栗子? $NAME=go
protocfoo.proto文g(搜烦路径为当前\?的内定w过命o行输出给位于..\tools\的插件protoc-gen-go.exe, 输出文g名字?foo.go
descriptor.proto信息挖掘
我们注意到在descriptor.proto文g中包含有q样的一个message: SourceCodeInfo, q个消息体里有如下字D?/p>
optional string leading_comments = 3;
optional string trailing_comments = 4;
q两个字D对于我们获取proto文g的meta信息ؓ重要, 所谓的meta信息, 理解理解为C#语言中的attribute
q个attribute功能可以Z个字D? 一个消息扩充一些描q? 比如: 当一个字D通过反射昄在gui上时, gui需要获取这个字D늚中文描述
那么只需要如下编?
optional int32 somevalue = 1 //@ desc=”中文描q?
位于字段N的描q? 会被填充到SourceCodeInfo?trailing_comments? 而位于字D上方的字段, 会被填充到leading_comments?
SourceCodeInfo q没有直接挂载在message或者字D늚附近, 而是通过其下的path字段来描qC字段的关p? q是个极为麻烦的设计.
其原理如?
假设我有如下一个message
message foo
{
optional int32 v = 1; // comments
}
要获取v后的注释, 对应的path?4, 0, 2, 0
4 表示descriptor中message_type所在的序号,׃message_type对应的类型DescriptorProto是一个数l? 所?表示foo是在FileDescriptorProto的message_type数组cd的烦引ؓ0;
如此cL: 2, 0 表示 v在DescriptorProtol构体的field成员序号?的数l元素的索引?
如果需要更多的参? 可以获取https://github.com/golang/protobuf
github.com\golang\protobuf\protoc-gen-go工程内有详细代码解析
q是C地球上调试lua5.1最方便的工? 没有之一. 强大的注入式调试, 性能极高.支持 挂接q程, 变量展开, 断点{各U日常所需.
早期的Decoda是收费工? 因此质量非常?
Decoda现在已经停止开发ƈ开源了, 调试lua5.2会crash. 源代码可以作ZU技术参? 很多dll注入修改技? 灰常牛X
比较优秀的调试工?因ؓ收费), 可以调试lua5.1/5.2, 界面属于vs2008cd, 土豪可以考虑买几套试?/p>
对lua5.1支持较好, 5.2也能调但偶尔q是会crash, Zq程调试方式, 所以性能略低.
没有IDE, U命令行方式调试? 但因为简? 所以可以参考后写一个自qE序内徏调试?/p>
把这货放在最后是有原因的, q记得那句老话: 老外一开? 我们有自主研发? 对的, q货一定是参考了Decoda的代码后搞出个vs的插件来, 虽然不收? 但是不提下参考对象的行ؓq是值得Ҏ? q货在中文博客上? 不支持挂接到q程(Decoda支持), 不支?4位调?LuaStudio支持), 调试30~50ơ偶挂1?? ? 毕竟只是代码搬运? 不生产代?
q货装上, 能用, ?.2是不行的, 5.1比Decoda方便? 毕竟vs支持悬Q昄变量.
说了那么? 其实对于lua5.2版本的调? q是没有免费的比较合适的Ҏ, 如果实在惌? q是可以参考下RemDebug的原理及lua官方调试文档, 自己通过c api调用写一套适合自己的远E调试工? 其实没有多复? 但L不调试的?img class="wlEmoticon wlEmoticon-smile" style="border-top-style: none; border-bottom-style: none; border-right-style: none; border-left-style: none" alt="微笑" src="http://www.shnenglu.com/images/cppblog_com/sunicdavy/Windows-Live-Writer/lua_D2A5/wlEmoticon-smile_2.png">
׃要用protoc-gen-lua, q东西生成出来的lua依然使用官方的module/package机制. 对于游戏目来说, 惌行一些自定义d, 加密{? 变得不可能. q好官方在扩展上支持的还是不错的.
参考lua5.2的官Ҏ?a title="http://www.lua.org/manual/5.2/manual.html#pdf-require" >http://www.lua.org/manual/5.2/manual.html#pdf-require
require? lua会自动根据一定的搜烦规律扑ֈ加蝲代码的方? q个Ҏ定义?a name="pdf-package.searchers">package.searchersq个数组? 一共有4个加载搜索顺?/p>
1. preload, 对已加蝲的moduleq行直接q回, 对应package.preload[modname]
2. lualoader, 对lua文gq行加蝲, 搜烦路径?a >package.path
3. cloader, 对lua标准dllq行加蝲, 搜烦路径?a >package.cpath
4. croot, 官方文档说的是all-in-one加蝲? 感觉很神? 感兴可以自行参考源?/p>
那么, 如果只需要自q加蝲? 只需要这样做:
package.searchers[2] = function( name ) print("try to load", name ) end package.searchers[3] = nil package.searchers[4] = nil require "libtest"只保留preload功能, 然后第二个加蝲器换成自q加蝲函数, W三,W四直接屏蔽
1. L了全局性质的setfenv/getfenvpd函数, 语言层面提供_ENV语法p? q东西跟:操作W一? 只存在于~译?
官方自己实现module/require/package机制, 毕竟原生q套机制实现太弱Z..
2. 提供了无W号讉K函数
3. 更多的lua api变化. 如果惛_容lua5.1的写? 可以参?a >luabridge内LuaHelpers.h的实?/p>
以下是本Z用lua5.2实现的一套package机制, 供大家参?/p>
package = {}
-- d标记
package.loaded = {}
-- 搜烦路径数组
package.path = {}
package.access =
{
["string"] = string,
["print"] = print,
["table"] = table,
["assert"] = assert,
["error"] = error,
["pairs"] = pairs,
["ipairs"] = ipairs,
["tonumber"] = tonumber,
["tostring"] = tostring,
["type"] = type,
["math"] = math,
}
local function getreadablepath( name, pathlist )
for _, path in ipairs(pathlist) do
local fullpath = path .. "/" .. name .. ".lua"
local f = io.open( fullpath )
if f then
f:close()
return fullpath
end
end
return nil
end
function package.import( name )
-- 已经d的直接返?/pre>local existedenv = package.loaded[name]if existedenv then
return existedenv
endlocal access = package.access-- 讄讉K控制权限local meta ={__index = function( tab, key )-- 优先取包的空?/pre>local v = rawget( tab, key )if v then
return v
end-- 找不到时,从可讉K的权限表中查?/pre>return access[key]
end,}-- 初始化一个包的全局环境, q设|访问方?/pre>local env = setmetatable( {} , meta )--local readablepath = getreadablepath( name, package.path )if not readablepath then
error(string.format("package '%s' not found \n%s", name, table.concat( package.path, "\n" ) ) )endlocal func = loadfile( readablepath, "bt", env )
if type(func) ~= "function" thenreturn nil
end-- 讄标记package.loaded[name] = env-- 执行全局I间func( )return env
endpackage.path = {"E:/Download/t"}
local m = package.import "m"
m.foo()以下是m模块(m.lua)的内?/pre>function foo( )print("转蝲注明: 战魂筑 http://www.shnenglu.com/sunicdavy", io )
end
试l果? io打印出nil, 昄权限已经被控制住
本package设计比原生package更灵z? 更强?/p>
最q准备在手机目客户端中使用lua, 以前一直在服务器用luabind. 另外, tolua++也体验过, LuaPlus也在早年用过. 以下是本人对q些l定库的个h感觉:
luabind
利用boost机制把绑定做到极? 比较适合主c++, 弱lua的脚本框?
作者已l停止更? 在windows/linux~译没问? 但是在ios的LLVM? 无法~译
tolua++
像cocos2dx使用tolua++也是可以理解? 那么多函数需要绑? tolua++的头文gparse及自动代码生成节U了很多手动l定的时?
但是看到代码中有一部分bugfix心存不?U个人感? 本h使用不多, Ƣ迎砖头伺?,另外, tolua++只能p本层驱动C++, 而没有将已经实例化的句柄注册到lua的功能也是煞W啊
LuaPlus
接口较ؓ? 适于初学者上? 无Q何的模板, 性能不高
luaBridge
目地址: https://github.com/vinniefalco/LuaBridge
手册: http://vinniefalco.com/LuaBridge/Manual.html
U头文g实现, 无需~译, 包含q入工程卛_, 接口z高?/p>
相比luabind, 唯一不能实现的常用功能就是枚? 但是可以支持cL员静态变量注? q个无所谓了, 手写一个枚举支持也很简?/p>
看下演示代码:
class A { public: A( ) { } virtual void foo( int a ) { printf("foo base\n"); } std::string Member; }; class B : public A { public: virtual void foo( int a ) { printf("foo inherited\n"); } };
void foo( int b ) { }
luabridge::getGlobalNamespace(L) .beginClass<A>("Sobj") .addConstructor<void (*) (void)> () .addFunction("foo", &A::foo) .addData("Member",&A::Member) .endClass() .deriveClass<B, A>("SSec") .addFunction("foo",&B::foo ) .endClass(); luabridge::getGlobalNamespace(L).addFunction("foo", foo ); B ins; ins.Member = "data"; luabridge::setGlobal(L, ins, "ins");
lua侧的代码
local a = Sobj()
a:foo(2)
a.Member = "hello"
ins:foo(3)
文本格式的解析错误不能用捕获错误来获取, 因此,我们需要用自定义的错误收集器q行攉, 看代?
#include <google/protobuf/text_format.h>
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
#include <google/protobuf/io/tokenizer.h>
class PBTextErrorCollector : public google::protobuf::io::ErrorCollector
{
public:
PBTextErrorCollector( const std::string& FileName )
: mFileName( FileName )
{
}
virtual void AddError(int line, int column, const string& message)
{
CCLog("%s(%d:%d) %s ", mFileName.c_str(), line, column, message.c_str() );
}
virtual void AddWarning(int line, int column, const string& message)
{
CCLog("%s(%d:%d) %s ", mFileName.c_str(), line, column, message.c_str() );
}
private:
std::string mFileName;
};
解析代码
google::protobuf::TextFormat::Parser P;
P.RecordErrorsTo( &PEC );
P.Parse( &AIS, &AF );
另外: 文本格式的注释用unix shell风格: ?开?/p>
下面是我的文本格式的配置文g
AnchorPointX: 0.5 AnchorPointY: 0 SpriteScale: 2 ComponentName: "ActorActionManager" ComponentName: "ActorFrameEventDispatcher" #ComponentName: "SoundFXController" ComponentName: "RoleDeltaMoveController" ComponentName: "RoleBehaviorDirector" InitAction: AA_Idle Animations { AnimationName: "mai_idle" AnimationInterval: 0.067 }
~译python版的protobuf模块
?a >https://code.google.com/p/protobuf/downloads/list 下蝲官方的原生版本protobuf, q里发文时用的?.4.1版本
~译出protoc执行文g, 放一份在protobuf-2.4.1\src\?/p>
下蝲python2.7版本, 在protobuf-2.4.1\python下运行python setup.py install(如果找不到pythonLpythonl对路径)
q一? python会下一个蛋( 真的是一个python的egg文g ), 然后~译出python版本的protobuf模块攄在python?/p>
制作protoc-gen-lua的批处理
放一份protoc在protoc-gen-lua的plugin目录
~写批处?protoc-gen-lua.bat
@python "%~dp0protoc-gen-lua"
协议目录生成脚本
在你需要放|协议的目录~写如下批处?/p>
buildproto.bat
rd /S /Q .\%1%
"..\..\src\protoc-gen-lua\plugin\protoc.exe" --plugin=protoc-gen-lua="..\..\src\protoc-gen-lua\plugin\protoc-gen-lua.bat" --lua_out=. %1%.proto
注意protoc.exe及protoc-gen-lua.bat的\径符合你的\?/p>
再编写要~译的proto协议的批处理generate.bat
call buildproto.bat loginsvc
执行generate.bat? 会~译同目录下的loginsvc.proto,输出loginsvc_pb.lua
~译链接lua的pb?/strong>
protoc-gen-lua\protobuf\目录拯C前的协议目录
其下的pb.c铑օ你的工程, 注意VS2010的VC下需要修Ҏ?/p>
1.?#include <endian.h>修改?/p>
#ifndef _WIN32
#include <endian.h>
#endif
避免在windows下缺失文件报?
2. 调整struct_unpack函数前几行ؓ
static int struct_unpack(lua_State *L)
{
uint8_t format = luaL_checkinteger(L, 1);
size_t len;
const uint8_t* buffer = (uint8_t*)luaL_checklstring(L, 2, &len);
size_t pos = luaL_checkinteger(L, 3);
uint8_t out[8];
buffer += pos;
避免VS2010的VC~译器过于标? 严格要求C风格函数变量前置声明
在lua_State声明后添加如下代?/p>
extern "C" { int luaopen_pb (lua_State *L);} // 注意防在命名I间外的全局声明
luaopen_pb( L ); // 直接注入全局pb, 避免动态加载pb.dll造成的一pd跨^台问?/p>
lua中用pb
local loginsvc_pb = require “loginsvc_pb”
local REQ = loginsvc_pb.CheckVersionREQ()
local Data = REQ:SerializeToString( )
local ACK = loginsvc_pb.CheckVersionACK()
ACK:ParseFromString( Data )
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }
我的工程目录
script\
protobuf\
buildproto.bat
generate.bat
loginsvc_pb.lua
loginsvc.proto
Main.lua
src\
protoc-gen-lua\
example\
plugin\
protobuf\
q里我们讨论的是lua的事件派发机? 我将此写成lua模块, 方便配合cocos2dxq行逻辑处理
local Global = _G
local package = _G.package
local setmetatable = _G.setmetatable
local assert = _G.assert
local table = _G.table
local pairs = _G.pairs
local ipairs = _G.ipairs
module "Core.EventDispatcher"
--[[
数据层次
["EventName1"] =
{
["_StaticFunc"] = { Func1, Func2 },
[Object1] = { Func1, Func2 },
[Object2] = { Func1, Func2 },
},
["EventName2"] =
{
...
}
]]
-- 默认调用函数
local function PreInvoke( EventName, Func, Object, UserData, ... )
if Object then
Func( Object, EventName, ... )
else
Func( EventName, ... )
end
end
function New( )
local NewObj = setmetatable( {}, { __index = package.loaded["Core.EventDispatcher"] } )
-- 对象成员初始?/pre>NewObj.mPreInvokeFunc = PreInvokeNewObj.mEventTable = {}return NewObj
end
-- dfunction Add( Self, EventName, Func, Object, UserData )
assert( Func )Self.mEventTable[ EventName ] = Self.mEventTable[ EventName ] or {}local Event = Self.mEventTable[ EventName ]
if not Object then
Object = "_StaticFunc"
end
Event[Object] = Event[Object] or {}local ObjectEvent = Event[Object]
ObjectEvent[Func] = UserData or trueend
-- 讄调用前回?/pre>function SetDispatchHook( Self, HookFunc )
Self.mPreInvokeFunc = HookFuncend
-- z֏function Dispatch( Self, EventName, ... )
assert( EventName )local Event = Self.mEventTable[ EventName ]
for Object,ObjectFunc in pairs( Event ) doif Object == "_StaticFunc" thenfor Func, UserData in pairs( ObjectFunc ) doSelf.mPreInvokeFunc( EventName, Func, nil, UserData, ... )end
else
for Func, UserData in pairs( ObjectFunc ) doSelf.mPreInvokeFunc( EventName, Func, Object, UserData, ... )end
end
end
end
-- 回调是否存在function Exist( Self, EventName )
assert( EventName )local Event = Self.mEventTable[ EventName ]
if not Event then
return false
end
-- 需要遍历下map, 可能有事件名存在, 但是没有M回调?/pre>for Object,ObjectFunc in pairs( Event ) dofor Func, _ in pairs( ObjectFunc ) do-- 居然有一?/pre>return true
end
end
return false
end
-- 清除function Remove( Self, EventName, Func, Object )
assert( Func )local Event = Self.mEventTable[ EventName ]
if not Event then
return
end
if not Object then
Object = "_StaticFunc"
end
local ObjectEvent = Event[Object]
if not ObjectEvent then
return
end
ObjectEvent[Func] = nilend
-- 清除对象的所有回?/pre>function RemoveObjectAllFunc( Self, EventName, Object )
assert( Object )local Event = Self.mEventTable[ EventName ]
if not Event then
return
end
Event[Object] = nilend
q里注意? 我是EventDispatcher.lua攄在Core目录? 因此需要用require “Core.EventDispatcher”进行调?/p>
使用用例
local EventDispatcher = require 'Core.EventDispatcher'
local E = EventDispatcher.New()
E:Add( "a", function( a, b ) print( a, b ) end )
local Func = function( a ) print( a ) end
E:Add( "a", Func )
E:Dispatch("a", 1, 2 )
print( E:Exist("a"), E:Exist("b"))
E:Remove("a", Func )
E:Dispatch("a", 1, 2 )
print( E:Exist("a"), E:Exist("b"))
Private Sub ConvFile(InputFile As String, OutputFile As String)
Dim ReadStream As Object
Set ReadStream = CreateObject("ADODB.Stream")
Dim FileContent As String
With ReadStream
.Type = 2 'adTypeText
.Charset = "UNICODE"
.Open
.LoadFromFile InputFile
FileContent = .ReadText
.Close
End With
Set ReadStream = Nothing
Dim WriteStream As Object
Set WriteStream = CreateObject("ADODB.Stream")
With WriteStream
.Type = 2 'adTypeText
.Charset = "UTF-8"
.Open
.WriteText FileContent
.SaveToFile OutputFile, 2 'adSaveCreateOverWrite
.Flush
.Close
End With
Set WriteStream = Nothing
End Sub
上半截是d文g, 下半截是写入文g, 需要{换不同格? 误行更?/p>
ServicePath=/usr/local/bin ServiceList=( "wkcenterd --toc /home/davy/dev/kaze/Config/CenterService.toc --logfile /tmp/centerd.log" "wkagentd --toc /home/davy/dev/kaze/Config/AgentService.toc --logfile /tmp/agentd.log" ) StartAll() { for((i = 0;i<${#ServiceList[*]};i=i+1)) do echo "start:" $ServicePath/${ServiceList[i]} $ServicePath/${ServiceList[i]} > /dev/null & done } StopAll() { for((i = 0;i<${#ServiceList[*]};i=i+1)) do echo "stop:" $ServicePath/${ServiceList[i]} svcname=`echo ${ServiceList[i]} | awk '{print $1}'` killall $svcname > /dev/null done } RestartAll() { StopAll StartAll } InstallService() { svcname=`basename $0` chmod +x $svcname cp $svcname /etc/init.d ln /etc/init.d/$svcname /etc/rc3.d/S03$svcname ln /etc/init.d/$svcname /etc/rc0.d/K03$svcname chkconfig --add $svcname chkconfig $svcname on chkconfig --list | grep $svcname } UninstallService() { svcname=`basename $0` chkconfig --del $svcname rm -f /etc/init.d/$svcname rm -f /etc/rc3.d/S03$svcname rm -f /etc/rc3.d/K03$svcname } case "$1" in start) StartAll ;; stop) StopAll ;; restart) RestartAll ;; install) InstallService ;; uninstall) UninstallService ;; *) echo "Usage: service $EXEC {install|start|stop|restart|uninst}" exit 1 esac exit $?
另外一U获取方法是table.getn(obj), 但是q个Ҏ已经标记为废除了, 量使用通用且简z的#操作W?/p>
使用lua api实现此功能就需要用到lua_objlen( ),但是q个功能未在luabind中提?所以我们顺手添加一?/p>
首先扑ֈluabind源码的object.hpp中取对象cd的type函数,在其下添加以下代?/p>
重新~译你的代码, 可以这样用luabind::obj_size( obj ) 获取对象大小?img src ="http://www.shnenglu.com/sunicdavy/aggbug/169178.html" width = "1" height = "1" />1: template<class ValueWrapper>2: inline int obj_size(ValueWrapper const& value)3: {4: lua_State* interpreter = value_wrapper_traits<ValueWrapper>::interpreter(5: value6: );7:8: value_wrapper_traits<ValueWrapper>::unwrap(interpreter, value);9: detail::stack_pop pop(interpreter, 1);10: return lua_objlen(interpreter, -1);
11: }
1: void ScriptManagedChannel::OnServiceInitialize()
2: {
3: try
4: {
5: mThread = lua_newthread( GScriptScriptContext->GetVM() );
6:
7: luabind::resume_function<void>( mThread, "ScriptMain", this );
8:
9: Resume();
10: }
11: catch (std::exception& e)
12: {
13: const char* ErrorMsg = lua_tostring( GScriptScriptContext->GetVM(), -1 );
14: printf("%s\n", e.what() );
15: }
16:
17:
18: }
19:
20: void ScriptManagedChannel::Resume( )
21: {
22: luabind::resume<void>( mThread );
23: }
24:
25: void ScriptManagedChannel::StopTest( )
26: {
27: lua_yield( mThread, 0 );
28: }
29:
30:
代码? mThreadcd为lua_State*cd
GScriptScriptContext->GetVM()是加载了代码的lua_State*
StopTest为注册ؓScriptManagedChannelcL员函数到lua中的定义
接下来看lua端的试代码:
1: function ScriptMain( Channel )
2:
3:
4: for i = 1, 5 do
5:
6: print("done", i)
7:
8: Channel:StopTest( )
9:
10:
11:
12: end
13: end
刚开?在测试代码时, lua中有个手误而造成的错? DC++代码q行到第7行时弹出assert
位于:luabind-0.9.1\luabind\detail\call_function.hpp W?64?对应以下代码W?3?/p>
1: ~proxy_function_void_caller()
2: {
3: if (m_called) return;
4:
5: m_called = true;
6: lua_State* L = m_state;
7:
8: int top = lua_gettop(L);
9:
10: push_args_from_tuple<1>::apply(L, m_args);
11: if (m_fun(L, boost::tuples::length<Tuple>::value, 0))
12: {
13: assert(lua_gettop(L) == top - m_params + 1);
14:
15: NO_EXCEPTIONS
16: throw luabind::error(L);
17: #else
18: error_callback_fun e = get_error_callback();
19: if (e) e(L);
20:
21: assert(0 && "the lua function threw an error and exceptions are disabled."
22: " If you want to handle the error you can use luabind::set_error_callback()");
23: std::terminate();
24: #endif
25: }
26: // pops the return values from the function call
27: stack_pop pop(L, lua_gettop(L) - top + m_params);
28: }
11行代码中调用的是lua_resume, q回的是q行错误, 但是?3行的assert挡住? 无法通过W?6行抛出异常被外面捕获.
因此,试注释W?3?/strong>, 再测? 可以在lua抛出错误? 在栈捕获到coroutine函数resume时报出的错误信息.问题解决
对于lua的coroutine, |上资料不多, q里有一比较详l的代码
我比较疑惑的? 有没有必要将代码在dofile或者dobuffer? 必须传入newthread出的state? 如果q是传入原始的state会有什么媄?
Ƣ迎各位有此l验的讨?/p>
废话不多? 看代?/p>
1: -- 创徏沙盒
2: function SpawnSandBox( )
3:
4: local SandBoxGlobals = {}
5:
6: -- 基础函数d
7: SandBoxGlobals.print = print
8: SandBoxGlobals.table = table
9: SandBoxGlobals.string = string
10: SandBoxGlobals.math = math
11: SandBoxGlobals.assert = assert
12: SandBoxGlobals.getmetatable = getmetatable
13: SandBoxGlobals.ipairs = ipairs
14: SandBoxGlobals.pairs = pairs
15: SandBoxGlobals.pcall = pcall
16: SandBoxGlobals.setmetatable = setmetatable
17: SandBoxGlobals.tostring = tostring
18: SandBoxGlobals.tonumber = tonumber
19: SandBoxGlobals.type = type
20: SandBoxGlobals.unpack = unpack
21: SandBoxGlobals.collectgarbage = collectgarbage
22: SandBoxGlobals._G = SandBoxGlobals
23:
24: return SandBoxGlobals
25: end
26:
27: -- 在沙盒内执行脚本, 出错时返回错? nil表示正确
28: function ExecuteInSandBox( SandBox, Script )
29:
30: local ScriptFunc, CompileError = loadstring( Script )
31:
32: if CompileError then
33: return CompileError
34: end
35:
36: setfenv( ScriptFunc, SandBox )
37:
38: local Result, RuntimeError = pcall( ScriptFunc )
39: if RuntimeError then
40: return RuntimeError
41: end
42:
43: return nil
44: end
45:
46: function ProtectedFunction( )
47: print("protected func")
48: end
49:
50:
51: local SandBox = SpawnSandBox( )
52:
53:
54: print ( "Response=", ExecuteInSandBox( SandBox, "table.foreach( _G, print )" ) )
55:
56: print ( "Response=", ExecuteInSandBox( SandBox, "ProtectedFunction()" ) )
57:
58: SandBox.ProtectedFunction = ProtectedFunction
59:
60: print ( "Response=", ExecuteInSandBox( SandBox, "ProtectedFunction()" ) )
54行执行结果是
1: _G table: 00421258
2: string table: 00421050
3: pairs function: 00567F58
4: collectgarbage function: 005675F0
5: unpack function: 004217E8
6: assert function: 005675B0
7: print function: 00567830
8: ipairs function: 00567F28
9: type function: 004217A8
10: tonumber function: 00421768
11: tostring function: 00421788
12: table table: 00420DA8
13: math table: 004210C8
14: setmetatable function: 00421748
15: getmetatable function: 00567710
16: pcall function: 005677F0
17: Response= nil
q里是一个Shell可以依赖列表中的文件拷贝到指定目录
deplist=$( ldd $1 | awk '{if (match($3,"/")){ print $3}}' )
cp $deplist $2
代码解释: ldd导出列表, q个列表打印出来很丑
linux-gate.so.1 => (0x00ed2000)
liblog4cpp.so.4 => /usr/local/lib/liblog4cpp.so.4 (0x00657000)
libprotobuf.so.7 => /usr/local/lib/libprotobuf.so.7 (0x00360000)
libboost_filesystem.so.1.48.0 => /usr/local/lib/libboost_filesystem.so.1.48.0 (0x00a9a000)
libboost_program_options.so.1.48.0 => /usr/local/lib/libboost_program_options.so.1.48.0 (0x00110000)
libboost_system.so.1.48.0 => /usr/local/lib/libboost_system.so.1.48.0 (0x00a85000)
libboost_thread.so.1.48.0 => /usr/local/lib/libboost_thread.so.1.48.0 (0x00179000)
libunwind-x86.so.7 => /usr/lib/libunwind-x86.so.7 (0x00821000)
libluabindd.so.0.9.0 => /usr/local/lib/libluabindd.so.0.9.0 (0x00bb3000)
libmysqlpp.so.3 => /usr/local/lib/libmysqlpp.so.3 (0x00de5000)
libstdc++.so.6 => /usr/lib/i386-linux-gnu/libstdc++.so.6 (0x001a9000)
libm.so.6 => /lib/i386-linux-gnu/libm.so.6 (0x00782000)
libgcc_s.so.1 => /lib/i386-linux-gnu/libgcc_s.so.1 (0x00aea000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0x00447000)
libpthread.so.0 => /lib/i386-linux-gnu/libpthread.so.0 (0x00abd000)
librt.so.1 => /lib/i386-linux-gnu/librt.so.1 (0x00193000)
libnsl.so.1 => /lib/i386-linux-gnu/libnsl.so.1 (0x00294000)
libunwind.so.7 => /usr/lib/libunwind.so.7 (0x002ab000)
libdl.so.2 => /lib/i386-linux-gnu/libdl.so.2 (0x00e8a000)
libmysqlclient_r.so.16 => /usr/lib/libmysqlclient_r.so.16 (0x0083b000)
/lib/ld-linux.so.2 (0x00608000)
libz.so.1 => /lib/i386-linux-gnu/libz.so.1 (0x002c0000)
我们发现W一行的so没有对应的库地址, 因此我们使用awk的脚本功?判断W三个参?也就?>之后的\径必d?
之后第一行的输出重定向到变量? 再用cp指o从列表拷贝到指定目录
BuildProtoCC.bat
@echo off
set protofile=%1%.proto
set output_cc=%1%.pb.cc
"protoc.exe" %protofile% --cpp_out .
@echo 使用%protofile%生成%output_cc%
if exist "pchheader.txt" goto 合ƈ预编译头 else echo pchheader.txt NOT EXIST
:合ƈ预编译头
@echo 试删除以前的中间文?br>del *.pched
@echo 合ƈ~译头文件pchheader.txt到生?output_cc%
copy pchheader.txt+"%output_cc%" "%output_cc%.pched" /y
@echo {待protoc.exel束
@ping -n 2 127.1>nul
echo 清理文g
del "%output_cc%"
ren "%output_cc%.pched" "%output_cc%"
q段批处理这样?
假设你有一个叫login.proto文g和批处理攑֜一?
在同一目录再放|一个pchheader.txt文g,q在里面写入#include "stdafx.h?
调用一下批处理
call BuildProtoCC.bat login
注意login不能带后~
用protoc.exe生成login.pb.cc和login.pb.h 然后使用批处理合q文件功能自动合q~译?
不过官网也提到过ActionScript3的支?点击?a >q里
protobuf-actionscript3包括ActionScript3的序列号及反序列化的as源码.以及protoc的as3代码生成器的C++代码
另外, protobuf-actionscript3q需要一个加密库as3crypto支持,需要一q下?/p>
当然, protobuf 库也是最重要?
下面说明如何~译出支持as3的protoc代码生成?
1. protobuf-actionscript3库中compiler\as3目录拯到protobuf库的src\google\protobuf\compiler?目录l构如下:
as3\
cpp\
java\
python\
code_generator.cc
command_line_interface.cc
...
2.打开protobuf工程中的sln, 在libprotocd刚才d的as3目录下的所有文?/p>
3. 在protoc工程的main.cc中添?/p>
google::protobuf::compiler::as3::As3Generator as3_generator; cli.RegisterGenerator("--as3_out", &as3_generator, "Generate ActionScript source file.");
4. 打开as3_file.h
注释掉以下代?/p>
namespace protobuf { class FileDescriptor; // descriptor.h namespace io { class Printer; // printer.h } namespace compiler { class OutputDirectory; // code_generator.h } }
包含内添?/p>
#include <google/protobuf/stubs/common.h> #include <google/protobuf/compiler/code_generator.h> #include <google/protobuf/io/printer.h>
5. ~译出protoc.exe
6. 准备proto文g, 使用protoc.exe使用cMCPP生成的方式进行生?/pre>7. protobuf-actionscript里的as3-lib及下载好的加密的swc整合到自qflash工程卛_开始?/pre>
]]>
N脚本可以说是Lua的超U增强版,作者在Crysis目使用Lua多年,qLua的优~点.之后自己~写了松鼠脚本来解决诸如class,attribute,delegation,更强大的thread,exception{等功能.
N脚本本n对Windows开发h员极为照?W三方库可谓丰富,q程调试,代码加色及语法检查都可以直接在VS2008的IDE中进?
单的q程调试功能需要以下步?
1. 下蝲N脚本3.0版本
2. ?a >N脚本Wiki中下?a >SQDBGq程调试?/a>
3. sqdbg工程攑ֈSQUIRREL3之下,打开SQUIRREL3\squirrel.sln,sqdbgd到工E?~译所?/p>
4. 在这个Solution?创徏一个SquirrelN工程
5. 在新创徏的松鼠工E属性中如下图设|?/p>
Interpreter其实是启动调试?不是sq.exe)
WorkingDirectory 是main.nut所在的目录(官网的\径设|有点误?
Command Line Options 是传入sqdbg.exe的命令行参数
修改下main.nut文g,例如:
for(local i = 1;i<10;i++)
{
print( i );
}
在print语句前打上断?调试N工程,卛_看到调试l果
有关于SQDBG多文件调?
SQDBG默认只能调试1个文?昄是个玩具,不能应对游戏和其他领域的多文件调? 分析了下SQDBG的代?/p>
1: int main(int argc, char *argv[])
2: {
3: if(argc < 2){
4: scprintf(_SC("SQDBG error : no file specified"));
5: return -1;
6: }
7:
8: HSQUIRRELVM v = sq_open(1024);
9: sqstd_seterrorhandlers(v);
10:
11: //!! INITIALIZES THE DEBUGGER ON THE TCP PORT 1234
12: //!! ENABLES AUTOUPDATE
13: HSQREMOTEDBG rdbg = sq_rdbg_init(v,1234,SQTrue);
14: if(rdbg) {
15:
16: //!! ENABLES DEBUG INFO GENERATION(for the compiler)
17: sq_enabledebuginfo(v,SQTrue);
18:
19: sq_setprintfunc(v,printfunc,errorfunc);
20:
21: //!! SUSPENDS THE APP UNTIL THE DEBUGGER CLIENT CONNECTS
22: if(SQ_SUCCEEDED(sq_rdbg_waitforconnections(rdbg))) {
23: scprintf(_SC("connected\n"));
24:
25: const SQChar *fname=NULL;
26: #ifdef _UNICODE
27: SQChar sTemp[256];
28: mbstowcs(sTemp,argv[1],(int)strlen(argv[1])+1);
29: fname=sTemp;
30: #else
31: fname=argv[1];
32: #endif
33: //!!REGISTERS STANDARDS LIBS
34: sq_pushroottable(v);
35: sqstd_register_bloblib(v);
36: sqstd_register_iolib(v);
37: //!!EXECUTE A SCTIPT
38: if(SQ_FAILED(sqstd_dofile(v,fname,SQFalse,SQTrue))) {
39: PrintError(v);
40: _getch();
41: }
42: }
43: //!! CLEANUP
44: sq_rdbg_shutdown(rdbg);
45: }
46: else {
47: PrintError(v);
48: }
49: sq_close(v);
发现写这个库的老外q是很认真的,使用了sq_rdbg作ؓdebugger的api前缀,意味着q个库代码是可以复用?
sqstd_dofile(v,fname,SQFalse,SQTrue)
q就是SQDBG只能debug 1个文件的原因.
如果需要在目中做q程调试,只需要将q句代码换ؓ工程中加载所有脚本的代码和注册系lAPI代码卛_
当然,最单的Ҏ,直接在代码顶端添加dofile引用另外的代码即?/p>
1. Lua
Lua用了5,6q的样子,从LuaPlus到lua-tinker再到lua_bind. 虽然lua本n很小巧方?但是其不支持面向对象Ҏ?让很多h在用时模拟了很多面向对象的Ҏ?但是q种做法在调试时直是噩梦.
我觉得游戏脚本最好是能预~译成byte code,让编译器在编译期很多的bug暴露出来,而不是像lua那样.很多I问错误必要{到runtime才能暴露.让调试效率大大降?q点,mono C#是极好的选择.
2. Mono
׃Unity的流?Mono被带入游戏开发者的视线?其内|的很多pȝ脚本都是用C#写成,而且逻辑脚本用C#~写也是非常清晰严}?
据说Mono在Windows下编译异帔R?而且嵌入方式也没有太多例?现在q块严重~Z资料.
3. V8
Google V8正是׃Chrome而风靡v?直接JIT方式是Chrome速度飞快的原?
最qdown了一个下来试了下,果然名不虚传,API也非常的易用.不过׃不是很熟悉JavaScript的原? 自己用scons~译Z个v8的shell,跑了一个带cȝ承的例子,居然不识别class关键?q才感叹q不如用y的lua?在我看来,JavaScript与Lua比较,也就是个能new,但是没class的语a.也被别hUCؓ半吊子面向对?都是使用prototype方式来实现类功能.
4. JavaScriptCore
在Google V8的类试壁?马上研究了下Unity下的JavaScript到底用了什么库,没错是Apple Safari里的JavaScriptCore. q东西资料比Monoq少,都是高龄库了.惛_整合不是一般的ȝ.但是q是不确定这个脚本引擎是否原生支持类
5. Python
Python? 没想q这U格式诡异的语言,正如Unity里支持Boo(一U很cMPython的语a)很少有h用一? 上次用过Python是在一个buildpȝ? 游戏里是不会考虑q种脚本pȝ?效率也是很大的原?
6. AngleScript, GameMonkey
q两U语a都是很老的游戏脚本语言,不过都是cc++方式?不过׃目使用不多,或许是有一定的bug,资料也相对较?所以可能最后考虑
更新了文档(q是必须的)
新的无符h数C API
位处理函数重命名
更好及更快的支持双精度QҎ转换为整?/strong>
原文在此
可以看到Q我在年初发文指出的lua数字处理斚w的bug已经得到很好的解冻I不过q种解决Ҏ只是d了api而已Q看来还是没有松鼠脚本处理的dQ原?a href="http://www.shnenglu.com/sunicdavy/archive/2010/02/04/107161.html">在此
1. LEffectpȝQ改用HLSL + 渲染脚本
2. 优化渲染接口Q用材质统一shader和渲染状?/p>
随即参考了DirectX SDK的Graphics部分文档QDirectX9 时代的EffectpȝUa只是一个HLSL的简单渲染脚本实玎ͼ除了DXUTQFXComposer{极程序用这套东西外Q大型的引擎很少使用q种半成品系l。到了DirectX10甚至11Q因为架构更改,L固定线Q因此Effect成ؓ较ؓ高效和便L渲染脚本Q如果不是要求较高的3d引擎Q一般的游戏使用DirectX10的Effect渲染脚本q是很不错的?/p>
DX10的fx脚本与DX9的差异在?/p>
渲染状态,采样器状态等都变为对象,q与API高度l一
在脚本与API中均可以讄
DepthStencilState EnableDepth
{
DepthEnable = TRUE;
DepthWriteMask = ALL;
DepthFunc = LESS_EQUAL;
};
BlendState NoBlending
{
AlphaToCoverageEnable = FALSE;
BlendEnable[0] = FALSE;
};
technique10 Render
{
pass P0
{
SetDepthStencilState( EnableDepth, 0 );
SetBlendState( NoBlending, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );
}
}
本h觉得Q这L设计让图形API更ؓ敏捷与归cdQ另外,也便于StateManager或者自己做渲染状态{Ud差异比较时更为高?
Vista操作pȝ推出很久后,DX10的显卡也占有了大量的市场份额。但是由于DX10仍然是一个过渡APIQ类gDX8)Q因此,很多3D游戏要么仍然支持DX9Q要不然x持DX9也支持DX10Q甚至DX11.
看博客上有达人组团编写类似DX10接口和系l的软渲染,DX10的设计是优秀的。因此,在DX9 HLSL基础上,l合自己~写的渲染脚本会是非常好的选择?
渲染脚本我的设计思\是这LQ?
1. 只是一U预处理脚本Qƈ非实时运行脚本?
~译器将文本解析后,转化Z些运行指令,比如Q本pass使用一块小U理Q下一pass的target是这个纹理,q且开启哪些渲染状态?
2. 自定义格式的解析脚本?
使用luaQpython{脚本其实也是可以的。但是在出现错误Ӟ报出的错可能会让不熟悉这个脚本语a的h莫名其妙?
使用Nsq脚本语言Q可惜其在lua基础上,对table的slot初次赋值时必须使用<-而不是统一使用=Q因此会让你的脚本稀奇古?
XML脚本Q?XML可以避免复杂的语法检查,写完是归整的,但也是罗嗦的Q本来Texture[2]可以表达完毕的,非要<Texture index = 2/>来罗嗦下?
OGRE的compositor脚本和材质脚本就是自p析的Q不q出乎预料的使用了BNF范式q类较ؓ正规的方法。这是_需要先解析BNF表达式,然后再输入脚本解析,~写q程和系l复杂度会变得异常复杂?
最l选择q是使用自己解析的脚本,使用一些具体代码结构来替代BNFq类高深的东?
军_以后Q下一步需要制定渲染脚本具体各部分及制作过E?
1. 基本lexer
从文本得到各Utoken
1. 渲染状态对?
照着DX10抄就?
2. Shader导入?
shader文g来自于何处,入口怎样定义
3. 渲染脚本VM及指?
军_一个纹理怎样讄QRenderTarget怎样使用{的指o
LemonpȝҎ:
1. 支持 Canvas,Sprite,ImageSetQ图片存储于一张图片,{大)
2. ImageSetExQ自由摆攄囄帧于一张图片)*
3. 支持对象无关键时用静态属性进行设|,cM于HGE里的_
4. 每个对象均可成ؓContainerQƈ拥有Child Node
5. 动画关键帧类型支持:~放Q旋转,位移Q颜Ԍ动画帧,锚点Q音?
6. 支持拑֏
7. ZXML存储的文件格?/p>
8. ZSquirrelN脚本的高速面向对象脚?
9. 囑ŞpȝGraphics抽象Q适用于Q何渲染设?/p>
10. 控gpȝ*
11. 视频回放*
所有对象均由RTTI创徏Q枚丑֝有NamePool+HashQƈ׃PropertySet的反系l?/p>
LemonComposer~辑器特?/p>
界面Z我去q开发的MotionUIQlua
8+1控制点点对象调节属?/p>
cAdobe Flash的~辑?/p>
c?DS Max的分轨道关键帧编辑,有助于优化art assert
自由调节对象层及父子关p?/p>
全功能无限制自由Redo,Undo
*在未来版本支持
2D游戏是独立游戏的LQ也是创意,投入比最的一个维度。但是基?D的大多是一些类gHGEQIndieLib{开源免?D引擎。但是面Ҏ戏中大量的动画而言Q开发者大多是使用囄帧来制作Q虽然效果很好,但是讑֤资源好用和制作难度也是很难控制的?/p>
行于去q的植物对僵和2004q发行的RO Offlinel过资源分析Q就是用类gLemonpȝQ或者说Flash的系l制作而成Q因此效果和扩展性非常好?/p>
q就是Lemon存在的理由?/p>
Flash面向的是GDI+WebQ那么Lemon是针对游戏专有的,Zg加速的游戏框架
Flash Action Script 对应的就是Lemon?a >Squirrel脚本
FlashIDE 对应的就是Lemon Composer
Lemon的目标就是让2D游戏开发更单,让游戏中充满更多的动? 让游戏开发难度降?/p>
例子Q?/p>
for /r publish\ui\ %%i in (*.lua) do luac -o %%i %%i
lua中,数g用double来存储,包含整Ş和double。而解析出来的整Ş也是被强转ؓdoubleq行存储Q这样就会出问题?/p>
举一个简单的例子Q?/p>
double f = (double)0xffffffff;
int a = int(f);
q里的文章说明这个类型{换问题的~由?/p>
?a >Squirrel脚本中就不会有这个问?/p>
local a = 0xffffffff
print( a )
l果?1
查看其源代码Q?/p>
typedef union tagSQObjectValue
{
struct SQTable *pTable;
struct SQArray *pArray;
struct SQClosure *pClosure;
struct SQGenerator *pGenerator;
struct SQNativeClosure *pNativeClosure;
struct SQString *pString;
struct SQUserData *pUserData;
SQInteger nInteger;
SQFloat fFloat;
SQUserPointer pUserPointer;
struct SQFunctionProto *pFunctionProto;
struct SQRefCounted *pRefCounted;
struct SQDelegable *pDelegable;
struct SQVM *pThread;
struct SQClass *pClass;
struct SQInstance *pInstance;
struct SQWeakRef *pWeakRef;
SQRawObjectVal raw;
}SQObjectValue;
可以看到
SQInteger nInteger;
SQFloat fFloat;
是分开存储的,因此׃会有q个问题
lua解决ҎQ?/p>
1. 十六进制换?0q制存储
2. {待大侠或者官方修改代码,做出patch
lua代码Q?/p>
t = {}
t.FillColor = 0xFFFFFFFF
foo( t )
在C++中注册一个foo函数Q然后获取table t中的FillColor成员
发现取得的值居然ؓ0x80000000
使用lua c api试代码
lua_newtable( L );
lua_setglobal( L, "t");
lua_getglobal( L, "t");
lua_pushstring(L,"FillColor");
lua_pushinteger( L, 0xffffffff );
lua_pushinteger( L, -1 );
lua_settable( L, -3 );
lua_getglobal( L, "t");
lua_pushstring( L, "FillColor");
lua_gettable( L, -2 );
int t = lua_tointeger( L, -1 );
l果t也是0x80000000
然后十六进制的0xFFFFFFFF换成十进制的4294967295Q测试结果正显C?1
再用几个样本测?
0xFF5F5F5F = 4284440415 会被Ҏ0xFF5F5F00
q个bug倒是很好解决Q将代码中的十六q制数全换ؓ10q制卛_。但是ؓ什么只在Release版本发生呢?
本h使用的是lua 5.1.4 原生
1. UC API方式导出Q类gWindows API方式
优点Q简z,可以供C/C#乃至其他可以导入C DLL的语a使用
~点QC++的系l{化ؓC会遇到很多性能以及架构的折损,对于对象控制cd能导出比较多的系l,q种方式直是噩梦
2. C++方式导出Q宏方式实现RTTI以及C++反射pȝ
优点Q强大,易用?/p>
~点Q对象生命周期不Ҏ控制Q反系l设计比较费Ӟ可能暴露很多cȝl节Q只能给C++使用
3. COM方式Q类DirectX的接口方?/p>
优点Q商业项目已l证明这U接口方式的强大地方。无论是多个对象的类功能导出Q还是COM接口重蝲都非常方ѝ而且Q可以极为容易的?NET讉K。XBOX SDK里的XUI是采用q种方式Q而且q设计了一套C API搭配的强大C++反射pȝQ支持动态类创徏QRTTIQ动态类型{换等{?/p>
~点Q需要系l注册,不能跨^台。COM标准学习h需要时?/p>
4. 脚本l定
优点Q保持你的系l对外C/C++接口的干净Q简z。通过脚本cȝ定,可以很快的将C++功能注册到脚本中?/p>
~点Q脚本如果没有调试器Q将会让开发中到的棘手问题,甚至于在后期l护pȝ以及pȝ架构大变动变得异常复杂。脚本的性能军_了不能让其做实时处理Q例如:渲染
最l选择下来Q由于有自己的界面系lMotion使用lua的函数绑定的前例Q因此还是决定选择一ƾ脚本语a来做pȝ的对外接口,q里有几个选择Q?/p>
1. Lua
可以说最好的游戏pȝ脚本语言。稳定,高效Qbug几乎没有Q即便有Q普通开发者也是很隑֯觉的Q。配上LuaPlus的强大C++l定pȝQ你的系l开发效率可以提高很多。这里推荐notepad++来做lua开发,E微配置下,弹出提示l你感觉在用Visual StudioQ:Q?/p>
同时需要指出的是,lua的类功能实比较弱。虽然可以用metatable方式来模拟。但D跟native class支持q差很远Q实际开发中Q你能体会出class中的权限控制QprivateQprotectedQ有多么重要?/p>
2. Python
诚然Q这是个最OO的脚本。但是对于游戏,它太慢了。虽然本人只是用python写过一些buildpȝQ但从很多朋友反应的情况来看QPython嵌入游戏pȝQ确实太慢。用Stackless PythonQ?用第三方开源品,q是认准品牌Q呵呵,q里如果有用q的同学Q欢q提供感受?/p>
3. C#
语言和系l都很美Q但是想嵌入游戏Q还是很痛的?netq_可惜在于,到现在ؓ止,可能q不是所有机器默认安装有.netq_。如果你的游戏是C++写成Q但却要安装.net以便你的脚本能运行,q很奇怪吧Q所以,如果要用C#Q还不如不用脚本Q全?net好了。Managed DXQ?那东西几q前pMS打入冷宫了。XNAQ?那东西只是一个玩P别摸?/p>
4.SquirrelN脚本
q是个好东西。类lua的语法,C/C++/Java的语al构Q纯正的native class外加OO支持。拥有开源的C++cȝ定系l。最爽的是,SQDEV支持日食QEclipseQ下的远E调试,开发环境还支持动态语法检查。oh,my god。还说不定哪天这脚本被MS招安Q跟IronPython一样弄?netl定?/p>
q是一个简单的教学Q告诉你Kismet是怎么q行?/p>
http://udn.epicgames.com/Three/KismetUserGuide.html
q是Kismet的资?/p>
http://udn.epicgames.com/Three/KismetReference.html
让我们来熟悉?/p>
q是一个Event节点Q一般用于创入流Q事件可以从Actor或者其他地方进?/p>
q是一个Action节点Q动态的搭接输入条gQ可以快速的输出你需要的l果
q是一个Condition节点Q用于根据输入,输出l果
q是一个普通的变量Q存储Q何可以存储的对象
W一个例子:
q个例子要实现的是,玩家点击后,打开一盏灯
玩家通过Event节点Q生一个输入流Q这个流被连接到ToggerQActionQ的Turn On节点Q注意,黑色的连接线表示“操作流”,而Togger的执行目标被接到了灯上,q样一个简单的逻辑执行出来了
动态绑定事?/p>
有时你需要绑定的对象是不在编辑器里的Q这个例子就是在游戏中动态创Z个ActorQ要解决q个问题Q就必须物体连接到一个变量?/p>
当Actor Factory执行后,其生成一个新的ActorQƈ其攄在一个对象数l中Q图中的问号Q,然后Q他会调用AttachToEvent actionQ将M事gq接到这个变量?那么当这个ActorMӞ事g׃被触发?/p>
先讲q些Q呵呵,吃饭吃饭