minetest源码解析五:IGameDef、ItemDefManager、NodeDefManager类介绍

minetest源码解析五:IGameDefItemDefManagerNodeDefManager类介绍


IGameDef

minetest->gamedef.h

      这个类中主要管理了游戏全局的一些定义。通过这个类接口可以获取它所有管理的对象指针。主要包括了TextureSource、ShaderSource、ItemDefManagerNodeDefManager、CraftDefManager、SoundManagerMtEventManagerRollbackReportSink

这个对象的实例会发现在这个程序中作为参数被传入很多对象中,譬如在一些对象初始化时就传入。

      这个类中的接口没有都实现,且它是一个基类,主要是在Client和Server这两个类中实现的,这两个类都继承了IGameDef。SoundManagerMtEventManager主要在client类中会使用到;RollbackReportSink主要在server这个类中会使用到。


相关涉及类

minetest->server.h

class Server : public con::PeerHandler, public MapEventReceiver, public InventoryManager, public IGameDef


minetest->client.h

class Client : public con::PeerHandler, public InventoryManager, public IGameDef



创建这个对象的位置

game.cpp->the_game()

server = new Server(map_dir, gamespec, simple_singleplayer_mode,bind_addr.isIPv6());


Client client(device, playername.c_str(), password, draw_control, tsrc, shsrc, itemdef, nodedef, sound, &eventmgr, connect_address.isIPv6());


IGameDef *gamedef = &client;



ItemDefManager

minetest->itemdef.h

       这个对象中管理了所有的Item,这里说的Item是指ItemTypenonenodecrafttool这几类的。这里的所有item都能在物品栏中显示出来。涉及到的注册方法时如下几种:

minetest.register_item   type = "none",

core.register_node       nodedef.type = "node"

core.register_craftitem      craftitemdef.type = "craft"

core.register_tool   tooldef.type = "tool"


node craftitemtool 都在物品栏表内,可以在游戏界面下方显示,有些type在游戏上是不能放置,只能使用的。 


注意:如下这种注册craft这种不包括在item中。


minetest.register_craft({

output = 'bucket:bucket_empty 1',

recipe = {

{'default:steel_ingot', '', 'default:steel_ingot'},

{'', 'default:steel_ingot', ''},

}

})


ItemDefManager对象中重要的成员变量m_item_definitions以及m_aliases

std::map<std::string, ItemDefinition*> m_item_definitions;

// Aliases

std::map<std::string, std::string> m_aliases;


    m_item_definitions 是注册时加入的一系列itemsm_aliases是一些item的名字不是一个,为了兼容之前的名字,譬如minetest.register_alias("stone", "default:stone”)


    ItemDefinitionminetest->itemdef.h 是结构体,描述定义item,其中有个ItemType type,这个表示的是item的类型,只有ITEM_NONE,ITEM_NODE,ITEM_CRAFT,ITEM_TOOL这四个值。



NodeDefManager

minetest->nodedef.h


      这个对象主要管理了所有的node,必须是itemType是node类型的,注册的方式时通过core.register_node这种方式的。

NodeDefManager对象中重要的成员变量m_content_features

// Features indexed by id

std::vector<ContentFeatures> m_content_features;

m_content_features是一系列node


   ContentFeaturesminetest->node.h)是结构体,这里主要是node的一些特性,譬如tiles、name、pointable(玩家能指向它)、diggable(玩家能挖掉它)、liquid_typerightclickableselection_boxdamage_per_second等等这些。其中有个NodeDrawType drawtype,这里代表有14种node类型,每种类型显示的方式时不一样的,具体类型如下NDT_NORMAL, NDT_AIRLIKE, NDT_LIQUID,NDT_FLOWINGLIQUID,NDT_GLASSLIKE, NDT_ALLFACES, NDT_ALLFACES_OPTIONAL, NDT_TORCHLIKE, NDT_SIGNLIKE, NDT_PLANTLIKE, NDT_FENCELIKE, NDT_RAILLIKE, NDT_NODEBOX, NDT_GLASSLIKE_FRAMED



ItemDefManager、NodeDefManager读入值流程图


minetest源码解析五:IGameDef、ItemDefManager、NodeDefManager类介绍


流程图中核心API说明


1.the_game():创建服务器

