// Copyright 2008-2018 Yolo Technologies, Inc. All Rights Reserved. https://www.comblockengine.com

#include "kbcmd.h"
#include "client_sdk.h"
#include "client_sdk_cxx.h"
#include "entitydef/entitydef.h"
#include "entitydef/scriptdef_module.h"
#include "entitydef/property.h"
#include "entitydef/method.h"
#include "entitydef/datatype.h"
#include "network/fixed_messages.h"

namespace KBEngine {	

static std::string headerBody = "/*\n\tGenerated by KBEngine!\n\tPlease do not modify this file!\n#REPLACE#\ttools = kbcmd\n*/\n\n";
static std::string moduleSuffix = "Base";
static std::string ConflictTypePrefix = "KBE_";
static std::string namespaceNameBegin = "namespace KBEngine\n{\n\n";
static std::string namespaceNameEnd   = "\n}";

//-------------------------------------------------------------------------------------
ClientSDKCXX::ClientSDKCXX():
	ClientSDK(),
	initBody_(),
	contextHeader_(true)
{
}

//-------------------------------------------------------------------------------------
ClientSDKCXX::~ClientSDKCXX()
{

}

//-------------------------------------------------------------------------------------
std::string ClientSDKCXX::typeToType(const std::string& type)
{
	if (type == "INT8")
	{
		return "int8";
	}
	else if (type == "INT16")
	{
		return "int16";
	}
	else if (type == "INT32")
	{
		return "int32";
	}
	else if (type == "INT64")
	{
		return "int64";
	}
	else if (type == "UINT8")
	{
		return "uint8";
	}
	else if (type == "UINT16")
	{
		return "uint16";
	}
	else if (type == "UINT32")
	{
		return "uint32";
	}
	else if (type == "UINT64")
	{
		return "uint64";
	}
	else if (type == "FLOAT")
	{
		return "float";
	}
	else if (type == "DOUBLE")
	{
		return "double";
	}
	else if (type == "STRING")
	{
		return "KBString";
	}
	else if (type == "UNICODE" || type == fmt::format("{}UNICODE", ConflictTypePrefix))
	{
		return "KBString";
	}
	else if (type == "PYTHON")
	{
		return "KBArray<uint8>";
	}
	else if (type == "PY_DICT")
	{
		return "KBArray<uint8>";
	}
	else if (type == "PY_TUPLE")
	{
		return "KBArray<uint8>";
	}
	else if (type == "PY_LIST")
	{
		return "KBArray<uint8>";
	}
	else if (type == "BLOB")
	{
		return "KBArray<uint8>";
	}
	else if (type == "ARRAY")
	{
		return "KBArray";
	}
	else if (type == "FIXED_DICT")
	{
		return "KBMap";
	}
#ifdef CLIENT_NO_FLOAT
	else if (type == "VECTOR2")
	{
		return "KBVector2f";
	}
	else if (type == "VECTOR3")
	{
		return "KBVector2f";
	}
	else if (type == "VECTOR4")
	{
		return "KBVector3f";
	}
#else
	else if (type == "VECTOR2")
	{
		return "KBVector2f";
	}
	else if (type == "VECTOR3")
	{
		return "KBVector3f";
	}
	else if (type == "VECTOR4")
	{
		return "KBVector4f";
	}
#endif
	else if (type == "ENTITYCALL")
	{
		return "KBArray<uint8>";
	}

	return type;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::getArrayType(DataType* pDataType, std::string& outstr)
{
	if (pDataType->type() == DATA_TYPE_FIXEDARRAY)
	{
		FixedArrayType* pFixedArrayType = static_cast<FixedArrayType*>(pDataType);

		// 如果元素又是数组
		if (pFixedArrayType->getDataType()->type() == DATA_TYPE_FIXEDARRAY)
		{
			if (outstr.size() > 0)
				strutil::kbe_replace(outstr, pDataType->aliasName(), fmt::format("KBArray<{}>", pFixedArrayType->getDataType()->aliasName()));
			else
				outstr = fmt::format("KBArray<{}>", pFixedArrayType->getDataType()->aliasName());

			return getArrayType(pFixedArrayType->getDataType(), outstr);
		}
		else if (pFixedArrayType->getDataType()->type() == DATA_TYPE_FIXEDDICT)
		{
			if (outstr.size() > 0)
				strutil::kbe_replace(outstr, pDataType->aliasName(), pFixedArrayType->getDataType()->aliasName());
			else
				outstr = pFixedArrayType->getDataType()->aliasName();
		}
		else
		{
			if (outstr.size() > 0)
				strutil::kbe_replace(outstr, pDataType->aliasName(), typeToType(pFixedArrayType->getDataType()->getName()));
			else
				outstr = typeToType(pFixedArrayType->getDataType()->getName());
		}
	}

	outstr = fmt::format("KBArray<{}>", outstr);
	return true;
}

//-------------------------------------------------------------------------------------
void ClientSDKCXX::onCreateTypeFileName()
{
	sourcefileName_ = "";
	headerfileName_ = "KBETypes.h";

	changeContextToHeader();
}

//-------------------------------------------------------------------------------------
void ClientSDKCXX::onCreateEntityModuleFileName(const std::string& moduleName)
{
	sourcefileName_ = moduleName + moduleSuffix + ".cpp";
	headerfileName_ = moduleName + moduleSuffix + ".h";

	changeContextToHeader();
}

//-------------------------------------------------------------------------------------
void ClientSDKCXX::onCreateServerErrorDescrsModuleFileName()
{
	sourcefileName_ = "";
	headerfileName_ = "ServerErrorDescrs.h";


	changeContextToHeader();
}

//-------------------------------------------------------------------------------------
void ClientSDKCXX::onCreateEngineMessagesModuleFileName()
{
	sourcefileName_ = "Messages.cpp";
	headerfileName_ = "Messages.h";


	changeContextToHeader();
}

//-------------------------------------------------------------------------------------
void ClientSDKCXX::onCreateDefsCustomTypesModuleFileName()
{
	sourcefileName_ = "CustomDataTypes.cpp";
	headerfileName_ = "CustomDataTypes.h";


	changeContextToHeader();
}

//-------------------------------------------------------------------------------------
void ClientSDKCXX::onCreateEntityDefsModuleFileName()
{
	sourcefileName_ = "EntityDef.cpp";
	headerfileName_ = "EntityDef.h";


	changeContextToHeader();
}

//-------------------------------------------------------------------------------------
void ClientSDKCXX::onEntityCallModuleFileName(const std::string& moduleName)
{
	sourcefileName_ = std::string("EntityCall") + moduleName + moduleSuffix + ".cpp";
	headerfileName_ = std::string("EntityCall") + moduleName + moduleSuffix + ".h";

	changeContextToHeader();
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeServerErrorDescrsModuleBegin()
{
	fileBody() = headerBody;
	strutil::kbe_replace(fileBody(), "#REPLACE#", "");

	fileBody() += "#pragma once\n\n";
	fileBody() += "#include \"KBECommon.h\"\n\n";

	fileBody() += namespaceNameBegin;
	fileBody() += "// defined in */res/server/server_errors.xml\n\n";
	fileBody() += fmt::format("class {}\n{{\npublic:\n", "ServerErrorDescrs");

	fileBody() += "\tServerErrorDescrs():\n\tserverErrs_()\n\t{\n";
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeServerErrorDescrsModuleErrDescr(int errorID, const std::string& errname, const std::string& errdescr)
{
	fileBody() += fmt::format("\t\t{{\n\t\t\tFKServerErr e;\n\t\t\te.id = {};\n\t\t\te.name = KBTEXT(\"{}\");\n\t\t\te.descr = KBTEXT(\"{}\");\n\n\t\t\tserverErrs_.Add(e.id, e);\n", errorID, errname, errdescr);
	fileBody() += "\t\t}\n\n";
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeServerErrorDescrsModuleEnd()
{
	fileBody() += "\t}\n\n";

	fileBody() += "\tvoid Clear()\n\t{\n\t\tserverErrs_.Clear();\n\t}\n\n";

	fileBody() += "\tKBString ServerErrStr(uint16 id)\n\t{\n\t\tFKServerErr e = serverErrs_.FindRef(id);\n\t\treturn KBString::Printf(KBTEXT(\"%s[%s]\"), e.name.c_str(), e.descr.c_str());\n\t}\n\n";
	fileBody() += "\tFKServerErr ServerErr(uint16 id)\n\t{\n\t\treturn serverErrs_.FindRef(id);\n\t}\n\n";

	fileBody() += "\tprotected:\n\t\tKBMap<uint16, FKServerErr> serverErrs_;";
	fileBody() += "\n};\n";
	fileBody() += namespaceNameEnd;
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEngineMessagesModuleBegin()
{
	changeContextToHeader();

	initBody_ = "";
	fileBody() = headerBody;
	strutil::kbe_replace(fileBody(), "#REPLACE#", "");

	fileBody() += "#pragma once\n\n";
	fileBody() += "#include \"KBECommon.h\"\n";
	fileBody() += "#include \"MemoryStream.h\"\n\n";

	fileBody() += "// engine-c++ messages\n\n";
	fileBody() += namespaceNameBegin;
	fileBody() += fmt::format("class {}\n{{\npublic:", "Message");

	fileBody() += "\n\tMessage()\n\t{\n";
	fileBody() += "\t\tid = 0;\n";
	fileBody() += "\t\tname = KBTEXT(\"\");\n";
	fileBody() += "\t\tmsglen = -1;\n";
	fileBody() += "\t\targsType = 0;\n\n";
	 
	fileBody() += "\t\targtypes = KBArray<uint8>();";

	fileBody() += "\n\t}\n\n";

	fileBody() += "\n\tMessage(MessageID msgid, const KBString& msgname, int16 length, int8 argstype, const KBArray<uint8>& msgargtypes)\n\t{\n";
	fileBody() += "\t\tid = msgid;\n";
	fileBody() += "\t\tname = msgname;\n";
	fileBody() += "\t\tmsglen = length;\n";
	fileBody() += "\t\targsType = argstype;\n\n";

	fileBody() += "\t\targtypes = msgargtypes;\n\n";

	fileBody() += "\t\t// DEBUG_MSG(\"Message::Message() : (%s / %d / %d)!\", \n";
	fileBody() += "\t\t//\t\tmsgname, (int32)msgid, (int32)msglen));";

	fileBody() += "\n\t}\n\n";

	fileBody() += "\tvirtual ~Message()\n";
	fileBody() += "\t{\n";
	fileBody() += "\t}\n\n";

	fileBody() += "\tvirtual void handleMessage(MemoryStream& msgstream)\n";
	fileBody() += "\t{\n";
	fileBody() += "\t}\n\n";

	fileBody() += "public:\n";
	fileBody() += "\tMessageID id;\n";
	fileBody() += "\tKBString name;\n";
	fileBody() += "\tint16 msglen;\n";
	fileBody() += "\tKBArray<uint8> argtypes;\n";
	fileBody() += "\tint8 argsType;\n";

	fileBody() += "};\n\n";

	changeContextToSource();

	fileBody() += "#include \"Messages.h\"\n";
	fileBody() += "#include \"MemoryStream.h\"\n";
	fileBody() += "#include \"KBEngine.h\"\n\n";

	fileBody() += namespaceNameBegin;
	
	fileBody() += "KBMap<MessageID, Message*> Messages::loginappMessages;\n";
	fileBody() += "KBMap<MessageID, Message*> Messages::baseappMessages;\n";
	fileBody() += "KBMap<MessageID, Message*> Messages::clientMessages;\n";
	fileBody() += "KBMap<KBString, Message*> Messages::messages;\n\n";
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEngineMessagesModuleMessage(Network::ExposedMessageInfo& messageInfos, COMPONENT_TYPE componentType)
{
	changeContextToHeader();

	fileBody() += fmt::format("class Message_{} : public Message\n{{\npublic:\n", messageInfos.name);

	fileBody() += fmt::format("\tMessage_{}(MessageID msgid, const KBString& msgname, int16 length, int8 argstype, const KBArray<uint8>& msgargtypes):\n\tMessage(msgid, msgname, length, argstype, msgargtypes)\n\t{{\n", messageInfos.name);
	fileBody() += "\n\t}\n\n";

	fileBody() += "\tvoid handleMessage(MemoryStream& msgstream) override;\n";

	changeContextToSource();

	fileBody() += fmt::format("void Message_{}::handleMessage(MemoryStream& msgstream)\n", messageInfos.name);
	fileBody() += "{\n";
	fileBody() += "\ttry\n\t{\n";

	if (messageInfos.argsTypes.size() == 0)
	{
		initBody_ += fmt::format("\t\tMessages::messages.Add(KBTEXT(\"{}\"), new Message_{}({}, \"{}\", {}, {}, ",
			messageInfos.name, messageInfos.name, messageInfos.id, messageInfos.name, messageInfos.msgLen, (int)messageInfos.argsType);

		initBody_ += "KBArray<uint8>()));\n";

		if (componentType == CLIENT_TYPE)
		{
			if (messageInfos.argsType < 0)
			{
				fileBody() += fmt::format("\tKBEngineApp::getSingleton().{}(msgstream);\n", messageInfos.name);
			}
			else
			{
				fileBody() += fmt::format("\tKBEngineApp::getSingleton().{}();\n", messageInfos.name);
			}
		}
	}
	else
	{
		std::string argsparse = "";
		std::string giveargs = "";
		initBody_ += fmt::format("\n\t\tKBArray<uint8> {}_argstypes;\n", messageInfos.name);

		for (size_t i = 0; i < messageInfos.argsTypes.size(); ++i)
		{
			int argindex = static_cast<int>(i + 1);
			std::string nativetype = datatype2nativetype(messageInfos.argsTypes[i]);

			KBE_ASSERT(nativetype != "FIXED_DICT" && nativetype != "ARRAY" && nativetype != "PYTHON" && nativetype != "ENTITYCALL");

			std::string readName = nativetype;
			std::transform(readName.begin(), readName.end(), readName.begin(), tolower);
			readName[0] = std::toupper(readName[0]);

			argsparse += fmt::format("\t{} arg{} = msgstream.read{}();\n", typeToType(nativetype), argindex, readName);
			giveargs += fmt::format("arg{}, ", argindex);
			initBody_ += fmt::format("\t\t{}_argstypes.Add({});\n", messageInfos.name, (int)messageInfos.argsTypes[i]);
		}

		if (giveargs.size() > 0)
			giveargs.erase(giveargs.size() - 2, 2);

		initBody_ += fmt::format("\t\tMessages::messages.Add(KBTEXT(\"{}\"), new Message_{}({}, \"{}\", {}, {}, {}_argstypes));\n",
			messageInfos.name, messageInfos.name, messageInfos.id, messageInfos.name, messageInfos.msgLen, (int)messageInfos.argsType, messageInfos.name);

		if (componentType == CLIENT_TYPE)
		{
			fileBody() += argsparse;
			fileBody() += fmt::format("\tKBEngineApp::getSingleton().{}({});\n", messageInfos.name, giveargs);
		}
	}

	if (componentType == CLIENT_TYPE)
	{
		initBody_ += fmt::format("\t\tMessages::clientMessages.Add({}, Messages::messages[\"{}\"]);\n\n", messageInfos.id, messageInfos.name);
	}
	else if (componentType == LOGINAPP_TYPE)
	{
		initBody_ += fmt::format("\t\tMessages::loginappMessages.Add({}, Messages::messages[\"{}\"]);\n\n", messageInfos.id, messageInfos.name);
	}
	else if (componentType == BASEAPP_TYPE)
	{
		initBody_ += fmt::format("\t\tMessages::baseappMessages.Add({}, Messages::messages[\"{}\"]);\n\n", messageInfos.id, messageInfos.name);
	}

	fileBody() += "\t}\n";
	fileBody() += "\tcatch (...)\n\t{\n";
	fileBody() += fmt::format("\t\tSCREEN_ERROR_MSG(\"Message_%s::handleMessage: exception!\");\n", messageInfos.name);
	fileBody() += "\t}\n";
	fileBody() += "}\n\n";

	changeContextToHeader();
	fileBody() += "};\n\n";
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEngineMessagesModuleEnd()
{
	changeContextToSource();
	fileBody() += namespaceNameEnd;
	changeContextToHeader();

	fileBody() += fmt::format("class {}\n{{\npublic:\n", "Messages");

	fileBody() += "\tstatic KBMap<MessageID, Message*> loginappMessages;\n";
	fileBody() += "\tstatic KBMap<MessageID, Message*> baseappMessages;\n";
	fileBody() += "\tstatic KBMap<MessageID, Message*> clientMessages;\n";
	fileBody() += "\tstatic KBMap<KBString, Message*> messages;\n";

	fileBody() += "\n\tstatic Message* findClientMessage(MessageID mid)\n\t{\n";
	fileBody() += "\t\treturn clientMessages.FindRef(mid);";
	fileBody() += "\n\t}\n";

	fileBody() += "\n\tstatic Message* findMessage(const KBString& mname)\n\t{\n";
	fileBody() += "\t\treturn messages.FindRef(mname);";
	fileBody() += "\n\t}\n";

	fileBody() += "\n\tstatic void clear()\n\t{\n";

	fileBody() += "\t\tloginappMessages.Clear();\n";
	fileBody() += "\t\tbaseappMessages.Clear();\n";
	fileBody() += "\t\tclientMessages.Clear();\n\n";
	fileBody() += "\t\tfor (auto item : messages)\n";
	fileBody() += "\t\t\tdelete item.second;\n\n";
	fileBody() += "\t\tmessages.Clear();\n";
	fileBody() += "\n\t\tinitialize();";

	fileBody() += "\n\t}\n";

	fileBody() += "\n\tstatic bool initialize()\n\t{\n";

	fileBody() += initBody_;

	fileBody() += "\n\t\treturn true;";
	fileBody() += "\n\t}";
	fileBody() += "\n}\n;";
	fileBody() += namespaceNameEnd;
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityDefsModuleBegin()
{
	changeContextToHeader();

	initBody_ = "";
	fileBody() = headerBody;
	strutil::kbe_replace(fileBody(), "#REPLACE#", "");

	fileBody() += "#pragma once\n\n";
	fileBody() += "#include \"KBECommon.h\"\n\n";

	fileBody() += namespaceNameBegin;
	fileBody() += "class Entity;\n";
	fileBody() += "class DATATYPE_BASE;\n";
	fileBody() += "class ScriptModule;\n\n";

	fileBody() += "// Manage descriptions of all entities\n\n";
	fileBody() += fmt::format("class {}\n{{\npublic:\n", "EntityDef");

	fileBody() += "\tstatic KBMap<KBString, uint16> datatype2id;\n";
	fileBody() += "\tstatic KBMap<KBString, DATATYPE_BASE*> datatypes;\n";
	fileBody() += "\tstatic KBMap<uint16, DATATYPE_BASE*> id2datatypes;\n";
	fileBody() += "\tstatic KBMap<KBString, int32> entityclass;\n";
	fileBody() += "\tstatic KBMap<KBString, ScriptModule*> moduledefs;\n";
	fileBody() += "\tstatic KBMap<uint16, ScriptModule*> idmoduledefs;\n\n";

	fileBody() += "\tstatic bool initialize();\n";
	fileBody() += "\tstatic bool reset();\n";
	fileBody() += "\tstatic void clear();\n";
	fileBody() += "\tstatic void initDataTypes();\n";
	fileBody() += "\tstatic void initScriptModules();\n";
	fileBody() += "\tstatic void initDefTypes();\n";
	fileBody() += "\tstatic Entity* createEntity(int utype);\n";

	changeContextToSource();
	
	fileBody() += "#include \"EntityDef.h\"\n";
	fileBody() += "#include \"DataTypes.h\"\n";
	fileBody() += "#include \"CustomDataTypes.h\"\n";
	fileBody() += "#include \"ScriptModule.h\"\n";
	fileBody() += "#include \"Property.h\"\n";
	fileBody() += "#include \"Method.h\"\n";
	fileBody() += "#include \"Entity.h\"\n\n";
	fileBody() += "#include \"EntityFactory.h\"\n\n";

	int numEntity = 0;
	const EntityDef::SCRIPT_MODULES& modules = EntityDef::getScriptModules();
	EntityDef::SCRIPT_MODULES::const_iterator iter = modules.begin();
	for (; iter != modules.end(); ++iter)
	{
		if (!iter->get()->hasClient())
			continue;

		++numEntity;

		/*if(iter->get()->isComponentModule())
			fileBody() += fmt::format("#include \"../Scripts/Components/{}.h\"\n", iter->get()->getName());
		else
			fileBody() += fmt::format("#include \"../Scripts/{}.h\"\n", iter->get()->getName());*/
	}

	fileBody() += "\n";
	fileBody() += namespaceNameBegin;
	fileBody() += "KBMap<KBString, uint16> EntityDef::datatype2id;\n";
	fileBody() += "KBMap<KBString, DATATYPE_BASE*> EntityDef::datatypes;\n";
	fileBody() += "KBMap<uint16, DATATYPE_BASE*> EntityDef::id2datatypes;\n";
	fileBody() += "KBMap<KBString, int32> EntityDef::entityclass;\n";
	fileBody() += "KBMap<KBString, ScriptModule*> EntityDef::moduledefs;\n";
	fileBody() += "KBMap<uint16, ScriptModule*> EntityDef::idmoduledefs;\n\n";

	fileBody() += "bool EntityDef::initialize()\n{\n";
	fileBody() += "\tinitDataTypes();\n";
	fileBody() += "\tinitDefTypes();\n";
	fileBody() += "\tinitScriptModules();\n";
	fileBody() += "\treturn true;\n";
	fileBody() += "}\n\n";

	fileBody() += "bool EntityDef::reset()\n{\n";
	fileBody() += "\tclear();\n";
	fileBody() += "\treturn initialize();\n";
	fileBody() += "}\n\n";

	fileBody() += "void EntityDef::clear()\n";
	fileBody() += "{\n";
	fileBody() += "\tKBArray<DATATYPE_BASE*> deleted_datatypes;\n";
	fileBody() += "\tfor (auto& item : EntityDef::datatypes)\n";
	fileBody() += "\t{\n";
	fileBody() += "\t\tint32 idx = deleted_datatypes.Find(item.second);\n";
	fileBody() += "\t\tif (idx != -1)\n";
	fileBody() += "\t\t\tcontinue;\n";
	fileBody() += "\n";
	fileBody() += "\t\tdeleted_datatypes.Add(item.second);\n";
	fileBody() += "\t\tdelete item.second;\n";
	fileBody() += "\t}\n";
	fileBody() += "\n";
	fileBody() += "\tfor (auto& item : EntityDef::moduledefs)\n";
	fileBody() += "\t\tdelete item.second;\n\n";
	fileBody() += "\tdatatype2id.Clear();\n";
	fileBody() += "\tdatatypes.Clear();\n";
	fileBody() += "\tid2datatypes.Clear();\n";
	fileBody() += "\tentityclass.Clear();\n";
	fileBody() += "\tmoduledefs.Clear();\n";
	fileBody() += "\tidmoduledefs.Clear();\n";
	fileBody() += "}\n\n";

	fileBody() += "void EntityDef::initDataTypes()\n";
	fileBody() += "{\n";
	fileBody() += "\tdatatypes.Add(KBTEXT(\"UINT8\"), new DATATYPE_UINT8());\n";
	fileBody() += "\tdatatypes.Add(KBTEXT(\"UINT16\"), new DATATYPE_UINT16());\n";
	fileBody() += "\tdatatypes.Add(KBTEXT(\"UINT32\"), new DATATYPE_UINT32());\n";
	fileBody() += "\tdatatypes.Add(KBTEXT(\"UINT64\"), new DATATYPE_UINT64());\n\n";

	fileBody() += "\tdatatypes.Add(KBTEXT(\"INT8\"), new DATATYPE_INT8());\n";
	fileBody() += "\tdatatypes.Add(KBTEXT(\"INT16\"), new DATATYPE_INT16());\n";
	fileBody() += "\tdatatypes.Add(KBTEXT(\"INT32\"), new DATATYPE_INT32());\n";
	fileBody() += "\tdatatypes.Add(KBTEXT(\"INT64\"), new DATATYPE_INT64());\n\n";

	fileBody() += "\tdatatypes.Add(KBTEXT(\"FLOAT\"), new DATATYPE_FLOAT());\n";
	fileBody() += "\tdatatypes.Add(KBTEXT(\"DOUBLE\"), new DATATYPE_DOUBLE());\n\n";

	fileBody() += "\tdatatypes.Add(KBTEXT(\"STRING\"), new DATATYPE_STRING());\n";
	fileBody() += "\tdatatypes.Add(KBTEXT(\"VECTOR2\"), new DATATYPE_VECTOR2());\n\n";
	fileBody() += "\tdatatypes.Add(KBTEXT(\"VECTOR3\"), new DATATYPE_VECTOR3());\n\n";
	fileBody() += "\tdatatypes.Add(KBTEXT(\"VECTOR4\"), new DATATYPE_VECTOR4());\n";
	fileBody() += "\tdatatypes.Add(KBTEXT(\"PYTHON\"), new DATATYPE_PYTHON());\n\n";
	fileBody() += "\tdatatypes.Add(KBTEXT(\"UNICODE\"), new DATATYPE_UNICODE());\n";
	fileBody() += "\tdatatypes.Add(KBTEXT(\"ENTITYCALL\"), new DATATYPE_ENTITYCALL());\n\n";
	fileBody() += "\tdatatypes.Add(KBTEXT(\"BLOB\"), new DATATYPE_BLOB());\n";
	fileBody() += "}\n\n";

	fileBody() += "Entity* EntityDef::createEntity(int utype)\n";
	fileBody() += "{\n\tEntity* pEntity = NULL;\n\n";

	if (numEntity > 0)
	{
		fileBody() += "\tswitch(utype)\n\t{\n";

		iter = modules.begin();
		for (; iter != modules.end(); ++iter)
		{
			if (!iter->get()->hasClient() || iter->get()->isComponentModule())
				continue;

			fileBody() += fmt::format("\t\tcase {}:\n", iter->get()->getUType());
			//fileBody() += fmt::format("\t\t\tpEntity = new {}();\n\t\t\tbreak;\n", iter->get()->getName());
			fileBody() += fmt::format("\t\t\tpEntity = EntityFactory::instance().create(\"{}\");\n\t\t\tbreak;\n", iter->get()->getName());
		}

		fileBody() += "\t\tdefault:\n\t\t\tSCREEN_ERROR_MSG(\"EntityDef::createEntity() : entity(%d) not found!\", utype);\n\t\t\tbreak;\n\t};\n\n";
	}

	fileBody() += "\treturn pEntity;\n}\n\n";
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityDefsModuleEnd()
{
	changeContextToSource();
	fileBody() += namespaceNameEnd;
	changeContextToHeader();
	fileBody() += "};\n";
	fileBody() += namespaceNameEnd;
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityDefsModuleInitScriptBegin()
{
	changeContextToSource();
	fileBody() += "void EntityDef::initScriptModules()\n";
	fileBody() += "{\n";
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityDefsModuleInitScriptEnd()
{
	changeContextToSource();
	fileBody() += "}\n\n";
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityDefsModuleInitDefTypesBegin()
{
	changeContextToSource();
	fileBody() += "void EntityDef::initDefTypes()\n";
	fileBody() += "{\n";
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityDefsModuleInitDefTypesEnd()
{
	changeContextToSource();
	fileBody() += "\tfor(auto& Elem : EntityDef::datatypes)\n\t{\n";
	fileBody() += "\t\tif(Elem.second)\n\t\t{\n";
	fileBody() += "\t\t\tElem.second->bind();\n\t\t}\n\t}\n";

	fileBody() += "}\n\n";
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityDefsModuleInitDefType(const DataType* pDataType)
{
	changeContextToSource();

	uint16 typeID = datatype2id(pDataType->getName());
	if (typeID == 0 || strcmp(pDataType->getName(), "FIXED_DICT") == 0 || strcmp(pDataType->getName(), "ARRAY") == 0)
	{
		typeID = pDataType->id();
		KBE_ASSERT(typeID > datatype2id("KBE_DATATYPE2ID_MAX"));
	}

	static std::map< int, std::string > type2name;

	fileBody() += fmt::format("\t{{\n");
	fileBody() += fmt::format("\t\tuint16 utype = {};\n", typeID);

	std::string typeName = (strlen(pDataType->aliasName()) > 0 ? pDataType->aliasName() : fmt::format("AnonymousArray_{}", typeID));
	fileBody() += fmt::format("\t\tKBString typeName = KBTEXT(\"{}\");\n", typeName);

	std::map< int, std::string >::iterator iter = type2name.find(typeID);
	if (iter == type2name.end())
		type2name[typeID] = (strlen(pDataType->getName()) > 0 ? pDataType->getName() : typeName);

	if (strcmp(pDataType->getName(), "FIXED_DICT") == 0)
	{
		fileBody() += fmt::format("\t\tDATATYPE_{}* pDatatype = new DATATYPE_{}();\n", typeName, typeName);
		fileBody() += fmt::format("\t\tEntityDef::datatypes.Add(typeName, (DATATYPE_BASE*)pDatatype);\n");
	}
	else if (strcmp(pDataType->getName(), "ARRAY") == 0)
	{
		FixedArrayType* pFixedArrayType = const_cast<FixedArrayType*>(static_cast<const FixedArrayType*>(pDataType));
		typeID = datatype2id(pFixedArrayType->getDataType()->getName());

		if (typeID == 0 || strcmp(pFixedArrayType->getDataType()->getName(), "FIXED_DICT") == 0 ||
			strcmp(pFixedArrayType->getDataType()->getName(), "ARRAY") == 0)
			typeID = pFixedArrayType->getDataType()->id();

		fileBody() += fmt::format("\t\tDATATYPE_{}* pDatatype = new DATATYPE_{}();\n", typeName, typeName);
		fileBody() += fmt::format("\t\tEntityDef::datatypes.Add(typeName, (DATATYPE_BASE*)pDatatype);\n");
	}
	else
	{
		fileBody() += fmt::format("\t\tKBString name = KBTEXT(\"{}\");\n", pDataType->getName());
		fileBody() += fmt::format("\t\tDATATYPE_BASE** fPtr = EntityDef::datatypes.Find(name);\n");
		fileBody() += fmt::format("\t\tDATATYPE_BASE* pVal = fPtr != NULL ? *fPtr : NULL;\n");
		fileBody() += fmt::format("\t\tEntityDef::datatypes.Add(typeName, pVal);\n");
	}

	fileBody() += fmt::format("\t\tEntityDef::id2datatypes.Add(utype, EntityDef::datatypes[typeName]);\n");
	fileBody() += fmt::format("\t\tEntityDef::datatype2id.Add(typeName, utype);\n");
	fileBody() += fmt::format("\t}}\n\n");

	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityCallBegin(ScriptDefModule* pScriptDefModule)
{
	fileBody() = headerBody;
	strutil::kbe_replace(fileBody(), "#REPLACE#", fmt::format("\t\n",
		fileBody()));

	fileBody() += "#pragma once\n\n";
	fileBody() += "#include \"KBECommon.h\"\n";
	fileBody() += "#include \"EntityCall.h\"\n";
	fileBody() += fmt::format("#include \"KBETypes.h\"\n");
	fileBody() += fmt::format("#include \"CustomDataTypes.h\"\n\n");

	{
		std::map<std::string, PropertyDescription*> includesHistroy;
		ScriptDefModule::PROPERTYDESCRIPTION_MAP clientPropertys = pScriptDefModule->getClientPropertyDescriptions();
		ScriptDefModule::PROPERTYDESCRIPTION_MAP::const_iterator propIter = clientPropertys.begin();
		for (; propIter != clientPropertys.end(); ++propIter)
		{
			PropertyDescription* pPropertyDescription = propIter->second;

			if (pPropertyDescription->getDataType()->type() != DATA_TYPE_ENTITY_COMPONENT)
				continue;

			EntityComponentType * pEntityComponentType = (EntityComponentType*)pPropertyDescription->getDataType();

			if (includesHistroy.find(pEntityComponentType->pScriptDefModule()->getName()) != includesHistroy.end())
				continue;

			fileBody() += fmt::format("#include \"{}.h\"\n", (std::string("EntityCall") + pEntityComponentType->pScriptDefModule()->getName() + moduleSuffix));
			includesHistroy[pEntityComponentType->pScriptDefModule()->getName()] = pPropertyDescription;
		}
	}

	fileBody() += std::string("\n// defined in ") + pScriptDefModule->getDefSourceFile() + "\n\n";
	fileBody() += namespaceNameBegin;
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityCallEnd(ScriptDefModule* pScriptDefModule)
{
	changeContextToSource();
	fileBody() += namespaceNameEnd;
	changeContextToHeader();
	fileBody() += namespaceNameEnd;
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityCallMethodBegin(ScriptDefModule* pScriptDefModule, MethodDescription* pMethodDescription, const char* fillString1, const char* fillString2, COMPONENT_TYPE componentType)
{
	std::string newModuleName;

	if(componentType == BASEAPP_TYPE)
		newModuleName = std::string("EntityBaseEntityCall_") + std::string(pScriptDefModule->getName()) + moduleSuffix;
	else
		newModuleName = std::string("EntityCellEntityCall_") + std::string(pScriptDefModule->getName()) + moduleSuffix;

	changeContextToHeader();

	fileBody() += fmt::format("\tvoid {}({});\n", pMethodDescription->getName(), fillString1);

	changeContextToSource();
	fileBody() += fmt::format("void {}::{}({})\n{{\n", newModuleName, pMethodDescription->getName(), fillString1);

	fileBody() += fmt::format("\tBundle* pBundleRet = newCall(\"{}\", {});\n", pMethodDescription->getName(), (pScriptDefModule->isComponentModule() ? "entityComponentPropertyID" : "0"));;
	fileBody() += fmt::format("\tif(!pBundleRet)\n");
	fileBody() += fmt::format("\t\treturn;\n\n");

	std::vector<DataType*>& argTypes = pMethodDescription->getArgTypes();
	std::vector<DataType*>::iterator iter = argTypes.begin();

	std::string writeName;

	int i = 1;

	for (; iter != argTypes.end(); ++iter)
	{
		DataType* pDataType = (*iter);

		if (pDataType->type() == DATA_TYPE_FIXEDDICT)
		{
			writeName = fmt::format("((DATATYPE_{}*)EntityDef::id2datatypes[{}])->addToStreamEx(*pBundleRet, arg{})",
				pDataType->aliasName(), pDataType->id(), i);
		}
		else if (pDataType->type() == DATA_TYPE_FIXEDARRAY)
		{
			if (strlen(pDataType->aliasName()) > 0)
			{
				writeName = fmt::format("((DATATYPE_{}*)EntityDef::id2datatypes[{}])->addToStreamEx(*pBundleRet, arg{})",
					pDataType->aliasName(), pDataType->id(), i);
			}
			else
			{
				writeName = fmt::format("((DATATYPE_AnonymousArray_{}*)EntityDef::id2datatypes[{}])->addToStreamEx(*pBundleRet, arg{})",
					pDataType->id(), pDataType->id(), i);
			}
		}
		else
		{
			writeName = datatype2nativetype(pDataType->getName());
			std::transform(writeName.begin(), writeName.end(), writeName.begin(), tolower);
			writeName[0] = std::toupper(writeName[0]);

			writeName = fmt::format("pBundleRet->write{}(arg{})", writeName, i);
		}

		fileBody() += fmt::format("\t{};\n", writeName);

		i++;
	}

	fileBody() += fmt::format("\tsendCall(NULL);\n");
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityCallMethodEnd(ScriptDefModule* pScriptDefModule, MethodDescription* pMethodDescription)
{
	changeContextToSource();
	fileBody() += fmt::format("}}\n\n");
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeBaseEntityCallBegin(ScriptDefModule* pScriptDefModule)
{
	changeContextToHeader();
	std::string newModuleName;

	newModuleName = std::string("EntityBaseEntityCall_") + std::string(pScriptDefModule->getName()) + moduleSuffix;
	fileBody() += fmt::format("class {} : public EntityCall\n{{\npublic:\n", newModuleName);

	if (!pScriptDefModule->isComponentModule())
	{
		std::string initstr = "";

		ScriptDefModule::PROPERTYDESCRIPTION_MAP clientPropertys = pScriptDefModule->getClientPropertyDescriptions();
		ScriptDefModule::PROPERTYDESCRIPTION_MAP::const_iterator propIter = clientPropertys.begin();
		for (; propIter != clientPropertys.end(); ++propIter)
		{
			PropertyDescription* pPropertyDescription = propIter->second;

			if (pPropertyDescription->getDataType()->type() != DATA_TYPE_ENTITY_COMPONENT)
				continue;

			EntityComponentType * pEntityComponentType = (EntityComponentType*)pPropertyDescription->getDataType();

			fileBody() += fmt::format("\tEntityBaseEntityCall_{}{}* {};\n",
				pEntityComponentType->pScriptDefModule()->getName(), moduleSuffix, pPropertyDescription->getName());

			initstr += fmt::format("\t{} = new EntityBaseEntityCall_{}{}({}, id);\n",
				pPropertyDescription->getName(), pEntityComponentType->pScriptDefModule()->getName(), moduleSuffix, pPropertyDescription->getUType());
		}

		changeContextToHeader();
		fileBody() += fmt::format("\n\t{}(int32 eid, const KBString& ename);\n", newModuleName);
		fileBody() += fmt::format("\n\tvirtual ~{}();\n", newModuleName);

		changeContextToSource();

		fileBody() += fmt::format("#include \"{}.h\"\n", (std::string("EntityCall") + pScriptDefModule->getName() + moduleSuffix));
		fileBody() += fmt::format("#include \"Bundle.h\"\n\n");

		fileBody() += namespaceNameBegin;
		fileBody() += fmt::format("{}::{}(int32 eid, const KBString& ename) : EntityCall(eid, ename)\n{{\n", newModuleName, newModuleName);
		fileBody() += initstr;
	}
	else
	{
		fileBody() += fmt::format("\tuint16 entityComponentPropertyID;\n");

		changeContextToHeader();
		fileBody() += fmt::format("\n\t{}(uint16 ecpID, int32 eid);\n", newModuleName);
		fileBody() += fmt::format("\n\tvirtual ~{}();\n", newModuleName);

		changeContextToSource();

		fileBody() += fmt::format("#include \"{}.h\"\n", (std::string("EntityCall") + pScriptDefModule->getName() + moduleSuffix));
		fileBody() += fmt::format("#include \"Bundle.h\"\n\n");
		fileBody() += namespaceNameBegin;
		fileBody() += fmt::format("{}::{}(uint16 ecpID, int32 eid) : \nEntityCall(eid, \"{}\"),\nentityComponentPropertyID(0)\n{{\n", newModuleName, newModuleName, pScriptDefModule->getName());
		fileBody() += fmt::format("\tentityComponentPropertyID = ecpID;\n");
	}

	changeContextToSource();
	fileBody() += fmt::format("\ttype = ENTITYCALL_TYPE_BASE;\n");
	fileBody() += fmt::format("}}\n");

	fileBody() += fmt::format("\n{}::~{}()\n{{\n", newModuleName, newModuleName);
	if (!pScriptDefModule->isComponentModule())
	{
		ScriptDefModule::PROPERTYDESCRIPTION_MAP clientPropertys = pScriptDefModule->getClientPropertyDescriptions();
		ScriptDefModule::PROPERTYDESCRIPTION_MAP::const_iterator propIter = clientPropertys.begin();
		for (; propIter != clientPropertys.end(); ++propIter)
		{
			PropertyDescription* pPropertyDescription = propIter->second;

			if (pPropertyDescription->getDataType()->type() != DATA_TYPE_ENTITY_COMPONENT)
				continue;

			//EntityComponentType * pEntityComponentType = (EntityComponentType*)pPropertyDescription->getDataType();

			fileBody() += fmt::format("\tif({})\n\t\tdelete {};\n\n", pPropertyDescription->getName(), pPropertyDescription->getName());
		}
	}

	fileBody() += fmt::format("}}\n\n");
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeBaseEntityCallEnd(ScriptDefModule* pScriptDefModule)
{
	changeContextToHeader();
	fileBody() += fmt::format("}};\n");
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeCellEntityCallBegin(ScriptDefModule* pScriptDefModule)
{
	changeContextToHeader();
	std::string newModuleName;

	newModuleName = std::string("EntityCellEntityCall_") + std::string(pScriptDefModule->getName()) + moduleSuffix;
	fileBody() += fmt::format("class {} : public EntityCall\n{{\npublic:\n", newModuleName);

	if (!pScriptDefModule->isComponentModule())
	{
		std::string initstr = "";

		ScriptDefModule::PROPERTYDESCRIPTION_MAP clientPropertys = pScriptDefModule->getClientPropertyDescriptions();
		ScriptDefModule::PROPERTYDESCRIPTION_MAP::const_iterator propIter = clientPropertys.begin();
		for (; propIter != clientPropertys.end(); ++propIter)
		{
			PropertyDescription* pPropertyDescription = propIter->second;

			if (pPropertyDescription->getDataType()->type() != DATA_TYPE_ENTITY_COMPONENT)
				continue;

			EntityComponentType * pEntityComponentType = (EntityComponentType*)pPropertyDescription->getDataType();

			fileBody() += fmt::format("\tEntityCellEntityCall_{}{}* {};\n",
				pEntityComponentType->pScriptDefModule()->getName(), moduleSuffix, pPropertyDescription->getName());

			initstr += fmt::format("\t{} = new EntityCellEntityCall_{}{}({}, id);\n",
				pPropertyDescription->getName(), pEntityComponentType->pScriptDefModule()->getName(), moduleSuffix, pPropertyDescription->getUType());
		}

		changeContextToHeader();
		fileBody() += fmt::format("\n\t{}(int32 eid, const KBString& ename);\n", newModuleName);
		fileBody() += fmt::format("\n\tvirtual ~{}();\n", newModuleName);

		changeContextToSource();
		fileBody() += fmt::format("\n{}::{}(int32 eid, const KBString& ename) : EntityCall(eid, ename)\n{{\n", newModuleName, newModuleName);
		fileBody() += initstr;
	}
	else
	{
		fileBody() += fmt::format("\tuint16 entityComponentPropertyID;\n");

		changeContextToHeader();
		fileBody() += fmt::format("\n\t{}(uint16 ecpID, int32 eid);\n", newModuleName);
		fileBody() += fmt::format("\n\tvirtual ~{}();\n", newModuleName);

		changeContextToSource();
		fileBody() += fmt::format("\n{}::{}(uint16 ecpID, int32 eid) : \nEntityCall(eid, \"{}\"),\nentityComponentPropertyID(0)\n{{\n", newModuleName, newModuleName, pScriptDefModule->getName());
		fileBody() += fmt::format("\tentityComponentPropertyID = ecpID;\n");
	}

	changeContextToSource();
	fileBody() += fmt::format("\ttype = ENTITYCALL_TYPE_CELL;\n");
	fileBody() += fmt::format("}}\n");

	fileBody() += fmt::format("\n{}::~{}()\n{{\n", newModuleName, newModuleName);
	if (!pScriptDefModule->isComponentModule())
	{
		ScriptDefModule::PROPERTYDESCRIPTION_MAP clientPropertys = pScriptDefModule->getClientPropertyDescriptions();
		ScriptDefModule::PROPERTYDESCRIPTION_MAP::const_iterator propIter = clientPropertys.begin();
		for (; propIter != clientPropertys.end(); ++propIter)
		{
			PropertyDescription* pPropertyDescription = propIter->second;

			if (pPropertyDescription->getDataType()->type() != DATA_TYPE_ENTITY_COMPONENT)
				continue;

			//EntityComponentType * pEntityComponentType = (EntityComponentType*)pPropertyDescription->getDataType();

			fileBody() += fmt::format("\tif({})\n\t\tdelete {};\n\n", pPropertyDescription->getName(), pPropertyDescription->getName());
		}
	}

	fileBody() += fmt::format("}}\n\n");
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeCellEntityCallEnd(ScriptDefModule* pScriptDefModule)
{
	changeContextToHeader();
	fileBody() += fmt::format("}};\n");
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeCustomDataTypesBegin()
{
	changeContextToHeader();

	initBody_ = "";
	fileBody() = headerBody;
	strutil::kbe_replace(fileBody(), "#REPLACE#", "");

	fileBody() += "#pragma once\n";
	fileBody() += "#include \"KBECommon.h\"\n";
	fileBody() += "#include \"KBETypes.h\"\n";
	fileBody() += "#include \"MemoryStream.h\"\n";
	fileBody() += "#include \"Bundle.h\"\n";
	fileBody() += "#include \"DataTypes.h\"\n";
	fileBody() += namespaceNameBegin;

	changeContextToSource();
	fileBody() += "#include \"CustomDataTypes.h\"\n";
	fileBody() += "#include \"EntityDef.h\"\n";
	fileBody() += "#include \"KBDebug.h\"\n";
	fileBody() += "#include \"DataTypes.h\"\n";
	fileBody() += namespaceNameBegin;

	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeCustomDataTypesEnd()
{
	changeContextToSource();
	fileBody() += namespaceNameEnd;
	changeContextToHeader();
	fileBody() += namespaceNameEnd;
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::createArrayChildClass(DataType* pRootDataType, DataType* pDataType, const std::string& className, const std::string& tabs, int numLayer)
{
	changeContextToHeader();

	fileBody() += fmt::format("{}class DATATYPE_{} : public DATATYPE_BASE\n{}{{\n{}public:\n", tabs, className, tabs, tabs);

	uint16 typeID = datatype2id(pDataType->getName());
	if (typeID == 0 || strcmp(pDataType->getName(), "FIXED_DICT") == 0 || strcmp(pDataType->getName(), "ARRAY") == 0)
	{
		typeID = pDataType->id();
		KBE_ASSERT(typeID > datatype2id("KBE_DATATYPE2ID_MAX"));
	}

	std::string readName;
	std::string typeName = (strlen(pDataType->aliasName()) > 0 ? pDataType->aliasName() : fmt::format("AnonymousArray_{}", typeID));

	bool isFixedType = strcmp(pDataType->getName(), "FIXED_DICT") == 0 ||
		strcmp(pDataType->getName(), "ARRAY") == 0;

	if (strcmp(pDataType->getName(), "FIXED_DICT") == 0)
	{
		readName = fmt::format("itemType.createFromStreamEx(stream, datas.EmplaceAt_GetRef(datas.Num()))");

		fileBody() += fmt::format("{}\tDATATYPE_{} itemType;\n\n",
			tabs, pDataType->aliasName(), pDataType->aliasName());

		// 如果是非匿名的数组,则第一层解析应该直接设置为有名字的类别
		// 否则设置为系统List类别
		if (numLayer == 1)
		{
			if (strlen(pRootDataType->aliasName()) == 0 || pRootDataType->aliasName()[0] == '_')
			{
				typeName = fmt::format("KBArray<{}>", typeName);
			}
			else
			{
				typeName = pRootDataType->aliasName();
			}
		}
		else
		{
			typeName = fmt::format("KBArray<{}>", typeName);
		}

		fileBody() += fmt::format("{}\tvoid createFromStreamEx(MemoryStream& stream, {}& datas)\n{}\t{{\n", tabs, typeName, tabs);
		fileBody() += fmt::format("{}\t\tuint32 size = stream.readUint32();\n", tabs);
		fileBody() += fmt::format("{}\t\twhile(size > 0)\n", tabs);
		fileBody() += fmt::format("{}\t\t{{\n", tabs);
		fileBody() += fmt::format("{}\t\t\t--size;\n", tabs);
		fileBody() += fmt::format("{}\t\t\t{};\n", tabs, readName);
		fileBody() += fmt::format("{}\t\t}};\n\n", tabs);
		fileBody() += fmt::format("{}\t}}\n\n", tabs);


		fileBody() += fmt::format("{}\tvoid addToStreamEx(Bundle& stream, const {}& v)\n{}\t{{\n", tabs, typeName, tabs);
		fileBody() += fmt::format("{}\t\tstream.writeUint32((uint32)v.Num());\n", tabs);
		fileBody() += fmt::format("{}\t\tfor(int i=0; i<v.Num(); ++i)\n", tabs);
		fileBody() += fmt::format("{}\t\t{{\n", tabs);

		std::string writeName;
		if (isFixedType)
		{
			writeName = fmt::format("itemType.addToStreamEx(stream, v[i])");
		}
		else
		{
			writeName = datatype2nativetype(pDataType->getName());
			std::transform(writeName.begin(), writeName.end(), writeName.begin(), tolower);
			writeName[0] = std::toupper(writeName[0]);
			writeName = fmt::format("stream.write{}(v[i])", writeName);
		}

		fileBody() += fmt::format("{}\t\t\t{};\n", tabs, writeName);
		fileBody() += fmt::format("{}\t\t}};\n", tabs);
		fileBody() += fmt::format("{}\t}}\n", tabs);
	}
	else if (strcmp(pDataType->getName(), "ARRAY") == 0)
	{
		FixedArrayType* pFixedArrayType = static_cast<FixedArrayType*>(pDataType);

		std::string classNameStr = typeName;

		// 如果是非匿名的数组,则第一层解析应该直接设置为有名字的类别
		// 否则设置为系统List类别
		if (numLayer == 1)
		{
			if (strlen(pRootDataType->aliasName()) == 0 || pRootDataType->aliasName()[0] == '_')
			{
				typeName = "";
				getArrayType(pFixedArrayType, typeName);
				typeName = fmt::format("KBArray<{}>", typeName);
			}
			else
			{
				typeName = pRootDataType->aliasName();
			}
		}
		else
		{
			typeName = "";
			getArrayType(pFixedArrayType, typeName);
			typeName = fmt::format("KBArray<{}>", typeName);
		}

		readName = fmt::format("itemType.createFromStreamEx(stream, datas.EmplaceAt_GetRef(datas.Num()))");

		std::string childClassName = classNameStr + "_ChildArray";

		if (!createArrayChildClass(pRootDataType, pFixedArrayType->getDataType(), childClassName, tabs + "\t", numLayer + 1))
			return false;

		fileBody() += fmt::format("{}\tDATATYPE_{} itemType;\n\n",
			tabs, childClassName, childClassName);

		fileBody() += fmt::format("{}\tvoid createFromStreamEx(MemoryStream& stream, {}& datas)\n{}\t{{\n", tabs, typeName, tabs);
		fileBody() += fmt::format("{}\t\tuint32 size = stream.readUint32();\n", tabs);
		fileBody() += fmt::format("{}\t\twhile(size > 0)\n", tabs);
		fileBody() += fmt::format("{}\t\t{{\n", tabs);
		fileBody() += fmt::format("{}\t\t\t--size;\n", tabs);
		fileBody() += fmt::format("{}\t\t\t{};\n", tabs, readName);
		fileBody() += fmt::format("{}\t\t}};\n\n", tabs);
		fileBody() += fmt::format("{}\t}}\n\n", tabs);


		fileBody() += fmt::format("{}\tvoid addToStreamEx(Bundle& stream, const {}& v)\n{}\t{{\n", tabs, typeName, tabs);
		fileBody() += fmt::format("{}\t\tstream.writeUint32((uint32)v.Num());\n", tabs);
		fileBody() += fmt::format("{}\t\tfor(int i=0; i<v.Num(); ++i)\n", tabs);
		fileBody() += fmt::format("{}\t\t{{\n", tabs);

		std::string writeName;
		if (isFixedType)
		{
			writeName = fmt::format("itemType.addToStreamEx(stream, v[i])", writeName);
		}
		else
		{
			writeName = datatype2nativetype(pDataType->getName());
			std::transform(writeName.begin(), writeName.end(), writeName.begin(), tolower);
			writeName[0] = std::toupper(writeName[0]);
			writeName = fmt::format("stream.write{}(v[i])", writeName);
		}

		fileBody() += fmt::format("{}\t\t\t{};\n", tabs, writeName);
		fileBody() += fmt::format("{}\t\t}};\n", tabs);
		fileBody() += fmt::format("{}\t}}\n", tabs);
	}
	else
	{
		readName = datatype2nativetype(pDataType->getName());
		typeName = typeToType(readName);
		std::transform(readName.begin(), readName.end(), readName.begin(), tolower);
		readName[0] = std::toupper(readName[0]);
		readName = fmt::format("stream.read{}()", readName);

		fileBody() += fmt::format("{}\tvoid createFromStreamEx(MemoryStream& stream, KBArray<{}>& datas)\n{}\t{{\n", tabs, typeName, tabs);
		fileBody() += fmt::format("{}\t\tuint32 size = stream.readUint32();\n", tabs);
		fileBody() += fmt::format("{}\t\twhile(size > 0)\n", tabs);
		fileBody() += fmt::format("{}\t\t{{\n", tabs);
		fileBody() += fmt::format("{}\t\t\t--size;\n", tabs);
		fileBody() += fmt::format("{}\t\t\tdatas.Add({});\n", tabs, readName);
		fileBody() += fmt::format("{}\t\t}};\n\n", tabs);
		fileBody() += fmt::format("{}\t}}\n\n", tabs);

		fileBody() += fmt::format("{}\tvoid addToStreamEx(Bundle& stream, const KBArray<{}>& v)\n{}\t{{\n", tabs, typeName, tabs);
		fileBody() += fmt::format("{}\t\tstream.writeUint32((uint32)v.Num());\n", tabs);
		fileBody() += fmt::format("{}\t\tfor(int i=0; i<v.Num(); ++i)\n", tabs);
		fileBody() += fmt::format("{}\t\t{{\n", tabs);

		std::string writeName;
		writeName = datatype2nativetype(pDataType->getName());
		std::transform(writeName.begin(), writeName.end(), writeName.begin(), tolower);
		writeName[0] = std::toupper(writeName[0]);
		writeName = fmt::format("stream.write{}(v[i])", writeName);

		fileBody() += fmt::format("{}\t\t\t{};\n", tabs, writeName);
		fileBody() += fmt::format("{}\t\t}};\n", tabs);
		fileBody() += fmt::format("{}\t}}\n", tabs);
	}

	fileBody() += fmt::format("{}}};\n\n", tabs);
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeCustomDataType(const DataType* pDataType)
{
	changeContextToHeader();

	uint16 typeID = datatype2id(pDataType->getName());
	if (typeID == 0 || strcmp(pDataType->getName(), "FIXED_DICT") == 0 || strcmp(pDataType->getName(), "ARRAY") == 0)
	{
		typeID = pDataType->id();
		KBE_ASSERT(typeID > datatype2id("KBE_DATATYPE2ID_MAX"));
	}

	static std::map< int, std::string > type2name;

	std::string typeName = (strlen(pDataType->aliasName()) > 0 ? pDataType->aliasName() : fmt::format("AnonymousArray_{}", typeID));

	std::map< int, std::string >::iterator iter = type2name.find(typeID);
	if (iter == type2name.end())
		type2name[typeID] = (strlen(pDataType->getName()) > 0 ? pDataType->getName() : typeName);

	if (strcmp(pDataType->getName(), "FIXED_DICT") == 0)
	{
		fileBody() += fmt::format("\nclass DATATYPE_{} : DATATYPE_BASE\n{{\npublic:\n", typeName);
		std::map<std::string, std::string> allClassName;

		FixedDictType* dictdatatype = const_cast<FixedDictType*>(static_cast<const FixedDictType*>(pDataType));

		// 先创建属性
		{
			FixedDictType::FIXEDDICT_KEYTYPE_MAP& keys = dictdatatype->getKeyTypes();
			FixedDictType::FIXEDDICT_KEYTYPE_MAP::const_iterator keyiter = keys.begin();
			for (; keyiter != keys.end(); ++keyiter)
			{
				DataType* pKeyDataType = keyiter->second->dataType;
				if (strcmp(pKeyDataType->getName(), "FIXED_DICT") == 0)
				{
					fileBody() += fmt::format("\tDATATYPE_{} {}_DataType;\n",
						pKeyDataType->aliasName(), keyiter->first, pKeyDataType->aliasName());
				}
				else if (strcmp(pKeyDataType->getName(), "ARRAY") == 0)
				{
					FixedArrayType* pFixedArrayType = const_cast<FixedArrayType*>(static_cast<const FixedArrayType*>(pKeyDataType));

					std::string className = pKeyDataType->aliasName();

					if (strlen(pFixedArrayType->aliasName()) == 0 || pFixedArrayType->aliasName()[0] == '_')
					{
						std::map<std::string, std::string>::iterator findChildClassNameIter = allClassName.find(className + "_ChildArray");

						if (findChildClassNameIter == allClassName.end())
						{
							allClassName[className + "_ChildArray"] = typeName;
							createArrayChildClass(pFixedArrayType, pFixedArrayType->getDataType(), className + "_ChildArray", "\t");
						}

						fileBody() += fmt::format("\tDATATYPE_{} {}_DataType;\n\n",
							className + "_ChildArray", keyiter->first, className + "_ChildArray");
					}
					else
					{
						fileBody() += fmt::format("\tDATATYPE_{} {}_DataType;\n\n",
							className, keyiter->first, className);
					}
				}
				else
				{
				}
			}
		}

		// 创建createFromStreamEx方法
		{
			changeContextToHeader();
			fileBody() += fmt::format("\tvoid createFromStreamEx(MemoryStream& stream, {}& datas);\n", typeName);

			changeContextToSource();
			fileBody() += fmt::format("void DATATYPE_{}::createFromStreamEx(MemoryStream& stream, {}& datas)\n{{\n", typeName, typeName);

			FixedDictType::FIXEDDICT_KEYTYPE_MAP& keys = dictdatatype->getKeyTypes();
			FixedDictType::FIXEDDICT_KEYTYPE_MAP::const_iterator keyiter = keys.begin();
			for (; keyiter != keys.end(); ++keyiter)
			{
				DataType* pKeyDataType = keyiter->second->dataType;
				if (strcmp(pKeyDataType->getName(), "FIXED_DICT") == 0)
				{
					fileBody() += fmt::format("\t{}_DataType.createFromStreamEx(stream, datas.{});\n", keyiter->first, keyiter->first);
				}
				else if (strcmp(pKeyDataType->getName(), "ARRAY") == 0)
				{
					fileBody() += fmt::format("\t{}_DataType.createFromStreamEx(stream, datas.{});\n", keyiter->first, keyiter->first);
				}
				else
				{
					std::string readName = datatype2nativetype(pKeyDataType->getName());
					std::transform(readName.begin(), readName.end(), readName.begin(), tolower);
					readName[0] = std::toupper(readName[0]);
					readName = fmt::format("stream.read{}()", readName);

					fileBody() += fmt::format("\tdatas.{} = {};\n", keyiter->first, readName);
				}
			}

			fileBody() += fmt::format("}}\n\n");
		}

		// 创建addToStreamEx方法
		{
			changeContextToHeader();
			fileBody() += fmt::format("\tvoid addToStreamEx(Bundle& stream, const {}& v);\n", typeName);

			changeContextToSource();
			fileBody() += fmt::format("void DATATYPE_{}::addToStreamEx(Bundle& stream, const {}& v)\n{{\n", typeName, typeName);

			FixedDictType::FIXEDDICT_KEYTYPE_MAP& keys = dictdatatype->getKeyTypes();
			FixedDictType::FIXEDDICT_KEYTYPE_MAP::const_iterator keyiter = keys.begin();
			for (; keyiter != keys.end(); ++keyiter)
			{
				DataType* pKeyDataType = keyiter->second->dataType;
				if (strcmp(pKeyDataType->getName(), "FIXED_DICT") == 0)
				{
					fileBody() += fmt::format("\t{}_DataType.addToStreamEx(stream, v.{});\n", keyiter->first, keyiter->first);
				}
				else if (strcmp(pKeyDataType->getName(), "ARRAY") == 0)
				{
					fileBody() += fmt::format("\t{}_DataType.addToStreamEx(stream, v.{});\n", keyiter->first, keyiter->first);
				}
				else
				{
					std::string writeName = datatype2nativetype(pKeyDataType->getName());
					std::transform(writeName.begin(), writeName.end(), writeName.begin(), tolower);
					writeName[0] = std::toupper(writeName[0]);

					fileBody() += fmt::format("\tstream.write{}(v.{});\n", writeName, keyiter->first);
				}
			}

			fileBody() += fmt::format("}}\n\n");
		}

		changeContextToHeader();
		fileBody() += fmt::format("}};\n\n");

	}
	else if (strcmp(pDataType->getName(), "ARRAY") == 0)
	{
		FixedArrayType* pFixedArrayType = const_cast<FixedArrayType*>(static_cast<const FixedArrayType*>(pDataType));
		typeID = datatype2id(pFixedArrayType->getDataType()->getName());

		if (typeID == 0 || strcmp(pFixedArrayType->getDataType()->getName(), "FIXED_DICT") == 0 ||
			strcmp(pFixedArrayType->getDataType()->getName(), "ARRAY") == 0)
			typeID = pFixedArrayType->getDataType()->id();

		std::string itemTypeName = typeToType(type2name[typeID]);
		if (itemTypeName == "")
		{
			itemTypeName = pFixedArrayType->getDataType()->aliasName();
		}

		std::string className = typeName;

		if (strlen(pFixedArrayType->aliasName()) == 0 || pFixedArrayType->aliasName()[0] == '_')
		{
			typeName = "";
			getArrayType(pFixedArrayType, typeName);
		}

		std::string readName;
		fileBody() += fmt::format("\nclass DATATYPE_{} : DATATYPE_BASE\n{{\npublic:\n", className);

		bool isFixedType = strcmp(pFixedArrayType->getDataType()->getName(), "FIXED_DICT") == 0 ||
			strcmp(pFixedArrayType->getDataType()->getName(), "ARRAY") == 0;

		if (strcmp(pFixedArrayType->getDataType()->getName(), "FIXED_DICT") == 0)
		{
			readName = fmt::format("itemType.createFromStreamEx(stream, childDatas)", readName);

			fileBody() += fmt::format("\tDATATYPE_{} itemType;\n\n",
				pFixedArrayType->getDataType()->aliasName(), pFixedArrayType->getDataType()->aliasName());

			changeContextToHeader();
			fileBody() += fmt::format("\tvoid createFromStreamEx(MemoryStream& stream, {}& datas);\n", typeName);

			changeContextToSource();
			fileBody() += fmt::format("void DATATYPE_{}::createFromStreamEx(MemoryStream& stream, {}& datas)\n{{\n", className, typeName);
			fileBody() += fmt::format("\tuint32 size = stream.readUint32();\n");
			fileBody() += fmt::format("\twhile(size > 0)\n");
			fileBody() += fmt::format("\t{{\n");
			fileBody() += fmt::format("\t\t--size;\n");
			fileBody() += fmt::format("\t\t{} childDatas;\n", pFixedArrayType->getDataType()->aliasName());
			fileBody() += fmt::format("\t\t{};\n", readName);
			fileBody() += fmt::format("\t\tdatas.Add(childDatas);\n");
			fileBody() += fmt::format("\t}};\n\n");
			fileBody() += fmt::format("}}\n\n");

			changeContextToHeader();
			fileBody() += fmt::format("\tvoid addToStreamEx(Bundle& stream, const {}& v);\n", typeName);

			changeContextToSource();
			fileBody() += fmt::format("void DATATYPE_{}::addToStreamEx(Bundle& stream, const {}& v)\n{{\n", className, typeName);
			fileBody() += fmt::format("\tstream.writeUint32((uint32)v.Num());\n");
			fileBody() += fmt::format("\tfor(int i=0; i<v.Num(); ++i)\n");
			fileBody() += fmt::format("\t{{\n");

			std::string writeName;
			if (isFixedType)
			{
				writeName = fmt::format("itemType.addToStreamEx(stream, v[i])", writeName);
			}
			else
			{
				writeName = datatype2nativetype(pFixedArrayType->getDataType()->getName());
				std::transform(writeName.begin(), writeName.end(), writeName.begin(), tolower);
				writeName[0] = std::toupper(writeName[0]);
				writeName = fmt::format("stream.write{}(v[i])", writeName);
			}

			fileBody() += fmt::format("\t\t{};\n", writeName);
			fileBody() += fmt::format("\t}};\n");
			fileBody() += fmt::format("}}\n\n");

			changeContextToHeader();
			fileBody() += fmt::format("}};\n\n");
		}
		else if (strcmp(pFixedArrayType->getDataType()->getName(), "ARRAY") == 0)
		{
			readName = fmt::format("itemType.createFromStreamEx(stream, datas)", readName);

			createArrayChildClass(pFixedArrayType, pFixedArrayType->getDataType(), className + "_ChildArray", "\t");

			fileBody() += fmt::format("\tDATATYPE_{} itemType;\n\n",
				className + "_ChildArray", className + "_ChildArray");

			changeContextToHeader();
			fileBody() += fmt::format("\tvoid createFromStreamEx(MemoryStream& stream, {}& datas);\n", typeName);

			changeContextToSource();
			fileBody() += fmt::format("void DATATYPE_{}::createFromStreamEx(MemoryStream& stream, {}& datas)\n{{\n", className, typeName);
			fileBody() += fmt::format("\t{};\n", readName);
			fileBody() += fmt::format("}}\n\n");

			changeContextToHeader();
			fileBody() += fmt::format("\tvoid addToStreamEx(Bundle& stream, const {}& v);\n", typeName);

			changeContextToSource();
			fileBody() += fmt::format("void DATATYPE_{}::addToStreamEx(Bundle& stream, const {}& v)\n{{\n", className, typeName);
			std::string writeName = fmt::format("itemType.addToStreamEx(stream, v)", writeName);
			fileBody() += fmt::format("\t{};\n", writeName);
			fileBody() += fmt::format("}}\n");

			changeContextToHeader();
			fileBody() += fmt::format("}};\n\n");
		}
		else
		{
			readName = datatype2nativetype(pFixedArrayType->getDataType()->getName());
			std::transform(readName.begin(), readName.end(), readName.begin(), tolower);
			readName[0] = std::toupper(readName[0]);
			readName = fmt::format("stream.read{}()", readName);

			changeContextToHeader();
			fileBody() += fmt::format("\tvoid createFromStreamEx(MemoryStream& stream, {}& datas);\n", typeName);

			changeContextToSource();
			fileBody() += fmt::format("void DATATYPE_{}::createFromStreamEx(MemoryStream& stream, {}& datas)\n{{\n", className, typeName);
			fileBody() += fmt::format("\tuint32 size = stream.readUint32();\n");
			fileBody() += fmt::format("\twhile(size > 0)\n");
			fileBody() += fmt::format("\t{{\n");
			fileBody() += fmt::format("\t\t--size;\n");
			fileBody() += fmt::format("\t\tdatas.Add({});\n", readName);
			fileBody() += fmt::format("\t}};\n\n");
			fileBody() += fmt::format("}}\n\n");

			changeContextToHeader();
			fileBody() += fmt::format("\tvoid addToStreamEx(Bundle& stream, const {}& v);\n", typeName);

			changeContextToSource();
			fileBody() += fmt::format("void DATATYPE_{}::addToStreamEx(Bundle& stream, const {}& v)\n{{\n", className, typeName);
			fileBody() += fmt::format("\tstream.writeUint32((uint32)v.Num());\n");
			fileBody() += fmt::format("\tfor(int i=0; i<v.Num(); ++i)\n");
			fileBody() += fmt::format("\t{{\n");

			std::string writeName;
			if (isFixedType)
			{
				writeName = fmt::format("itemType.addToStreamEx(stream, v[i])", writeName);
			}
			else
			{
				writeName = datatype2nativetype(pFixedArrayType->getDataType()->getName());
				std::transform(writeName.begin(), writeName.end(), writeName.begin(), tolower);
				writeName[0] = std::toupper(writeName[0]);
				writeName = fmt::format("stream.write{}(v[i])", writeName);
			}

			fileBody() += fmt::format("\t\t{};\n", writeName);
			fileBody() += fmt::format("\t}};\n");
			fileBody() += fmt::format("}}\n\n");

			changeContextToHeader();
			fileBody() += fmt::format("}};\n\n");
		}
	}
	else
	{
	}

	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityDefsModuleInitScript_ScriptModule(ScriptDefModule* pScriptDefModule)
{
	fileBody() += fmt::format("\tScriptModule* p{}Module = new ScriptModule(\"{}\", {});\n", pScriptDefModule->getName(), pScriptDefModule->getName(), pScriptDefModule->getUType());
	fileBody() += fmt::format("\tEntityDef::moduledefs.Add(KBTEXT(\"{}\"), p{}Module);\n", pScriptDefModule->getName(), pScriptDefModule->getName());
	fileBody() += fmt::format("\tEntityDef::idmoduledefs.Add({}, p{}Module);\n\n", pScriptDefModule->getUType(), pScriptDefModule->getName());
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityDefsModuleInitScript_MethodDescr(ScriptDefModule* pScriptDefModule, MethodDescription* pDescr, COMPONENT_TYPE componentType)
{
	// 如果pDescr为None,并且是客户端方法,那么需要强制设定useMethodDescrAlias为true,否则默认为false将会出现问题
	if (!pDescr && componentType == CLIENT_TYPE)
	{
		fileBody() += fmt::format("\tp{}Module->useMethodDescrAlias = true;\n", pScriptDefModule->getName());
		return true;
	}

	assert(pDescr);

	fileBody() += fmt::format("\tKBArray<DATATYPE_BASE*> {}_{}_args;\n", pScriptDefModule->getName(), pDescr->getName());

	const std::vector<DataType*>& args = pDescr->getArgTypes();
	std::vector<DataType*>::const_iterator argiter = args.begin();
	for (; argiter != args.end(); ++argiter)
	{
		uint16 typeID = datatype2id((*argiter)->getName());
		if (typeID == 0 || strcmp((*argiter)->getName(), "FIXED_DICT") == 0 || strcmp((*argiter)->getName(), "ARRAY") == 0)
			typeID = (*argiter)->id();

		fileBody() += fmt::format("\t{}_{}_args.Add(EntityDef::id2datatypes[{}]);\n", pScriptDefModule->getName(), pDescr->getName(), typeID);
	}

	fileBody() += fmt::format("\n\tMethod* p{}_{} = new Method();\n", pScriptDefModule->getName(), pDescr->getName());
	fileBody() += fmt::format("\tp{}_{}->name = KBTEXT(\"{}\");\n", pScriptDefModule->getName(), pDescr->getName(), pDescr->getName());
	fileBody() += fmt::format("\tp{}_{}->methodUtype = {};\n", pScriptDefModule->getName(), pDescr->getName(), pDescr->getUType());
	fileBody() += fmt::format("\tp{}_{}->aliasID = {};\n", pScriptDefModule->getName(), pDescr->getName(), pDescr->aliasID());
	fileBody() += fmt::format("\tp{}_{}->args = {}_{}_args;\n\n", pScriptDefModule->getName(), pDescr->getName(), pScriptDefModule->getName(), pDescr->getName());

	fileBody() += fmt::format("\tp{}Module->methods.Add(KBTEXT(\"{}\"), p{}_{}); \n",
		pScriptDefModule->getName(), pDescr->getName(), pScriptDefModule->getName(), pDescr->getName());

	if (pDescr->aliasID() != -1)
	{
		if (componentType == CLIENT_TYPE)
		{
			fileBody() += fmt::format("\tp{}Module->useMethodDescrAlias = true;\n", pScriptDefModule->getName());
			fileBody() += fmt::format("\tp{}Module->idmethods.Add((uint16)p{}_{}->aliasID, p{}_{});\n\n",
				pScriptDefModule->getName(), pScriptDefModule->getName(), pDescr->getName(), pScriptDefModule->getName(), pDescr->getName());
		}
		else
		{
			KBE_ASSERT(false);
		}
	}
	else
	{
		if (componentType == CLIENT_TYPE)
		{
			fileBody() += fmt::format("\tp{}Module->useMethodDescrAlias = false;\n", pScriptDefModule->getName());
			fileBody() += fmt::format("\tp{}Module->idmethods.Add(p{}_{}->methodUtype, p{}_{});\n\n",
				pScriptDefModule->getName(), pScriptDefModule->getName(), pDescr->getName(), pScriptDefModule->getName(), pDescr->getName());
		}
		if (componentType == BASEAPP_TYPE)
		{
			fileBody() += fmt::format("\tp{}Module->base_methods.Add(KBTEXT(\"{}\"), p{}_{});\n\n",
				pScriptDefModule->getName(), pDescr->getName(), pScriptDefModule->getName(), pDescr->getName());

			fileBody() += fmt::format("\tp{}Module->idbase_methods.Add(p{}_{}->methodUtype, p{}_{});\n\n",
				pScriptDefModule->getName(), pScriptDefModule->getName(), pDescr->getName(), pScriptDefModule->getName(), pDescr->getName());
		}
		else
		{
			fileBody() += fmt::format("\tp{}Module->cell_methods.Add(KBTEXT(\"{}\"), p{}_{});\n\n",
				pScriptDefModule->getName(), pDescr->getName(), pScriptDefModule->getName(), pDescr->getName());

			fileBody() += fmt::format("\tp{}Module->idcell_methods.Add(p{}_{}->methodUtype, p{}_{});\n\n",
				pScriptDefModule->getName(), pScriptDefModule->getName(), pDescr->getName(), pScriptDefModule->getName(), pDescr->getName());
		}
	}

	fileBody() += fmt::format("\t//DEBUG_MSG(\"EntityDef::initScriptModules: add({}), method({} / {}).\");\n\n",
		pScriptDefModule->getName(), pDescr->getName(), pDescr->getUType());

	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityDefsModuleInitScript_PropertyDescr(ScriptDefModule* pScriptDefModule, PropertyDescription* pDescr)
{
	uint16 typeID = datatype2id(pDescr->getDataType()->getName());
	bool isFixedType = strcmp(pDescr->getDataType()->getName(), "FIXED_DICT") == 0 || strcmp(pDescr->getDataType()->getName(), "ARRAY") == 0;

	if (typeID == 0 || isFixedType)
		typeID = pDescr->getDataType()->id();

	fileBody() += fmt::format("\tProperty* p{}_{} = new Property();\n", pScriptDefModule->getName(), pDescr->getName());
	fileBody() += fmt::format("\tp{}_{}->name = KBTEXT(\"{}\");\n", pScriptDefModule->getName(), pDescr->getName(), pDescr->getName());
	fileBody() += fmt::format("\tp{}_{}->properUtype = {};\n", pScriptDefModule->getName(), pDescr->getName(), pDescr->getUType());
	fileBody() += fmt::format("\tp{}_{}->properFlags = {};\n", pScriptDefModule->getName(), pDescr->getName(), pDescr->getFlags());
	fileBody() += fmt::format("\tp{}_{}->aliasID = {};\n", pScriptDefModule->getName(), pDescr->getName(), pDescr->aliasID());

	if (isFixedType)
	{
		fileBody() += fmt::format("\tp{}_{}->pDefaultVal = EntityDef::id2datatypes[{}]->parseDefaultValStr(\"{}\");\n",
			pScriptDefModule->getName(), pDescr->getName(), typeID, pDescr->getDefaultValStr());
	}
	else
	{
		std::string readName = typeToType(datatype2nativetype(typeID));

		if (readName == "KBVector2f" || readName == "KBVector3f" || readName == "KBVector4f")
		{
			fileBody() += fmt::format("\tKBVariant* p{}_{}_defval = new KBVariant({}());\n", pScriptDefModule->getName(),
				pDescr->getName(), readName);
		}
		else if (readName == "KBString")
		{
			fileBody() += fmt::format("\tKBVariant* p{}_{}_defval = new KBVariant({}());\n", pScriptDefModule->getName(),
				pDescr->getName(), readName);
		}
		else if (readName == "PYTHON" || readName == "PY_DICT" || readName == "PY_TUPLE" || readName == "PY_LIST" || readName == "KBArray<uint8>")
		{
			fileBody() += fmt::format("\tKBVariant* p{}_{}_defval = new KBVariant(KBArray<uint8>());\n", pScriptDefModule->getName(),
				pDescr->getName());
		}
		else if (pDescr->getDataType()->type() == DATA_TYPE_ENTITY_COMPONENT)
		{
		}
		else
		{
			if (readName == "float")
			{
				fileBody() += fmt::format("\tKBVariant* p{}_{}_defval = new KBVariant(safe_atof(KBTEXT(\"{}\")));\n", 
					pScriptDefModule->getName(), pDescr->getName(), pDescr->getDefaultValStr());
			}
			if(readName == "double")
			{
				fileBody() += fmt::format("\tKBVariant* p{}_{}_defval = new KBVariant(safe_atod(KBTEXT(\"{}\")));\n", 
					pScriptDefModule->getName(), pDescr->getName(), pDescr->getDefaultValStr());
			}
			else if (readName == "int8" || readName == "int16" || readName == "int32" || readName == "int64" ||
				readName == "uint8" || readName == "uint16" || readName == "uint32" || readName == "uint64")
			{
				fileBody() += fmt::format("\tKBVariant* p{}_{}_defval = new KBVariant(({})safe_atoi64(KBTEXT(\"{}\")));\n", 
					pScriptDefModule->getName(), pDescr->getName(), readName, pDescr->getDefaultValStr());
			}
		}

		if (pDescr->getDataType()->type() != DATA_TYPE_ENTITY_COMPONENT)
			fileBody() += fmt::format("\tp{}_{}->pDefaultVal = p{}_{}_defval;\n", pScriptDefModule->getName(), pDescr->getName(), pScriptDefModule->getName(), pDescr->getName());
	}

	fileBody() += fmt::format("\tp{}Module->propertys.Add(KBTEXT(\"{}\"), p{}_{}); \n\n",
		pScriptDefModule->getName(), pDescr->getName(), pScriptDefModule->getName(), pDescr->getName());

	if (pDescr->aliasID() != -1)
	{
		fileBody() += fmt::format("\tp{}Module->usePropertyDescrAlias = true;\n", pScriptDefModule->getName());
		fileBody() += fmt::format("\tp{}Module->idpropertys.Add((uint16)p{}_{}->aliasID, p{}_{});\n\n",
			pScriptDefModule->getName(), pScriptDefModule->getName(), pDescr->getName(), pScriptDefModule->getName(), pDescr->getName());
	}
	else
	{
		fileBody() += fmt::format("\tp{}Module->usePropertyDescrAlias = false;\n", pScriptDefModule->getName());
		fileBody() += fmt::format("\tp{}Module->idpropertys.Add(p{}_{}->properUtype, p{}_{});\n\n",
			pScriptDefModule->getName(), pScriptDefModule->getName(), pDescr->getName(), pScriptDefModule->getName(), pDescr->getName());
	}

	fileBody() += fmt::format("\t//DEBUG_MSG(\"EntityDef::initScriptModules: add({}), property({} / {}).\");\n\n",
		pScriptDefModule->getName(), pDescr->getName(), pDescr->getUType());

	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeTypesBegin()
{
	fileBody() = headerBody;
	strutil::kbe_replace(fileBody(), "#REPLACE#", "");

	fileBody() += "#pragma once\n\n";
	fileBody() += "#include \"KBECommon.h\"\n\n";
	fileBody() += namespaceNameBegin;
	fileBody() += "\n// defined in */scripts/entity_defs/types.xml\n\n";
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeTypesEnd()
{
	fileBody() += namespaceNameEnd;
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeTypeBegin(std::string typeName, FixedDictType* pDataType)
{
	initBody_ = "";
	fileBody() += fmt::format("class {}\n{{\npublic:\n", typeName);
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeTypeEnd(std::string typeName, FixedDictType* pDataType)
{
	if (initBody_.size() > 0)
	{
		initBody_ = std::string(":\n") + initBody_;
		initBody_.erase(initBody_.size() - 2);
	}

	fileBody() += fmt::format("\n\t{}(){}\n\t{{\n\t}}\n", typeName, initBody_);
	fileBody() += "\n};\n\n";

	fileBody() += fmt::format("inline bool operator ==(const {}& a, const {}& b)\n{{\n", typeName, typeName);
	fileBody() += "\treturn ";

	FixedDictType::FIXEDDICT_KEYTYPE_MAP& keysMap = pDataType->getKeyTypes();
	FixedDictType::FIXEDDICT_KEYTYPE_MAP::iterator iter = keysMap.begin();
	for (; iter != keysMap.end(); ++iter)
	{
		if (iter != keysMap.begin())
			fileBody() += " && ";

		fileBody() += fmt::format("a.{} == b.{}", iter->first, iter->first);
	}

	fileBody() += ";\n};\n\n";
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeTypeBegin(std::string typeName, FixedArrayType* pDataType, const std::string& parentClass)
{
	initBody_ = "";
	fileBody() += fmt::format("class {}{}\n{{\npublic:\n", typeName, (parentClass.size() > 0 ? std::string(" : public ") + parentClass : ""));
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeTypeEnd(std::string typeName, FixedArrayType* pDataType)
{
	if (initBody_.size() > 0)
	{
		initBody_ = std::string(":\n") + initBody_;
		initBody_.erase(initBody_.size() - 2);
	}

	fileBody() += fmt::format("\n\t{}(){}\n\t{{\n\t}}\n", typeName, initBody_);
	fileBody() += "\n};\n\n";

	fileBody() += fmt::format("inline bool operator ==(const {}& a, const {}& b)\n{{\n", typeName, typeName);
	fileBody() += "\treturn a == b";
	fileBody() += ";\n};\n\n";
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeTypeBegin(std::string typeName, DataType* pDataType)
{
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeTypeEnd(std::string typeName, DataType* pDataType)
{
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeTypeItemType_AliasName(const std::string& itemName, const std::string& childItemName)
{
	if (childItemName == "UINT8" || childItemName == "UINT16" || childItemName == "UINT32" || childItemName == "UINT64" ||
		childItemName == "INT8" || childItemName == "INT16" || childItemName == "INT32" || childItemName == "INT64" ||
		childItemName == "FLOAT" || childItemName == "DOUBLE")
	{
		std::string ntype = typeToType(childItemName);
		fileBody() += fmt::format("typedef {} {};\n\n", ntype, itemName);
	}
	else if (childItemName == "STRING")
	{
		std::string ntype = typeToType(childItemName);
		fileBody() += fmt::format("typedef {} {};\n\n", ntype, itemName);
	}
	else if (childItemName == "UNICODE")
	{
		std::string ntype = typeToType(childItemName);
		fileBody() += fmt::format("typedef {} {}{};\n\n", ntype, ConflictTypePrefix, itemName);
	}
	else if (childItemName == "PYTHON" || childItemName == "PY_DICT" || childItemName == "PY_TUPLE" ||
		childItemName == "PY_LIST" || childItemName == "ENTITYCALL" || childItemName == "BLOB")
	{
		std::string ntype = "KBArray<uint8>";
		fileBody() += fmt::format("typedef {} {};\n\n", ntype, itemName);
	}
	else if (childItemName == "VECTOR2" || childItemName == "VECTOR3" || childItemName == "VECTOR4")
	{
		std::string ntype = typeToType(childItemName);
		fileBody() += fmt::format("typedef {} {};\n\n", ntype, itemName);
	}

	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeTypeItemType_INT8(const std::string& itemName, const std::string& childItemName)
{
	fileBody() += fmt::format("\tint8 {};\n", itemName);
	initBody_ += fmt::format("\t{}({}),\n", itemName, 0);
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeTypeItemType_INT16(const std::string& itemName, const std::string& childItemName)
{
	fileBody() += fmt::format("\tint16 {};\n", itemName);
	initBody_ += fmt::format("\t{}({}),\n", itemName, 0);
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeTypeItemType_INT32(const std::string& itemName, const std::string& childItemName)
{
	fileBody() += fmt::format("\tint32 {};\n", itemName);
	initBody_ += fmt::format("\t{}({}),\n", itemName, 0);
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeTypeItemType_INT64(const std::string& itemName, const std::string& childItemName)
{
	fileBody() += fmt::format("\tint64 {};\n", itemName);
	initBody_ += fmt::format("\t{}({}),\n", itemName, 0);
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeTypeItemType_UINT8(const std::string& itemName, const std::string& childItemName)
{
	fileBody() += fmt::format("\tuint8 {};\n", itemName);
	initBody_ += fmt::format("\t{}({}),\n", itemName, 0);
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeTypeItemType_UINT16(const std::string& itemName, const std::string& childItemName)
{
	fileBody() += fmt::format("\tuint16 {};\n", itemName);
	initBody_ += fmt::format("\t{}({}),\n", itemName, 0);
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeTypeItemType_UINT32(const std::string& itemName, const std::string& childItemName)
{
	fileBody() += fmt::format("\tuint32 {};\n", itemName);
	initBody_ += fmt::format("\t{}({}),\n", itemName, 0);
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeTypeItemType_UINT64(const std::string& itemName, const std::string& childItemName)
{
	fileBody() += fmt::format("\tuint64 {};\n", itemName);
	initBody_ += fmt::format("\t{}({}),\n", itemName, 0);
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeTypeItemType_FLOAT(const std::string& itemName, const std::string& childItemName)
{
	fileBody() += fmt::format("\tfloat {};\n", itemName);
	initBody_ += fmt::format("\t{}({}),\n", itemName, "0.0f");
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeTypeItemType_DOUBLE(const std::string& itemName, const std::string& childItemName)
{
	fileBody() += fmt::format("\tdouble {};\n", itemName);
	initBody_ += fmt::format("\t{}({}),\n", itemName, "0.0");
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeTypeItemType_STRING(const std::string& itemName, const std::string& childItemName)
{
	fileBody() += fmt::format("\tKBString {};\n", itemName);
	initBody_ += fmt::format("\t{}({}),\n", itemName, "");
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeTypeItemType_UNICODE(const std::string& itemName, const std::string& childItemName)
{
	fileBody() += fmt::format("\tKBString {};\n", itemName);
	initBody_ += fmt::format("\t{}({}),\n", itemName, "");
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeTypeItemType_PYTHON(const std::string& itemName, const std::string& childItemName)
{
	return writeTypeItemType_BLOB(itemName, childItemName);
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeTypeItemType_PY_DICT(const std::string& itemName, const std::string& childItemName)
{
	return writeTypeItemType_BLOB(itemName, childItemName);
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeTypeItemType_PY_TUPLE(const std::string& itemName, const std::string& childItemName)
{
	return writeTypeItemType_BLOB(itemName, childItemName);
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeTypeItemType_PY_LIST(const std::string& itemName, const std::string& childItemName)
{
	return writeTypeItemType_BLOB(itemName, childItemName);
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeTypeItemType_BLOB(const std::string& itemName, const std::string& childItemName)
{
	fileBody() += fmt::format("\tKBArray<uint8> {};\n", itemName);
	initBody_ += fmt::format("\t{}({}),\n", itemName, "");
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeTypeItemType_ARRAY(const std::string& itemName, const std::string& childItemName, DataType* pDataType)
{
	std::string typeStr;

	if (childItemName.size() == 0 || childItemName[0] == '_')
	{
		getArrayType(pDataType, typeStr);
	}
	else
	{
		typeStr = childItemName;
	}

	fileBody() += fmt::format("\t{} {};\n", typeStr, itemName);
	initBody_ += fmt::format("\t{}({}),\n", itemName, "");
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeTypeItemType_FIXED_DICT(const std::string& itemName, const std::string& childItemName, DataType* pDataType)
{
	fileBody() += fmt::format("\t{} {};\n", childItemName, itemName, childItemName);
	initBody_ += fmt::format("\t{}({}),\n", itemName, "");
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeTypeItemType_VECTOR2(const std::string& itemName, const std::string& childItemName)
{
#ifdef CLIENT_NO_FLOAT
	fileBody() += fmt::format("\tKBVector2f {};\n", itemName);
#else
	fileBody() += fmt::format("\tKBVector2f {};\n", itemName);
#endif

	initBody_ += fmt::format("\t{}({}),\n", itemName, "");
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeTypeItemType_VECTOR3(const std::string& itemName, const std::string& childItemName)
{
#ifdef CLIENT_NO_FLOAT
	fileBody() += fmt::format("\tKBVector3f {};\n", itemName);
#else
	fileBody() += fmt::format("\tKBVector3f {};\n", itemName);
#endif

	initBody_ += fmt::format("\t{}({}),\n", itemName, "");
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeTypeItemType_VECTOR4(const std::string& itemName, const std::string& childItemName)
{
#ifdef CLIENT_NO_FLOAT
	fileBody() += fmt::format("\tKBVector3f {};\n", itemName);
#else
	fileBody() += fmt::format("\tKBVector3f {};\n", itemName);
#endif

	initBody_ += fmt::format("\t{}({}),\n", itemName, "");
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeTypeItemType_ENTITYCALL(const std::string& itemName, const std::string& childItemName)
{
	fileBody() += fmt::format("\tKBArray<uint8> {};\n", itemName);
	initBody_ += fmt::format("\t{}({}),\n", itemName, "");
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityModuleBegin(ScriptDefModule* pEntityScriptDefModule)
{
	changeContextToHeader();

	std::string newModuleName = fmt::format("{}{}", pEntityScriptDefModule->getName(), moduleSuffix);

	if (!pEntityScriptDefModule->isComponentModule())
		initBody_ = "\tEntity(),\n\tpBaseEntityCall(NULL),\n\tpCellEntityCall(NULL),\n";
	else
		initBody_ = "\tEntityComponent(),\n\tpBaseEntityCall(NULL),\n\tpCellEntityCall(NULL),\n";

	fileBody() = headerBody;
	strutil::kbe_replace(fileBody(), "#REPLACE#", fmt::format("\tPlease inherit this module, such as: (class {} : public {}{})\n",
		pEntityScriptDefModule->getName(), pEntityScriptDefModule->getName(), moduleSuffix));

	fileBody() += "#pragma once\n";
	fileBody() += "#include \"KBECommon.h\"\n";

	if (!pEntityScriptDefModule->isComponentModule())
	{
		fileBody() += "#include \"Entity.h\"\n";
	}
	else
	{
		fileBody() += "#include \"EntityComponent.h\"\n";
	}

	fileBody() += "#include \"KBETypes.h\"\n";
	

	if (pEntityScriptDefModule->isComponentModule())
	{
		fileBody() += "#include \"ServerErrorDescrs.h\"\n";
	}

	fileBody() += fmt::format("#include \"EntityCall{}.h\"\n\n", newModuleName);

	std::map<std::string, PropertyDescription*> includesHistroy;
	ScriptDefModule::PROPERTYDESCRIPTION_MAP clientPropertys = pEntityScriptDefModule->getClientPropertyDescriptions();
	ScriptDefModule::PROPERTYDESCRIPTION_MAP::const_iterator propIter = clientPropertys.begin();
	for (; propIter != clientPropertys.end(); ++propIter)
	{
		PropertyDescription* pPropertyDescription = propIter->second;

		if (pPropertyDescription->getDataType()->type() != DATA_TYPE_ENTITY_COMPONENT)
			continue;

		EntityComponentType* pEntityComponentType = (EntityComponentType*)pPropertyDescription->getDataType();

		if (includesHistroy.find(pEntityComponentType->pScriptDefModule()->getName()) != includesHistroy.end())
			continue;

		//fileBody() += fmt::format("class {}{};\n", pEntityComponentType->pScriptDefModule()->getName(), moduleSuffix);
		fileBody() += fmt::format("#include \"{}{}.h\"\n", pEntityComponentType->pScriptDefModule()->getName(), moduleSuffix);
		includesHistroy[pEntityComponentType->pScriptDefModule()->getName()] = pPropertyDescription;
	}



	fileBody() += namespaceNameBegin;
	fileBody() += "class Method;\n";
	fileBody() += "class Property;\n";
	fileBody() += "class MemoryStream;\n";

	

	fileBody() += std::string("\n// defined in ") + pEntityScriptDefModule->getDefSourceFile() + "\n";

	if (pEntityScriptDefModule->isComponentModule())
	{
		fileBody() += fmt::format("class {} : public EntityComponent\n{{\npublic:\n", newModuleName);

		// 写entityCall属性
		fileBody() += fmt::format("\tEntityBaseEntityCall_{}* pBaseEntityCall;\n", newModuleName);
		fileBody() += fmt::format("\tEntityCellEntityCall_{}* pCellEntityCall;\n", newModuleName);
		fileBody() += fmt::format("\tScriptModule* getScriptModule();\n\n");

		changeContextToSource();
		
		fileBody() += fmt::format("#include \"{}.h\"\n", newModuleName);
		fileBody() += fmt::format("#include \"Entity.h\"\n");
		fileBody() += fmt::format("#include \"EntityDef.h\"\n");
		fileBody() += fmt::format("#include \"ScriptModule.h\"\n");
		fileBody() += fmt::format("#include \"Property.h\"\n");
		fileBody() += fmt::format("#include \"Method.h\"\n");
		fileBody() += fmt::format("#include \"DataTypes.h\"\n");
		fileBody() += fmt::format("#include \"CustomDataTypes.h\"\n");
		fileBody() += fmt::format("#include \"MemoryStream.h\"\n\n");
		fileBody() += namespaceNameBegin;
	}
	else
	{
		fileBody() += fmt::format("\t// Please inherit and implement \"class {} : public {}\"\n", pEntityScriptDefModule->getName(), newModuleName);
		fileBody() += fmt::format("class {} : public Entity\n{{\npublic:\n", newModuleName);

		// 写entityCall属性
		fileBody() += fmt::format("\tEntityBaseEntityCall_{}* pBaseEntityCall;\n", newModuleName);
		fileBody() += fmt::format("\tEntityCellEntityCall_{}* pCellEntityCall;\n\n", newModuleName);

		changeContextToSource();
		fileBody() += fmt::format("#include \"{}.h\"\n", newModuleName);
		fileBody() += fmt::format("#include \"EntityDef.h\"\n");
		fileBody() += fmt::format("#include \"ScriptModule.h\"\n");
		fileBody() += fmt::format("#include \"Property.h\"\n");
		fileBody() += fmt::format("#include \"Method.h\"\n");
		fileBody() += fmt::format("#include \"DataTypes.h\"\n");
		fileBody() += fmt::format("#include \"CustomDataTypes.h\"\n");
		fileBody() += fmt::format("#include \"MemoryStream.h\"\n");
		fileBody() += fmt::format("#include \"EntityComponent.h\"\n\n");
		fileBody() += fmt::format("#include \"EntityComponentFactory.h\"\n\n");

		std::map<std::string, PropertyDescription*> includesHistroy;
		ScriptDefModule::PROPERTYDESCRIPTION_MAP clientPropertys = pEntityScriptDefModule->getClientPropertyDescriptions();
		ScriptDefModule::PROPERTYDESCRIPTION_MAP::const_iterator propIter = clientPropertys.begin();
		for (; propIter != clientPropertys.end(); ++propIter)
		{
			PropertyDescription* pPropertyDescription = propIter->second;

			if (pPropertyDescription->getDataType()->type() != DATA_TYPE_ENTITY_COMPONENT)
				continue;

			EntityComponentType * pEntityComponentType = (EntityComponentType*)pPropertyDescription->getDataType();

			if (includesHistroy.find(pEntityComponentType->pScriptDefModule()->getName()) != includesHistroy.end())
				continue;

			// fileBody() += fmt::format("#include \"Scripts/Components/{}.h\"\n\n", pEntityComponentType->pScriptDefModule()->getName());
			includesHistroy[pEntityComponentType->pScriptDefModule()->getName()] = pPropertyDescription;
		}

		fileBody() += namespaceNameBegin;
	}

	changeContextToHeader();
	// 函数返回后,后续流程为写实体属性..
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityModuleEnd(ScriptDefModule* pEntityScriptDefModule)
{
	changeContextToHeader();

	if (initBody_.size() > 0)
	{
		initBody_ = std::string(":\n") + initBody_;
		initBody_.erase(initBody_.size() - 2);
	}

	std::string newModuleName = fmt::format("{}{}", pEntityScriptDefModule->getName(), moduleSuffix);

	fileBody() += fmt::format("\n\t{}();\n", newModuleName);
	fileBody() += fmt::format("\tvirtual ~{}();\n", newModuleName);

	changeContextToSource();
	fileBody() += fmt::format("\n{}::{}(){}\n{{\n", newModuleName, newModuleName, initBody_);

	if (!pEntityScriptDefModule->isComponentModule())
	{
		ScriptDefModule::PROPERTYDESCRIPTION_MAP clientPropertys = pEntityScriptDefModule->getClientPropertyDescriptions();
		ScriptDefModule::PROPERTYDESCRIPTION_MAP::const_iterator propIter = clientPropertys.begin();
		for (; propIter != clientPropertys.end(); ++propIter)
		{
			PropertyDescription* pPropertyDescription = propIter->second;

			if (pPropertyDescription->getDataType()->type() != DATA_TYPE_ENTITY_COMPONENT)
				continue;

			EntityComponentType * pEntityComponentType = (EntityComponentType*)pPropertyDescription->getDataType();
			fileBody() += fmt::format("\t{}->pOwner = this;\n", pPropertyDescription->getName());
			fileBody() += fmt::format("\t{}->ownerID = id_;\n", pPropertyDescription->getName());
			fileBody() += fmt::format("\t{}->entityComponentPropertyID = {};\n", pPropertyDescription->getName(), pPropertyDescription->getUType());
			fileBody() += fmt::format("\t{}->name_ = \"{}\";\n\n", pPropertyDescription->getName(), pEntityComponentType->pScriptDefModule()->getName());
		}
	}

	fileBody() += fmt::format("}}\n");
	
	fileBody() += fmt::format("\n{}::~{}()\n{{\n", newModuleName, newModuleName);

	if (!pEntityScriptDefModule->isComponentModule())
	{
		ScriptDefModule::PROPERTYDESCRIPTION_MAP clientPropertys = pEntityScriptDefModule->getClientPropertyDescriptions();
		ScriptDefModule::PROPERTYDESCRIPTION_MAP::const_iterator propIter = clientPropertys.begin();
		for (; propIter != clientPropertys.end(); ++propIter)
		{
			PropertyDescription* pPropertyDescription = propIter->second;

			if (pPropertyDescription->getDataType()->type() != DATA_TYPE_ENTITY_COMPONENT)
				continue;

			//EntityComponentType * pEntityComponentType = (EntityComponentType*)pPropertyDescription->getDataType();
			fileBody() += fmt::format("\tif({})\n", pPropertyDescription->getName());
			fileBody() += fmt::format("\t\tdelete {};\n\n", pPropertyDescription->getName());
		}
	}

	fileBody() += fmt::format("\tif(pBaseEntityCall)\n");
	fileBody() += fmt::format("\t\tdelete pBaseEntityCall;\n\n");

	fileBody() += fmt::format("\tif(pCellEntityCall)\n");
	fileBody() += fmt::format("\t\tdelete pCellEntityCall;\n\n");

	fileBody() += "}\n";

	// attach组件
	if (!pEntityScriptDefModule->isComponentModule())
	{
		changeContextToHeader();
		fileBody() += fmt::format("\n\tvoid attachComponents() override;\n");

		changeContextToSource();
		fileBody() += fmt::format("\nvoid {}::attachComponents()\n{{\n", newModuleName);

		ScriptDefModule::PROPERTYDESCRIPTION_MAP clientPropertys = pEntityScriptDefModule->getClientPropertyDescriptions();
		ScriptDefModule::PROPERTYDESCRIPTION_MAP::const_iterator propIter = clientPropertys.begin();
		for (; propIter != clientPropertys.end(); ++propIter)
		{
			PropertyDescription* pPropertyDescription = propIter->second;

			if (pPropertyDescription->getDataType()->type() != DATA_TYPE_ENTITY_COMPONENT)
				continue;

			fileBody() += fmt::format("\t{}->onAttached(this);\n", pPropertyDescription->getName());
		}

		fileBody() += fmt::format("}}\n");
	}

	// detach组件
	if (!pEntityScriptDefModule->isComponentModule())
	{
		changeContextToHeader();
		fileBody() += fmt::format("\tvoid detachComponents() override;\n");

		changeContextToSource();
		fileBody() += fmt::format("\nvoid {}::detachComponents()\n{{\n", newModuleName);

		ScriptDefModule::PROPERTYDESCRIPTION_MAP clientPropertys = pEntityScriptDefModule->getClientPropertyDescriptions();
		ScriptDefModule::PROPERTYDESCRIPTION_MAP::const_iterator propIter = clientPropertys.begin();
		for (; propIter != clientPropertys.end(); ++propIter)
		{
			PropertyDescription* pPropertyDescription = propIter->second;

			if (pPropertyDescription->getDataType()->type() != DATA_TYPE_ENTITY_COMPONENT)
				continue;

			fileBody() += fmt::format("\t{}->onDetached(this);\n", pPropertyDescription->getName());
		}

		fileBody() += fmt::format("}}\n");
	}

	std::vector<PropertyDescription*> components;

	ScriptDefModule::PROPERTYDESCRIPTION_MAP clientPropertys = pEntityScriptDefModule->getClientPropertyDescriptions();
	ScriptDefModule::PROPERTYDESCRIPTION_MAP::const_iterator propIter = clientPropertys.begin();
	for (; propIter != clientPropertys.end(); ++propIter)
	{
		PropertyDescription* pPropertyDescription = propIter->second;

		if (pPropertyDescription->getDataType()->type() == DATA_TYPE_ENTITY_COMPONENT)
			components.push_back(pPropertyDescription);
	}

	if (!components.empty())
	{
		changeContextToHeader();
		fileBody() += fmt::format("\tKBArray<EntityComponent*> getComponents(KBString componentName, bool all) override;\n");

		changeContextToSource();
		fileBody() += fmt::format("\nKBArray<EntityComponent*> {}::getComponents(KBString componentName, bool all)\n{{\n", newModuleName);
	
		fileBody() += fmt::format("\tKBArray<EntityComponent*> founds;\n\n");

		std::vector<PropertyDescription*>::const_iterator iter = components.begin();
		for (; iter != components.end(); ++iter)
		{
			PropertyDescription* pPropertyDescription = *iter;
			fileBody() += fmt::format("\tif({}->name_ == componentName)\n\t{{\n", pPropertyDescription->getName());
			fileBody() += fmt::format("\t\tfounds.Add({});\n", pPropertyDescription->getName());
			fileBody() += fmt::format("\t\tif(!all)\n");
			fileBody() += fmt::format("\t\t\treturn founds;\n\t}}\n\n");
		}

		fileBody() += "\treturn founds;\n";
		fileBody() += "}\n";
	}

	fileBody() += namespaceNameEnd;

	changeContextToHeader();
	fileBody() += "\n};\n";
	fileBody() += namespaceNameEnd;
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityProcessMessagesMethod(ScriptDefModule* pEntityScriptDefModule)
{
	std::string ownstr = "";
	if (pEntityScriptDefModule->isComponentModule())
		ownstr = "pOwner->";

	changeContextToHeader();

	// EntityCall
	std::string newModuleName = fmt::format("{}{}", pEntityScriptDefModule->getName(), moduleSuffix);

	if (pEntityScriptDefModule->isComponentModule())
	{
		changeContextToHeader();
		fileBody() += fmt::format("\n\tvoid createFromStream(MemoryStream& stream) override;\n");

		changeContextToSource();
		fileBody() += fmt::format("\nvoid {}::createFromStream(MemoryStream& stream)\n{{\n", newModuleName);
		fileBody() += fmt::format("\tEntityComponent::createFromStream(stream);\n");
		fileBody() += fmt::format("}}\n");

		changeContextToHeader();
		fileBody() += fmt::format("\n\tvoid onGetBase() override;\n");

		changeContextToSource();
		fileBody() += fmt::format("\nvoid {}::onGetBase()\n{{\n", newModuleName);
		sourcefileBody_ += fmt::format("\townerID = pOwner->id();\n\n");
		fileBody() += fmt::format("\tif(pBaseEntityCall)\n");
		fileBody() += fmt::format("\t\tdelete pBaseEntityCall;\n\n");
		fileBody() += fmt::format("\tpBaseEntityCall = new EntityBaseEntityCall_{}(entityComponentPropertyID, ownerID);\n", newModuleName);
		fileBody() += "}\n\n";

		changeContextToHeader();
		fileBody() += fmt::format("\tvoid onGetCell() override;\n");

		changeContextToSource();
		fileBody() += fmt::format("void {}::onGetCell()\n{{\n", newModuleName);
		sourcefileBody_ += fmt::format("\townerID = pOwner->id();\n\n");
		fileBody() += fmt::format("\tif(pCellEntityCall)\n");
		fileBody() += fmt::format("\t\tdelete pCellEntityCall;\n\n");
		fileBody() += fmt::format("\tpCellEntityCall = new EntityCellEntityCall_{}(entityComponentPropertyID, ownerID);\n", newModuleName);
		fileBody() += "}\n";

		changeContextToHeader();
		fileBody() += fmt::format("\tvoid onLoseCell() override;\n");

		changeContextToSource();
		fileBody() += fmt::format("\nvoid {}::onLoseCell()\n{{\n", newModuleName);
		fileBody() += fmt::format("\tdelete pCellEntityCall;\n");
		fileBody() += fmt::format("\tpCellEntityCall = NULL;\n");
		fileBody() += "}\n\n";
	}

	if (pEntityScriptDefModule->isComponentModule())
	{
		sourcefileBody_ += fmt::format("\nScriptModule* {}::getScriptModule()\n{{\n", newModuleName);
		sourcefileBody_ += fmt::format("\treturn *EntityDef::moduledefs.Find(\"{}\");\n", pEntityScriptDefModule->getName());
		sourcefileBody_ += "}\n";
	}

	if (!pEntityScriptDefModule->isComponentModule())
	{
		{
			changeContextToHeader();
			fileBody() += fmt::format("\n\tvoid onComponentsEnterworld() override;\n");

			changeContextToSource();
			fileBody() += fmt::format("\nvoid {}::onComponentsEnterworld()\n{{\n", newModuleName);

			ScriptDefModule::PROPERTYDESCRIPTION_MAP clientPropertys = pEntityScriptDefModule->getClientPropertyDescriptions();
			ScriptDefModule::PROPERTYDESCRIPTION_MAP::const_iterator propIter = clientPropertys.begin();
			for (; propIter != clientPropertys.end(); ++propIter)
			{
				PropertyDescription* pPropertyDescription = propIter->second;

				if (pPropertyDescription->getDataType()->type() != DATA_TYPE_ENTITY_COMPONENT)
					continue;

				fileBody() += fmt::format("\t{}->onEnterworld();\n", pPropertyDescription->getName());
			}

			fileBody() += fmt::format("}}\n");
		}

		{
			changeContextToHeader();
			fileBody() += fmt::format("\tvoid onComponentsLeaveworld() override;\n");

			changeContextToSource();
			fileBody() += fmt::format("\nvoid {}::onComponentsLeaveworld()\n{{\n", newModuleName);

			ScriptDefModule::PROPERTYDESCRIPTION_MAP clientPropertys = pEntityScriptDefModule->getClientPropertyDescriptions();
			ScriptDefModule::PROPERTYDESCRIPTION_MAP::const_iterator propIter = clientPropertys.begin();
			for (; propIter != clientPropertys.end(); ++propIter)
			{
				PropertyDescription* pPropertyDescription = propIter->second;

				if (pPropertyDescription->getDataType()->type() != DATA_TYPE_ENTITY_COMPONENT)
					continue;

				fileBody() += fmt::format("\t{}->onLeaveworld();\n", pPropertyDescription->getName());
			}

			fileBody() += fmt::format("}}\n");
		}

		{
			changeContextToHeader();
			fileBody() += fmt::format("\n\tvoid onGetBase() override;\n");

			changeContextToSource();
			fileBody() += fmt::format("\nvoid {}::onGetBase()\n{{\n", newModuleName);
			fileBody() += fmt::format("\tif(pBaseEntityCall)\n");
			fileBody() += fmt::format("\t\tdelete pBaseEntityCall;\n\n");
			fileBody() += fmt::format("\tpBaseEntityCall = new EntityBaseEntityCall_{}(id(), className());\n", newModuleName);

			ScriptDefModule::PROPERTYDESCRIPTION_MAP clientPropertys = pEntityScriptDefModule->getClientPropertyDescriptions();
			ScriptDefModule::PROPERTYDESCRIPTION_MAP::const_iterator propIter = clientPropertys.begin();
			for (; propIter != clientPropertys.end(); ++propIter)
			{
				PropertyDescription* pPropertyDescription = propIter->second;

				if (pPropertyDescription->getDataType()->type() != DATA_TYPE_ENTITY_COMPONENT)
					continue;

				fileBody() += fmt::format("\t{}->onGetBase();\n", pPropertyDescription->getName());
			}

			fileBody() += fmt::format("}}\n");
		}

		{
			changeContextToHeader();
			fileBody() += fmt::format("\tvoid onGetCell() override;\n");

			changeContextToSource();
			fileBody() += fmt::format("\nvoid {}::onGetCell()\n{{\n", newModuleName);
			fileBody() += fmt::format("\tif(pCellEntityCall)\n");
			fileBody() += fmt::format("\t\tdelete pCellEntityCall;\n\n");
			fileBody() += fmt::format("\tpCellEntityCall = new EntityCellEntityCall_{}(id(), className());\n", newModuleName);


			ScriptDefModule::PROPERTYDESCRIPTION_MAP clientPropertys = pEntityScriptDefModule->getClientPropertyDescriptions();
			ScriptDefModule::PROPERTYDESCRIPTION_MAP::const_iterator propIter = clientPropertys.begin();
			for (; propIter != clientPropertys.end(); ++propIter)
			{
				PropertyDescription* pPropertyDescription = propIter->second;

				if (pPropertyDescription->getDataType()->type() != DATA_TYPE_ENTITY_COMPONENT)
					continue;

				fileBody() += fmt::format("\t{}->onGetCell();\n", pPropertyDescription->getName());
			}

			fileBody() += "}\n";
		}

		{
			changeContextToHeader();
			fileBody() += fmt::format("\tvoid onLoseCell() override;\n\n");

			changeContextToSource();
			fileBody() += fmt::format("\nvoid {}::onLoseCell()\n{{\n", newModuleName);
			fileBody() += fmt::format("\tdelete pCellEntityCall;\n");
			fileBody() += fmt::format("\tpCellEntityCall = NULL;\n");

			ScriptDefModule::PROPERTYDESCRIPTION_MAP clientPropertys = pEntityScriptDefModule->getClientPropertyDescriptions();
			ScriptDefModule::PROPERTYDESCRIPTION_MAP::const_iterator propIter = clientPropertys.begin();
			for (; propIter != clientPropertys.end(); ++propIter)
			{
				PropertyDescription* pPropertyDescription = propIter->second;

				if (pPropertyDescription->getDataType()->type() != DATA_TYPE_ENTITY_COMPONENT)
					continue;

				fileBody() += fmt::format("\t{}->onLoseCell();\n", pPropertyDescription->getName());
			}

			fileBody() += "}\n\n";
		}

		changeContextToHeader();
		fileBody() += fmt::format("\tEntityCall* getBaseEntityCall() override;\n");

		changeContextToSource();
		fileBody() += fmt::format("EntityCall* {}::getBaseEntityCall()\n{{\n", newModuleName);
		fileBody() += fmt::format("\treturn pBaseEntityCall;\n");
		fileBody() += "}\n";

		changeContextToHeader();
		fileBody() += fmt::format("\tEntityCall* getCellEntityCall() override;\n\n");

		changeContextToSource();
		fileBody() += fmt::format("\nEntityCall* {}::getCellEntityCall()\n{{\n", newModuleName);
		fileBody() += fmt::format("\treturn pCellEntityCall;\n");
		fileBody() += "}\n";
	}

	// 处理方法
	changeContextToHeader();

	if (!pEntityScriptDefModule->isComponentModule())
		fileBody() += fmt::format("\n\tvoid onRemoteMethodCall(MemoryStream& stream) override;\n");
	else
		fileBody() += fmt::format("\n\tvoid onRemoteMethodCall(uint16 methodUtype, MemoryStream& stream) override;\n");

	changeContextToSource();

	if (!pEntityScriptDefModule->isComponentModule())
		fileBody() += fmt::format("\nvoid {}::onRemoteMethodCall(MemoryStream& stream)\n{{\n", newModuleName);
	else
		fileBody() += fmt::format("\nvoid {}::onRemoteMethodCall(uint16 methodUtype, MemoryStream& stream)\n{{\n", newModuleName);

	ScriptDefModule::METHODDESCRIPTION_MAP& clientMethods = pEntityScriptDefModule->getClientMethodDescriptions();
	if (clientMethods.size() > 0)
	{
		fileBody() += fmt::format("\tScriptModule* sm = *EntityDef::moduledefs.Find(\"{}\");\n", pEntityScriptDefModule->getName());
		
		int entityComponentSize = 0;
		ScriptDefModule::PROPERTYDESCRIPTION_MAP clientPropertys = pEntityScriptDefModule->getClientPropertyDescriptions();
		ScriptDefModule::PROPERTYDESCRIPTION_MAP::const_iterator propIter = clientPropertys.begin();
		for (; propIter != clientPropertys.end(); ++propIter)
		{
			PropertyDescription* pPropertyDescription = propIter->second;

			if (pPropertyDescription->getDataType()->type() != DATA_TYPE_ENTITY_COMPONENT)
				continue;

			++entityComponentSize;
		}

		if (!pEntityScriptDefModule->isComponentModule())
		{
			fileBody() += fmt::format("\tuint16 methodUtype = 0;\n", pEntityScriptDefModule->getName());
			fileBody() += fmt::format("\tuint16 componentPropertyUType = 0;\n\n");
			fileBody() += fmt::format("\tif (sm->usePropertyDescrAlias)\n\t{{\n");
			fileBody() += fmt::format("\t\tcomponentPropertyUType = stream.readUint8();\n");
			fileBody() += fmt::format("\t}}\n\telse\n\t{{\n");
			fileBody() += fmt::format("\t\tcomponentPropertyUType = stream.readUint16();\n\t}}\n\n");

			fileBody() += fmt::format("\tif (sm->useMethodDescrAlias)\n\t{{\n");
			fileBody() += fmt::format("\t\tmethodUtype = stream.read<uint8>();\n");

			bool foundComponentNoUseMethodDescrAlias = false;

			ScriptDefModule::PROPERTYDESCRIPTION_MAP clientPropertys = pEntityScriptDefModule->getClientPropertyDescriptions();
			ScriptDefModule::PROPERTYDESCRIPTION_MAP::const_iterator propIter = clientPropertys.begin();
			for (; propIter != clientPropertys.end(); ++propIter)
			{
				PropertyDescription* pPropertyDescription = propIter->second;

				if (pPropertyDescription->getDataType()->type() != DATA_TYPE_ENTITY_COMPONENT)
					continue;

				EntityComponentType * pEntityComponentType = (EntityComponentType*)pPropertyDescription->getDataType();
				if (!pEntityComponentType->pScriptDefModule()->useMethodDescrAlias())
				{
					foundComponentNoUseMethodDescrAlias = true;
					break;
				}
			}

			if (foundComponentNoUseMethodDescrAlias)
			{
				sourcefileBody_ += fmt::format("\n\t\tif(componentPropertyUType > 0)\n");
				sourcefileBody_ += fmt::format("\t\t{{\n");
				sourcefileBody_ += fmt::format("\t\t\tbool useComponentMethodDescrAlias = true;\n");
				sourcefileBody_ += fmt::format("\t\t\tProperty* pComponentPropertyDescription = sm->idpropertys[componentPropertyUType];\n\n");
				sourcefileBody_ += fmt::format("\t\t\tswitch(pComponentPropertyDescription->properUtype)\n");
				sourcefileBody_ += fmt::format("\t\t\t{{\n");

				for (propIter = clientPropertys.begin(); propIter != clientPropertys.end(); ++propIter)
				{
					PropertyDescription* pPropertyDescription = propIter->second;

					if (pPropertyDescription->getDataType()->type() != DATA_TYPE_ENTITY_COMPONENT)
						continue;

					EntityComponentType * pEntityComponentType = (EntityComponentType*)pPropertyDescription->getDataType();
					if (!pEntityComponentType->pScriptDefModule()->useMethodDescrAlias())
					{
						sourcefileBody_ += fmt::format("\t\t\t\tcase {}:\n", pPropertyDescription->getUType());
						sourcefileBody_ += fmt::format("\t\t\t\t\tuseComponentMethodDescrAlias = false;\n", pPropertyDescription->getName());
						sourcefileBody_ += fmt::format("\t\t\t\t\tbreak;\n");
					}
				}

				sourcefileBody_ += fmt::format("\t\t\t\tdefault:\n");
				sourcefileBody_ += fmt::format("\t\t\t\t\tbreak;\n");
				sourcefileBody_ += fmt::format("\t\t\t}}\n\n");

				sourcefileBody_ += fmt::format("\t\t\tif(!useComponentMethodDescrAlias)\n");
				sourcefileBody_ += fmt::format("\t\t\t{{\n");
				sourcefileBody_ += fmt::format("\t\t\t\tstream.rpos(stream.rpos() - 1);\n");
				sourcefileBody_ += fmt::format("\t\t\t\tmethodUtype = stream.read<uint16>();\n");
				sourcefileBody_ += fmt::format("\t\t\t}}\n");

				sourcefileBody_ += fmt::format("\t\t}}\n");
			}

			fileBody() += fmt::format("\t}}\n\telse\n\t{{\n");
			fileBody() += fmt::format("\t\tmethodUtype = stream.read<uint16>();\n\t}}\n\n");

			fileBody() += fmt::format("\tif(componentPropertyUType > 0)\n\t{{\n");
			if (entityComponentSize > 0)
			{
				fileBody() += fmt::format("\t\tProperty* pComponentPropertyDescription = sm->idpropertys[componentPropertyUType];\n\n");
				fileBody() += fmt::format("\t\tswitch(pComponentPropertyDescription->properUtype)\n\t\t{{\n");

				ScriptDefModule::PROPERTYDESCRIPTION_MAP clientPropertys = pEntityScriptDefModule->getClientPropertyDescriptions();
				ScriptDefModule::PROPERTYDESCRIPTION_MAP::const_iterator propIter = clientPropertys.begin();
				for (; propIter != clientPropertys.end(); ++propIter)
				{
					PropertyDescription* pPropertyDescription = propIter->second;

					if (pPropertyDescription->getDataType()->type() != DATA_TYPE_ENTITY_COMPONENT)
						continue;


					fileBody() += fmt::format("\t\t\tcase {}:\n", pPropertyDescription->getUType());
					fileBody() += fmt::format("\t\t\t\t{}->onRemoteMethodCall(methodUtype, stream);\n", pPropertyDescription->getName());
					fileBody() += fmt::format("\t\t\t\tbreak;\n");
				}

				fileBody() += fmt::format("\t\t}}\n");

				
			}
			else
			{
				fileBody() += fmt::format("\t\tKBE_ASSERT(false);\n");
			}

			fileBody() += fmt::format("\n\t\treturn;\n");
			fileBody() += fmt::format("\t}}\n\n");

			fileBody() += fmt::format("\tMethod* pMethod = sm->idmethods[methodUtype];\n\n");
		}
		else
		{
			fileBody() += fmt::format("\tMethod* pMethod = sm->idmethods[methodUtype];\n\n");
		}

		fileBody() += fmt::format("\tswitch(pMethod->methodUtype)\n\t{{\n");

		ScriptDefModule::METHODDESCRIPTION_MAP::iterator methodIter = clientMethods.begin();
		for (; methodIter != clientMethods.end(); ++methodIter)
		{
			MethodDescription* pMethodDescription = methodIter->second;

			fileBody() += fmt::format("\t\tcase {}:\n\t\t{{\n", pMethodDescription->getUType());

			std::vector<DataType*>& argTypes = pMethodDescription->getArgTypes();
			std::vector<DataType*>::iterator iter = argTypes.begin();

			int i = 1;
			std::string argsStr;

			for (; iter != argTypes.end(); ++iter)
			{
				DataType* pDataType = (*iter);

				uint16 typeID = datatype2id(pDataType->getName());
				if (typeID == 0 || strcmp(pDataType->getName(), "FIXED_DICT") == 0 || strcmp(pDataType->getName(), "ARRAY") == 0)
					typeID = pDataType->id();

				argsStr += fmt::format("{}_arg{}, ", pMethodDescription->getName(), i);

				std::string readName = datatype2nativetype(pDataType->getName());
				if (readName.size() > 0)
				{
					std::transform(readName.begin(), readName.end(), readName.begin(), tolower);
					readName[0] = std::toupper(readName[0]);
				}

				std::string nativetype = datatype2nativetype(typeID);
				if (strcmp(pDataType->getName(), "FIXED_DICT") == 0)
				{
					fileBody() += fmt::format("\t\t\t{} {}_arg{};\n", pDataType->aliasName(), pMethodDescription->getName(), i);

					fileBody() += fmt::format("\t\t\t((DATATYPE_{}*)pMethod->args[{}])->createFromStreamEx(stream, {}_arg{});\n",
						pDataType->aliasName(), (i - 1), pMethodDescription->getName(), i);
				}
				else if (strcmp(pDataType->getName(), "ARRAY") == 0)
				{
					std::string typestr;
					getArrayType(pDataType, typestr);

					if (strlen(pDataType->aliasName()) > 0)
					{
						fileBody() += fmt::format("\t\t\t{} {}_arg{};\n",
							pDataType->aliasName(), pMethodDescription->getName(), i);

						fileBody() += fmt::format("\t\t\t((DATATYPE_{}*)pMethod->args[{}])->createFromStreamEx(stream, {}_arg{});\n",
							pDataType->aliasName(), (i - 1), pMethodDescription->getName(), i);
					}
					else
					{
						fileBody() += fmt::format("\t\t\t{} {}_arg{};\n",
							typestr, pMethodDescription->getName(), i);

						fileBody() += fmt::format("\t\t\t((DATATYPE_AnonymousArray_{}*)pMethod->args[{}])->createFromStreamEx(stream, {}_arg{});\n",
							typeID, (i - 1), pMethodDescription->getName(), i);
					}
				}
				else
				{
					fileBody() += fmt::format("\t\t\t{} {}_arg{} = stream.read{}();\n",
						typeToType(nativetype), pMethodDescription->getName(), i, readName);
				}

				++i;
			}

			if (argsStr.size() > 0)
				argsStr.erase(argsStr.size() - 2, 2);

			fileBody() += fmt::format("\t\t\t{}({});\n", pMethodDescription->getName(), argsStr);
			fileBody() += fmt::format("\t\t\tbreak;\n\t\t}}\n");
		}

		fileBody() += fmt::format("\t\tdefault:\n");
		fileBody() += fmt::format("\t\t\tbreak;\n");
		fileBody() += fmt::format("\t}};\n");
	}

	fileBody() += "}\n";

	// 处理属性
	ENTITY_PROPERTY_UID posuid = 0;
	if (posuid == 0)
	{
		posuid = ENTITY_BASE_PROPERTY_UTYPE_POSITION_XYZ;
		Network::FixedMessages::MSGInfo* msgInfo =
			Network::FixedMessages::getSingleton().isFixed("Property::position");

		if (msgInfo != NULL)
			posuid = msgInfo->msgid;
	}

	PropertyDescription positionDescription(posuid, "VECTOR3", "position", ED_FLAG_ALL_CLIENTS, true, DataTypes::getDataType("VECTOR3"), false, "", 0, "", DETAIL_LEVEL_FAR);
	if (pEntityScriptDefModule->usePropertyDescrAlias() && positionDescription.aliasID() == -1)
		positionDescription.aliasID(ENTITY_BASE_PROPERTY_ALIASID_POSITION_XYZ);

	ENTITY_PROPERTY_UID diruid = 0;
	if (diruid == 0)
	{
		diruid = ENTITY_BASE_PROPERTY_UTYPE_DIRECTION_ROLL_PITCH_YAW;
		Network::FixedMessages::MSGInfo* msgInfo = Network::FixedMessages::getSingleton().isFixed("Property::direction");
		if (msgInfo != NULL)
			diruid = msgInfo->msgid;
	}

	PropertyDescription directionDescription(diruid, "VECTOR3", "direction", ED_FLAG_ALL_CLIENTS, true, DataTypes::getDataType("VECTOR3"), false, "", 0, "", DETAIL_LEVEL_FAR);
	if (pEntityScriptDefModule->usePropertyDescrAlias() && directionDescription.aliasID() == -1)
		directionDescription.aliasID(ENTITY_BASE_PROPERTY_ALIASID_DIRECTION_ROLL_PITCH_YAW);

	ENTITY_PROPERTY_UID spaceuid = 0;
	if (spaceuid == 0)
	{
		spaceuid = ENTITY_BASE_PROPERTY_UTYPE_SPACEID;
		Network::FixedMessages::MSGInfo* msgInfo = Network::FixedMessages::getSingleton().isFixed("Property::spaceID");
		if (msgInfo != NULL)
			spaceuid = msgInfo->msgid;
	}

	PropertyDescription spaceDescription(spaceuid, "UINT32", "spaceID", ED_FLAG_OWN_CLIENT, true, DataTypes::getDataType("UINT32"), false, "", 0, "", DETAIL_LEVEL_FAR);
	if (pEntityScriptDefModule->usePropertyDescrAlias() && spaceDescription.aliasID() == -1)
		spaceDescription.aliasID(ENTITY_BASE_PROPERTY_ALIASID_SPACEID);

	changeContextToHeader();
	if (pEntityScriptDefModule->isComponentModule())
		fileBody() += fmt::format("\tvoid onUpdatePropertys(uint16 propUtype, MemoryStream& stream, int maxCount) override;\n");
	else
		fileBody() += fmt::format("\tvoid onUpdatePropertys(MemoryStream& stream) override;\n");

	changeContextToSource();
	if (pEntityScriptDefModule->isComponentModule())
		fileBody() += fmt::format("\nvoid {}::onUpdatePropertys(uint16 propUtype, MemoryStream& stream, int maxCount)\n{{\n", newModuleName);
	else
		fileBody() += fmt::format("\nvoid {}::onUpdatePropertys(MemoryStream& stream)\n{{\n", newModuleName);

	fileBody() += fmt::format("\tScriptModule* sm = *EntityDef::moduledefs.Find(\"{}\");\n\n", pEntityScriptDefModule->getName());

	if (pEntityScriptDefModule->isComponentModule())
		sourcefileBody_ += fmt::format("\twhile(stream.length() > 0 && maxCount-- != 0)\n\t{{\n");
	else
		sourcefileBody_ += fmt::format("\twhile(stream.length() > 0)\n\t{{\n");

	fileBody() += fmt::format("\t\tuint16 componentPropertyUType = 0;\n");

	if (!pEntityScriptDefModule->isComponentModule())
	{
		fileBody() += fmt::format("\t\tuint16 properUtype = 0;\n\n");

		int entityComponentSize = 0;
		ScriptDefModule::PROPERTYDESCRIPTION_MAP clientPropertys = pEntityScriptDefModule->getClientPropertyDescriptions();
		ScriptDefModule::PROPERTYDESCRIPTION_MAP::const_iterator propIter = clientPropertys.begin();
		for (; propIter != clientPropertys.end(); ++propIter)
		{
			PropertyDescription* pPropertyDescription = propIter->second;

			if (pPropertyDescription->getDataType()->type() != DATA_TYPE_ENTITY_COMPONENT)
				continue;

			++entityComponentSize;
		}

		fileBody() += fmt::format("\t\tif (sm->usePropertyDescrAlias)\n\t\t{{\n");
		fileBody() += fmt::format("\t\t\tcomponentPropertyUType = stream.readUint8();\n");
		fileBody() += fmt::format("\t\t\tproperUtype = stream.read<uint8>();\n");
		fileBody() += fmt::format("\t\t}}\n\t\telse\n\t\t{{\n");
		fileBody() += fmt::format("\t\t\tcomponentPropertyUType = stream.readUint16();\n");
		fileBody() += fmt::format("\t\t\tproperUtype = stream.read<uint16>();\n\t\t}}\n\n");

		fileBody() += fmt::format("\t\tif(componentPropertyUType > 0)\n\t\t{{\n");
		if (entityComponentSize > 0)
		{
			fileBody() += fmt::format("\t\t\tProperty* pComponentPropertyDescription = sm->idpropertys[componentPropertyUType];\n\n");
			fileBody() += fmt::format("\t\t\tswitch(pComponentPropertyDescription->properUtype)\n\t\t\t{{\n");

			ScriptDefModule::PROPERTYDESCRIPTION_MAP clientPropertys = pEntityScriptDefModule->getClientPropertyDescriptions();
			ScriptDefModule::PROPERTYDESCRIPTION_MAP::const_iterator propIter = clientPropertys.begin();
			for (; propIter != clientPropertys.end(); ++propIter)
			{
				PropertyDescription* pPropertyDescription = propIter->second;

				if (pPropertyDescription->getDataType()->type() != DATA_TYPE_ENTITY_COMPONENT)
					continue;


				fileBody() += fmt::format("\t\t\t\tcase {}:\n", pPropertyDescription->getUType());
				fileBody() += fmt::format("\t\t\t\t\t{}->onUpdatePropertys(properUtype, stream, -1);\n", pPropertyDescription->getName());
				fileBody() += fmt::format("\t\t\t\t\tbreak;\n");
			}

			fileBody() += fmt::format("\t\t\t}}\n");
		}
		else
		{
			fileBody() += fmt::format("\t\t\tKBE_ASSERT(false);\n");
		}

		fileBody() += fmt::format("\n\t\t\treturn;\n");
		fileBody() += fmt::format("\t\t}}\n\n");

		fileBody() += fmt::format("\t\tProperty* pProp = sm->idpropertys[properUtype];\n\n");
	}
	else
	{
		fileBody() += fmt::format("\t\tuint16 properUtype = propUtype;\n\n");

		fileBody() += fmt::format("\t\tif (properUtype == 0)\n\t\t{{\n");
		fileBody() += fmt::format("\t\t\tif (sm->usePropertyDescrAlias)\n\t\t\t{{\n");
		fileBody() += fmt::format("\t\t\t\tcomponentPropertyUType = stream.readUint8();\n");
		fileBody() += fmt::format("\t\t\t\tproperUtype = stream.read<uint8>();\n");
		fileBody() += fmt::format("\t\t\t}}\n\t\t\telse\n\t\t\t{{\n");
		fileBody() += fmt::format("\t\t\t\tcomponentPropertyUType = stream.readUint16();\n");
		fileBody() += fmt::format("\t\t\t\tproperUtype = stream.read<uint16>();\n\t\t\t}}\n");
		fileBody() += fmt::format("\t\t}}\n\n");

		fileBody() += fmt::format("\t\tProperty* pProp = sm->idpropertys[properUtype];\n\n");
	}

	ScriptDefModule::PROPERTYDESCRIPTION_MAP clientPropertys = pEntityScriptDefModule->getClientPropertyDescriptions();

	// entity即使在属性小于0时仍然存在默认属性,而组件则可能因为没有属性导致空switch编译出错
	if (!pEntityScriptDefModule->isComponentModule() || clientPropertys.size() > 0)
	{
		fileBody() += fmt::format("\t\tswitch(pProp->properUtype)\n\t\t{{\n");

		if (!pEntityScriptDefModule->isComponentModule())
		{
			clientPropertys[positionDescription.getName()] = &positionDescription;
			clientPropertys[directionDescription.getName()] = &directionDescription;
			clientPropertys[spaceDescription.getName()] = &spaceDescription;
		}

		ScriptDefModule::PROPERTYDESCRIPTION_MAP::const_iterator propIter = clientPropertys.begin();
		for (; propIter != clientPropertys.end(); ++propIter)
		{
			PropertyDescription* pPropertyDescription = propIter->second;

			if (pPropertyDescription->getDataType()->type() == DATA_TYPE_ENTITY_COMPONENT)
			{
				fileBody() += fmt::format("\t\t\tcase {}:\n", pPropertyDescription->getUType());
				fileBody() += fmt::format("\t\t\t\t{}->createFromStream(stream);\n", pPropertyDescription->getName());
				fileBody() += fmt::format("\t\t\t\tbreak;\n");
				continue;
			}

			std::string typestr;

			if (std::string("position") == pPropertyDescription->getName() ||
				std::string("direction") == pPropertyDescription->getName())
			{
#ifdef CLIENT_NO_FLOAT
				typestr = "KBVector3f";
#else
				typestr = "KBVector3f";
#endif
			}
			else
			{
				if (std::string("spaceID") == pPropertyDescription->getName())
				{
					fileBody() += fmt::format("\t\t\tcase {}:\n\t\t\t{{\n", pPropertyDescription->getUType());
					fileBody() += fmt::format("\t\t\t\tstream.readUint32();\n");
					fileBody() += fmt::format("\t\t\t\tbreak;\n\t\t\t}}\n");
					continue;
				}
				else
				{
					std::string findstr = fmt::format(" {};", pPropertyDescription->getName());
					std::string::size_type fpos = headerfileBody_.find(findstr);
					std::string::size_type fposStart = headerfileBody_.rfind("\t", fpos - 1);
					std::string::size_type fposEnd = headerfileBody_.rfind(" ", fpos);

					typestr.assign(headerfileBody_.begin() + fposStart + 1, headerfileBody_.begin() + fposEnd);
				}
			}

			fileBody() += fmt::format("\t\t\tcase {}:\n\t\t\t{{\n", pPropertyDescription->getUType());
			fileBody() += fmt::format("\t\t\t\t{} oldval_{} = {};\n", typestr, pPropertyDescription->getName(), pPropertyDescription->getName());

			std::string readName = datatype2nativetype(pPropertyDescription->getDataType()->getName());
			if (readName.size() > 0)
			{
				std::transform(readName.begin(), readName.end(), readName.begin(), tolower);
				readName[0] = std::toupper(readName[0]);
			}
			else
			{
				KBE_ASSERT(false);
			}

			if (pPropertyDescription->getDataType()->type() == DATA_TYPE_FIXEDDICT)
			{
				readName = fmt::format("((DATATYPE_{}*)EntityDef::id2datatypes[{}])->createFromStreamEx(stream, {})",
					pPropertyDescription->getDataType()->aliasName(), pPropertyDescription->getDataType()->id(), pPropertyDescription->getName());

				fileBody() += fmt::format("\t\t\t\t{};\n", readName);
			}
			else if (pPropertyDescription->getDataType()->type() == DATA_TYPE_FIXEDARRAY)
			{
				if (strlen(pPropertyDescription->getDataType()->aliasName()) > 0)
				{
					readName = fmt::format("((DATATYPE_{}*)EntityDef::id2datatypes[{}])->createFromStreamEx(stream, {})",
						pPropertyDescription->getDataType()->aliasName(), pPropertyDescription->getDataType()->id(), pPropertyDescription->getName());
				}
				else
				{
					readName = fmt::format("((DATATYPE_AnonymousArray_{}*)EntityDef::id2datatypes[{}])->createFromStreamEx(stream, {})",
						pPropertyDescription->getDataType()->id(), pPropertyDescription->getDataType()->id(), pPropertyDescription->getName());
				}

				fileBody() += fmt::format("\t\t\t\t{};\n", readName);
			}
			else
			{
				readName = fmt::format("stream.read{}()", readName);
				fileBody() += fmt::format("\t\t\t\t{} = {};\n", pPropertyDescription->getName(), readName);
			}

			std::string name = pPropertyDescription->getName();
			name[0] = std::toupper(name[0]);
			fileBody() += fmt::format("\n\t\t\t\tif(pProp->isBase())\n\t\t\t\t{{\n");
			fileBody() += fmt::format("\t\t\t\t\tif({}inited())\n", ownstr);
			fileBody() += fmt::format("\t\t\t\t\t\ton{}Changed(oldval_{});\n\t\t\t\t}}\n", name, pPropertyDescription->getName());
			fileBody() += fmt::format("\t\t\t\telse\n\t\t\t\t{{\n");
			fileBody() += fmt::format("\t\t\t\t\tif({}inWorld())\n", ownstr);
			fileBody() += fmt::format("\t\t\t\t\t\ton{}Changed(oldval_{});\n", name, pPropertyDescription->getName());
			fileBody() += fmt::format("\t\t\t\t}}\n\n");
			fileBody() += fmt::format("\t\t\t\tbreak;\n\t\t\t}}\n");
		}

		fileBody() += fmt::format("\t\t\tdefault:\n");
		fileBody() += fmt::format("\t\t\t\tbreak;\n");
		fileBody() += fmt::format("\t\t}};\n");
	}

	fileBody() += "\t}\n";
	fileBody() += "}\n";

	// 处理属性callPropertysSetMethods
	changeContextToHeader();
	fileBody() += fmt::format("\tvoid callPropertysSetMethods() override;\n");

	changeContextToSource();
	fileBody() += fmt::format("\nvoid {}::callPropertysSetMethods()\n{{\n", newModuleName);
	fileBody() += fmt::format("\tScriptModule* sm = EntityDef::moduledefs[\"{}\"];\n", pEntityScriptDefModule->getName());
	fileBody() += fmt::format("\tKBMap<uint16, Property*>& pdatas = sm->idpropertys;\n\n");

	ScriptDefModule::PROPERTYDESCRIPTION_MAP::const_iterator propIter = clientPropertys.begin();
	for (; propIter != clientPropertys.end(); ++propIter)
	{
		PropertyDescription* pPropertyDescription = propIter->second;

		std::string typestr;

		if (std::string("spaceID") == pPropertyDescription->getName())
			continue;

		if (std::string("position") == pPropertyDescription->getName() ||
			std::string("direction") == pPropertyDescription->getName())
		{
#ifdef CLIENT_NO_FLOAT
			typestr = "KBVector3f";
#else
			typestr = "KBVector3f";
#endif
		}
		else
		{
			std::string findstr = fmt::format(" {};", pPropertyDescription->getName());
			std::string::size_type fpos = headerfileBody_.find(findstr);
			std::string::size_type fposStart = headerfileBody_.rfind("\t", fpos - 1);
			std::string::size_type fposEnd = headerfileBody_.rfind(" ", fpos);

			typestr.assign(headerfileBody_.begin() + fposStart + 1, headerfileBody_.begin() + fposEnd);
		}

		if (pPropertyDescription->getDataType()->type() == DATA_TYPE_ENTITY_COMPONENT)
		{
			fileBody() += fmt::format("\t{}->callPropertysSetMethods();\n\n", pPropertyDescription->getName());
		}
		else
		{
			fileBody() += fmt::format("\t{} oldval_{} = {};\n", typestr, pPropertyDescription->getName(), pPropertyDescription->getName());

			std::string name = pPropertyDescription->getName();
			name[0] = std::toupper(name[0]);

			fileBody() += fmt::format("\tProperty* pProp_{} = pdatas[{}];\n", pPropertyDescription->getName(), (pEntityScriptDefModule->usePropertyDescrAlias() ?
				pPropertyDescription->aliasID() : pPropertyDescription->getUType()));

			fileBody() += fmt::format("\tif(pProp_{}->isBase())\n\t{{\n", pPropertyDescription->getName());
			fileBody() += fmt::format("\t\tif({}inited() && !{}inWorld())\n", ownstr, ownstr);
			fileBody() += fmt::format("\t\t\ton{}Changed(oldval_{});\n", name, pPropertyDescription->getName());
			fileBody() += fmt::format("\t}}\n\telse\n\t{{\n");
			fileBody() += fmt::format("\t\tif({}inWorld())\n\t\t{{\n", ownstr);
			fileBody() += fmt::format("\t\t\tif(pProp_{}->isOwnerOnly() && !{}isPlayer())\n\t\t\t{{\n\t\t\t}}\n\t\t\telse\n\t\t\t{{\n", pPropertyDescription->getName(), ownstr);
			fileBody() += fmt::format("\t\t\t\ton{}Changed(oldval_{});\n\t\t\t}}\n", name, pPropertyDescription->getName());
			fileBody() += fmt::format("\t\t}}\n\t}}\n\n");
		}
	}

	fileBody() += "}\n";

	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityPropertyComponent(ScriptDefModule* pEntityScriptDefModule,
	ScriptDefModule* pCurrScriptDefModule, PropertyDescription* pPropertyDescription)
{
	EntityComponentType * pEntityComponentType = (EntityComponentType*)pPropertyDescription->getDataType();

	fileBody() += fmt::format("\t{}{}* {};\n", pEntityComponentType->pScriptDefModule()->getName(), moduleSuffix, pPropertyDescription->getName(),
		pEntityComponentType->pScriptDefModule()->getName());

	//initBody_ += fmt::format("\t{}(new {}()),\n", pPropertyDescription->getName(), pEntityComponentType->pScriptDefModule()->getName());
	initBody_ += fmt::format("\t{}(static_cast<{}{}*>(EntityComponentFactory::instance().create(\"{}\"))),\n", 
		pPropertyDescription->getName(), 
		pEntityComponentType->pScriptDefModule()->getName(),
		moduleSuffix,
		pEntityComponentType->pScriptDefModule()->getName()
	);

	std::string name = pPropertyDescription->getName();
	name[0] = std::toupper(name[0]);
	fileBody() += fmt::format("\tvirtual void on{}Changed(const {}{}& oldValue) {{}}\n", name, pEntityComponentType->pScriptDefModule()->getName(), moduleSuffix);
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityProperty_INT8(ScriptDefModule* pEntityScriptDefModule,
	ScriptDefModule* pCurrScriptDefModule, PropertyDescription* pPropertyDescription)
{
	fileBody() += fmt::format("\tint8 {};\n", pPropertyDescription->getName());
	initBody_ += fmt::format("\t{}((int8)safe_atoi64(KBTEXT(\"{}\"))),\n", pPropertyDescription->getName(), (strlen(pPropertyDescription->getDefaultValStr()) > 0 ? pPropertyDescription->getDefaultValStr() : "0"));

	std::string name = pPropertyDescription->getName();
	name[0] = std::toupper(name[0]);
	fileBody() += fmt::format("\tvirtual void on{}Changed(int8 oldValue) {{}}\n", name);
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityProperty_INT16(ScriptDefModule* pEntityScriptDefModule,
	ScriptDefModule* pCurrScriptDefModule, PropertyDescription* pPropertyDescription)
{
	fileBody() += fmt::format("\tint16 {};\n", pPropertyDescription->getName());
	initBody_ += fmt::format("\t{}((int16)safe_atoi64(KBTEXT(\"{}\"))),\n", pPropertyDescription->getName(), (strlen(pPropertyDescription->getDefaultValStr()) > 0 ? pPropertyDescription->getDefaultValStr() : "0"));

	std::string name = pPropertyDescription->getName();
	name[0] = std::toupper(name[0]);
	fileBody() += fmt::format("\tvirtual void on{}Changed(int16 oldValue) {{}}\n", name);
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityProperty_INT32(ScriptDefModule* pEntityScriptDefModule,
	ScriptDefModule* pCurrScriptDefModule, PropertyDescription* pPropertyDescription)
{
	fileBody() += fmt::format("\tint32 {};\n", pPropertyDescription->getName());
	initBody_ += fmt::format("\t{}((int32)safe_atoi64(KBTEXT(\"{}\"))),\n", pPropertyDescription->getName(), (strlen(pPropertyDescription->getDefaultValStr()) > 0 ? pPropertyDescription->getDefaultValStr() : "0"));

	std::string name = pPropertyDescription->getName();
	name[0] = std::toupper(name[0]);
	fileBody() += fmt::format("\tvirtual void on{}Changed(int32 oldValue) {{}}\n", name);
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityProperty_INT64(ScriptDefModule* pEntityScriptDefModule,
	ScriptDefModule* pCurrScriptDefModule, PropertyDescription* pPropertyDescription)
{
	fileBody() += fmt::format("\tint64 {};\n", pPropertyDescription->getName());
	initBody_ += fmt::format("\t{}((int64)safe_atoi64(KBTEXT(\"{}\"))),\n", pPropertyDescription->getName(), (strlen(pPropertyDescription->getDefaultValStr()) > 0 ? pPropertyDescription->getDefaultValStr() : "0"));

	std::string name = pPropertyDescription->getName();
	name[0] = std::toupper(name[0]);
	fileBody() += fmt::format("\tvirtual void on{}Changed(int64 oldValue) {{}}\n", name);
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityProperty_UINT8(ScriptDefModule* pEntityScriptDefModule,
	ScriptDefModule* pCurrScriptDefModule, PropertyDescription* pPropertyDescription)
{
	fileBody() += fmt::format("\tuint8 {};\n", pPropertyDescription->getName());
	initBody_ += fmt::format("\t{}((uint8)safe_atoi64(KBTEXT(\"{}\"))),\n", pPropertyDescription->getName(), (strlen(pPropertyDescription->getDefaultValStr()) > 0 ? pPropertyDescription->getDefaultValStr() : "0"));

	std::string name = pPropertyDescription->getName();
	name[0] = std::toupper(name[0]);
	fileBody() += fmt::format("\tvirtual void on{}Changed(uint8 oldValue) {{}}\n", name);
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityProperty_UINT16(ScriptDefModule* pEntityScriptDefModule,
	ScriptDefModule* pCurrScriptDefModule, PropertyDescription* pPropertyDescription)
{
	fileBody() += fmt::format("\tuint16 {};\n", pPropertyDescription->getName());
	initBody_ += fmt::format("\t{}((uint16)safe_atoi64(KBTEXT(\"{}\"))),\n", pPropertyDescription->getName(), (strlen(pPropertyDescription->getDefaultValStr()) > 0 ? pPropertyDescription->getDefaultValStr() : "0"));

	std::string name = pPropertyDescription->getName();
	name[0] = std::toupper(name[0]);
	fileBody() += fmt::format("\tvirtual void on{}Changed(uint16 oldValue) {{}}\n", name);
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityProperty_UINT32(ScriptDefModule* pEntityScriptDefModule,
	ScriptDefModule* pCurrScriptDefModule, PropertyDescription* pPropertyDescription)
{
	fileBody() += fmt::format("\tuint32 {};\n", pPropertyDescription->getName());
	initBody_ += fmt::format("\t{}((uint32)safe_atoi64(KBTEXT(\"{}\"))),\n", pPropertyDescription->getName(), (strlen(pPropertyDescription->getDefaultValStr()) > 0 ? pPropertyDescription->getDefaultValStr() : "0"));

	std::string name = pPropertyDescription->getName();
	name[0] = std::toupper(name[0]);
	fileBody() += fmt::format("\tvirtual void on{}Changed(uint32 oldValue) {{}}\n", name);
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityProperty_UINT64(ScriptDefModule* pEntityScriptDefModule,
	ScriptDefModule* pCurrScriptDefModule, PropertyDescription* pPropertyDescription)
{
	fileBody() += fmt::format("\tuint64 {};\n", pPropertyDescription->getName());
	initBody_ += fmt::format("\t{}((uint64)safe_atoi64(KBTEXT(\"{}\"))),\n", pPropertyDescription->getName(), (strlen(pPropertyDescription->getDefaultValStr()) > 0 ? pPropertyDescription->getDefaultValStr() : "0"));

	std::string name = pPropertyDescription->getName();
	name[0] = std::toupper(name[0]);
	fileBody() += fmt::format("\tvirtual void on{}Changed(uint64 oldValue) {{}}\n", name);
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityProperty_FLOAT(ScriptDefModule* pEntityScriptDefModule,
	ScriptDefModule* pCurrScriptDefModule, PropertyDescription* pPropertyDescription)
{
	fileBody() += fmt::format("\tfloat {};\n", pPropertyDescription->getName());
	initBody_ += fmt::format("\t{}(safe_atof(KBTEXT(\"{}\"))),\n", pPropertyDescription->getName(), (strlen(pPropertyDescription->getDefaultValStr()) > 0 ? pPropertyDescription->getDefaultValStr() : "0.0f"));

	std::string name = pPropertyDescription->getName();
	name[0] = std::toupper(name[0]);
	fileBody() += fmt::format("\tvirtual void on{}Changed(float oldValue) {{}}\n", name);
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityProperty_DOUBLE(ScriptDefModule* pEntityScriptDefModule,
	ScriptDefModule* pCurrScriptDefModule, PropertyDescription* pPropertyDescription)
{
	fileBody() += fmt::format("\tdouble {};\n", pPropertyDescription->getName());
	initBody_ += fmt::format("\t{}(safe_atod(KBTEXT(\"{}\"))),\n", pPropertyDescription->getName(), (strlen(pPropertyDescription->getDefaultValStr()) > 0 ? pPropertyDescription->getDefaultValStr() : "0.0"));

	std::string name = pPropertyDescription->getName();
	name[0] = std::toupper(name[0]);
	fileBody() += fmt::format("\tvirtual void on{}Changed(double oldValue) {{}}\n", name);
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityProperty_STRING(ScriptDefModule* pEntityScriptDefModule,
	ScriptDefModule* pCurrScriptDefModule, PropertyDescription* pPropertyDescription)
{
	fileBody() += fmt::format("\tKBString {};\n", pPropertyDescription->getName());
	initBody_ += fmt::format("\t{}(KBTEXT(\"{}\")),\n", pPropertyDescription->getName(), (strlen(pPropertyDescription->getDefaultValStr()) > 0 ? pPropertyDescription->getDefaultValStr() : ""));

	std::string name = pPropertyDescription->getName();
	name[0] = std::toupper(name[0]);
	fileBody() += fmt::format("\tvirtual void on{}Changed(const KBString& oldValue) {{}}\n", name);
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityProperty_UNICODE(ScriptDefModule* pEntityScriptDefModule,
	ScriptDefModule* pCurrScriptDefModule, PropertyDescription* pPropertyDescription)
{
	fileBody() += fmt::format("\tKBString {};\n", pPropertyDescription->getName());
	initBody_ += fmt::format("\t{}(KBTEXT(\"{}\")),\n", pPropertyDescription->getName(), (strlen(pPropertyDescription->getDefaultValStr()) > 0 ? pPropertyDescription->getDefaultValStr() : ""));

	std::string name = pPropertyDescription->getName();
	name[0] = std::toupper(name[0]);
	fileBody() += fmt::format("\tvirtual void on{}Changed(const KBString& oldValue) {{}}\n", name);
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityProperty_PYTHON(ScriptDefModule* pEntityScriptDefModule,
	ScriptDefModule* pCurrScriptDefModule, PropertyDescription* pPropertyDescription)
{
	ERROR_MSG("ClientSDKCXX::writeEntityProperty_PYTHON(): nonsupport!\n");
	return false;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityProperty_PY_DICT(ScriptDefModule* pEntityScriptDefModule,
	ScriptDefModule* pCurrScriptDefModule, PropertyDescription* pPropertyDescription)
{
	ERROR_MSG("ClientSDKCXX::writeEntityProperty_PY_DICT(): nonsupport!\n");
	return false;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityProperty_PY_TUPLE(ScriptDefModule* pEntityScriptDefModule,
	ScriptDefModule* pCurrScriptDefModule, PropertyDescription* pPropertyDescription)
{
	ERROR_MSG("ClientSDKCXX::writeEntityProperty_PY_TUPLE(): nonsupport!\n");
	return false;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityProperty_PY_LIST(ScriptDefModule* pEntityScriptDefModule,
	ScriptDefModule* pCurrScriptDefModule, PropertyDescription* pPropertyDescription)
{
	ERROR_MSG("ClientSDKCXX::writeEntityProperty_PY_LIST(): nonsupport!\n");
	return false;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityProperty_BLOB(ScriptDefModule* pEntityScriptDefModule,
	ScriptDefModule* pCurrScriptDefModule, PropertyDescription* pPropertyDescription)
{
	fileBody() += fmt::format("\tKBArray<uint8> {};\n", pPropertyDescription->getName());
	initBody_ += fmt::format("\t{}(),\n", pPropertyDescription->getName());
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityProperty_ARRAY(ScriptDefModule* pEntityScriptDefModule,
	ScriptDefModule* pCurrScriptDefModule, PropertyDescription* pPropertyDescription)
{
	if (std::string("ARRAY") == pPropertyDescription->getDataTypeName())
	{
		std::string s = fileBody();
		fileBody() = "";

		bool ret = writeTypeItemType_ARRAY(pPropertyDescription->getName(), pPropertyDescription->getDataType()->aliasName(), pPropertyDescription->getDataType());
		std::vector<std::string> values;
		KBEngine::strutil::kbe_splits(fileBody(), " ", values);
		fileBody() = s + fileBody();

		std::string name = pPropertyDescription->getName();
		name[0] = std::toupper(name[0]);
		fileBody() += fmt::format("\t\tvirtual void on{}Changed(const {}& oldValue) {{}}\n", name, values[1]);
		return ret;
	}
	else
	{
		fileBody() += fmt::format("\t{} {};\n", pPropertyDescription->getDataTypeName(), pPropertyDescription->getName());
		initBody_ += fmt::format("\t{}(),\n", pPropertyDescription->getName());

		std::string name = pPropertyDescription->getName();
		name[0] = std::toupper(name[0]);
		fileBody() += fmt::format("\tvirtual void on{}Changed(const {}& oldValue) {{}}\n", name, pPropertyDescription->getDataTypeName());
	} 

	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityProperty_FIXED_DICT(ScriptDefModule* pEntityScriptDefModule,
	ScriptDefModule* pCurrScriptDefModule, PropertyDescription* pPropertyDescription)
{
	fileBody() += fmt::format("\t{} {};\n", pPropertyDescription->getDataTypeName(), pPropertyDescription->getName());
	initBody_ += fmt::format("\t{}(),\n", pPropertyDescription->getName());

	std::string name = pPropertyDescription->getName();
	name[0] = std::toupper(name[0]);
	fileBody() += fmt::format("\tvirtual void on{}Changed(const {}& oldValue) {{}}\n", name, pPropertyDescription->getDataTypeName());
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityProperty_VECTOR2(ScriptDefModule* pEntityScriptDefModule,
	ScriptDefModule* pCurrScriptDefModule, PropertyDescription* pPropertyDescription)
{
#ifdef CLIENT_NO_FLOAT
	fileBody() += fmt::format("\tKBVector2f {};\n", pPropertyDescription->getName());
#else
	fileBody() += fmt::format("\tKBVector2f {};\n", pPropertyDescription->getName());
#endif

	initBody_ += fmt::format("\t{}(),\n", pPropertyDescription->getName());

	std::string name = pPropertyDescription->getName();
	name[0] = std::toupper(name[0]);
	fileBody() += fmt::format("\tvirtual void on{}Changed(const KBVector2f& oldValue) {{}}\n", name);
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityProperty_VECTOR3(ScriptDefModule* pEntityScriptDefModule,
	ScriptDefModule* pCurrScriptDefModule, PropertyDescription* pPropertyDescription)
{
#ifdef CLIENT_NO_FLOAT
	fileBody() += fmt::format("\tKBVector3f {};\n", pPropertyDescription->getName());
#else
	fileBody() += fmt::format("\tKBVector3f {};\n", pPropertyDescription->getName());
#endif

	initBody_ += fmt::format("\t{}(),\n", pPropertyDescription->getName());

	std::string name = pPropertyDescription->getName();
	name[0] = std::toupper(name[0]);
	fileBody() += fmt::format("\tvirtual void on{}Changed(const KBVector3f& oldValue) {{}}\n", name);
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityProperty_VECTOR4(ScriptDefModule* pEntityScriptDefModule,
	ScriptDefModule* pCurrScriptDefModule, PropertyDescription* pPropertyDescription)
{
#ifdef CLIENT_NO_FLOAT
	fileBody() += fmt::format("\tKBVector4f {};\n", pPropertyDescription->getName());
#else
	fileBody() += fmt::format("\tKBVector4f {};\n", pPropertyDescription->getName());
#endif

	initBody_ += fmt::format("\t{}(),\n", pPropertyDescription->getName());

	std::string name = pPropertyDescription->getName();
	name[0] = std::toupper(name[0]);
	fileBody() += fmt::format("\tvirtual void on{}Changed(const KBVector4f& oldValue) {{}}\n", name);
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityProperty_ENTITYCALL(ScriptDefModule* pEntityScriptDefModule,
	ScriptDefModule* pCurrScriptDefModule, PropertyDescription* pPropertyDescription)
{
	fileBody() += fmt::format("\tKBArray<uint8> {};\n", pPropertyDescription->getName());
	initBody_ += fmt::format("\t{}(),\n", pPropertyDescription->getName());

	std::string name = pPropertyDescription->getName();
	name[0] = std::toupper(name[0]);
	fileBody() += fmt::format("\tvirtual void on{}Changed(const KBArray<uint8>& oldValue) {{}}\n", name);
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityMethod(ScriptDefModule* pEntityScriptDefModule,
	ScriptDefModule* pCurrScriptDefModule, MethodDescription* pMethodDescription, const char* fillString)
{
	fileBody() += fmt::format("\tvirtual void {}({}) = 0; \n", pMethodDescription->getName(), fillString);
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityMethodArgs_ARRAY(FixedArrayType* pFixedArrayType, std::string& stackArgsTypeBody, const std::string& childItemName)
{
	// 对于匿名数组需要解析,否则直接填类型名称
	if (childItemName.size() == 0 || childItemName[0] == '_')
	{
		std::string typeStr;
		getArrayType(pFixedArrayType, typeStr);
		stackArgsTypeBody += fmt::format("const {}&", typeStr);
	}
	else
	{
		stackArgsTypeBody += fmt::format("const {}&", childItemName);
	}
	
	return true;
}

//-------------------------------------------------------------------------------------
bool ClientSDKCXX::writeEntityMethodArgs_Const_Ref(DataType* pDataType, std::string& stackArgsTypeBody)
{
	stackArgsTypeBody = std::string("const ") + stackArgsTypeBody + "&";
	return true;
}

//-------------------------------------------------------------------------------------
}