minetest->game.cpp->the_game()

server = new Server(map_dir, gamespec, simple_singleplayer_mode, bind_addr.isIPv6());


2.Initialize scripting


minetest->server.cpp


m_script = new GameScripting(this);

初始化过程中注册了一系列函数,lua文件中调用C函数。譬如注册了lua文件中的register_item_raw对应调用的C函数是l_register_item_raw()


主要操作流程是new Server()->new GameScripting()->GameScripting::InitializeModApi(L, top)->ModApiItemMod::Initialize(L, top)->ModApiBase::registerFunction()


涉及到的函数

minetest->script->scripting_game.cpp

GameScripting::GameScripting(Server* server)

{

// Initialize our lua_api modules

InitializeModApi(L, top);

}


void GameScripting::InitializeModApi(lua_State *L, int top)

{

// Initialize mod api modules

ModApiItemMod::Initialize(L, top);

}


minetest->script->lua_api->l_item.cpp

void ModApiItemMod::Initialize(lua_State *L, int top)

{

API_FCT(register_item_raw);        

API_FCT(register_alias_raw);

API_FCT(get_content_id);

API_FCT(get_name_from_content_id);

}

register_item_raw 主要是core.register_item中调用


minetest->script->lua_api->l_internal.h

#define API_FCT(name) registerFunction(L, #name, l_##name,top)


minetest->script->lua_api->l_base.cpp

bool ModApiBase::registerFunction(lua_State *L, const char *name, lua_CFunction fct, int top) 

{

//TODO check presence first!

lua_pushstring(L,name);

lua_pushcfunction(L,fct);

lua_settable(L, top);

。。。

}


3.加载脚本m_script->loadScript(scriptpath)

minetest->script->cpp_api->s_base.cpp->bool ScriptApiBase::loadScript(const std::string &scriptpath)->luaL_loadfile(L, scriptpath.c_str()) || lua_pcall(L, 0, 0, m_errorhandler)


执行这个路径下的lua文件 */MineT.app/Contents/Resources/share/builtin/init.lua init.lua会相应调用game文件夹中的init.lua,从而会调用到 */MineT.app/Contents/Resources/share/builtin/game/register.lua。

以下是这个文件register.lua中的部分代码,可以知道加载这个文件时会执行register_item_raw(itemdef),从而调用在脚本初始化时注册的register_item_raw对应的C函数是l_register_item_raw


function core.register_item(name, itemdef)

。。。

register_item_raw(itemdef)

end



core.register_item(":unknown", {

type = "none",

description = "Unknown Item",

inventory_image = "unknown_item.png",

on_place = core.item_place,

on_drop = core.item_drop,

groups = {not_in_creative_inventory=1},

diggable = true,

})


此时会加载这里的4个item。


4.调用C函数l_register_item_raw

minetest->script->lua_api->l_item.cpp->ModApiItemMod::l_register_item_raw(lua_State *L)

获取服务端的ItemDefManager以及INodeDefManager指针,从栈中读取item definition值并设置值。


涉及函数

// Register item definition

idef->registerItem(def);

// Read the node definition (content features) and register it

if(def.type == ITEM_NODE)

{

ContentFeatures f = read_content_features(L, table);

content_t id = ndef->set(f.name, f);

}


5.加载脚本m_script->loadMod()

minetest->script->cpp_api->s_base.cpp

bool ScriptApiBase::loadMod(const std::string &scriptpath, const std::string &modname)

检查mod 的name并加载mod中的init文件,如init.lua内容如下,代表注册了一个node,并按照函数要求传入了一些参数。函数定义是在builtin/game/register.lua中的core.register_node。执行init.lua文件,执行到minetest.register_node,等于去执行builtin/game/register.lua中的core.register_node,然后通过core.register_item执行register_item_raw,从而执行对应C函数完成item数据读入的。

minetest.register_node("tutorial:decowood", {

    description = "decowood",

tiles = {"tutorial_decowood.png"},

groups = {snappy=1,choppy=2,oddly_breakable_by_hand=2,flammable=3},

})


function core.register_node(name, nodedef)

nodedef.type = "node"

core.register_item(name, nodedef)

end


function core.register_item(name, itemdef)

。。。

register_item_raw(itemdef)

end