网络游戏开发基础篇

本篇的内容,会介绍几个内容:单例,dll动态加载以及一些跨平台的处理。       1、单例:单例模式是一种使用广泛而又比较简单的设计模式,他的定义我就不多介绍了,大家上网一查就知道了,基本都能理解。在游戏开发中,会有很多单件,所以封装一个单例类供后面的开发使用。       本单例使用模板实现,代码如下:[cpp] viewplaincopyprint?//

大家好,又见面了,我是你们的朋友全栈君。

本篇的内容,会介绍几个内容:单例,dll动态加载以及一些跨平台的处理。

       1、单例:单例模式是一种使用广泛而又比较简单的设计模式,他的定义我就不多介绍了,大家上网一查就知道了,基本都能理解。在游戏开发中,会有很多单件,所以封装一个单例类供后面的开发使用。

       本单例使用模板实现,代码如下:

  1. //singleton.h   
  2. #ifndef _SINGLETON_H   
  3. #define _SINGLETON_H   
  4.   
  5. namespace Blaze  
  6. {  
  7.     template<class T>  
  8.     class Singleton  
  9.     {  
  10.     public:  
  11.         static T* instance()  
  12.         {  
  13.             if (!_instance)  
  14.             {  
  15.                 _instance = new T;  
  16.             }  
  17.             return _instance;  
  18.         }  
  19.   
  20.     protected:  
  21.         /// 使用保护构造是为了用户不能在栈上声明一个实例   
  22.         Singleton() {}  
  23.   
  24.     private:  
  25.         static T* _instance;        /// 实例静态指针   
  26.     };  
  27.   
  28.     /// 静态实例指针初始化   
  29.     template <class T> T* Singleton<T>::_instance = NULL;  
  30.   
  31. } // namespace   
  32.   
  33. #endif //_SINGLETON_H  
//singleton.h
#ifndef _SINGLETON_H
#define _SINGLETON_H

namespace Blaze
{
	template<class T>
	class Singleton
	{
	public:
		static T* instance()
		{
			if (!_instance)
			{
				_instance = new T;
			}
			return _instance;
		}

	protected:
		/// 使用保护构造是为了用户不能在栈上声明一个实例
		Singleton() {}

	private:
		static T* _instance;		/// 实例静态指针
	};

	/// 静态实例指针初始化
	template <class T> T* Singleton<T>::_instance = NULL;

} // namespace

#endif //_SINGLETON_H
  1. //使用的时候只需要单件类继承此模板即可。   
  2. class Test : public Singleton<Test >{…};            
//使用的时候只需要单件类继承此模板即可。
class Test : public Singleton<Test >{...};          

        2、dll(so)动态加载

  在开发网络游戏的过程中,现在已经不是能够单打独斗的年代了,一款游戏基本上不可能有一个人完成,因此分模块开发成为了必然,各自开发相关的模块,然后组合到一起。dll就是分模块开发的产物之一,它的加载有动态和静态之分,各有优势,但是由于服务器程序是需要运行在多个平台,而他们又各自有各自的加载方法,为了方便使用,因此我们队加载dll进行了封装。

        实现使用模板,非常简单,代码如下

  1. // lib_def.h   
  2. #ifndef __LIB_DEF_H_   
  3. #define __LIB_DEF_H_   
  4.   
  5. namespace Blaze  
  6. {  
  7.     // DLL对象创建辅助类   
  8.     template<const TCHAR*& szFileName>  
  9.     class DllApi  
  10.     {  
  11.     public:  
  12.         static BOOL Load()  
  13.         {  
  14.             if(!m_h) m_h = ::LoadLibrary(szFileName);  
  15.             return m_h != NULL;  
  16.         }  
  17.         static void Unload()  
  18.         {  
  19.             if(m_h) ::FreeLibrary(m_h);  
  20.             m_h = NULL;  
  21.         }  
  22.     protected:  
  23.         static HMODULE m_h;  
  24.     };    
  25.     template<const TCHAR*& szFileName> HMODULE DllApi<szFileName>::m_h;  
  26.   
  27.     //库文件前后缀   
  28. #ifdef WIN32   
  29.     #define __DLL_PREFIX    _T(“”)   
  30.     #define __DLL_SUFFIX    _T(“.dll”)   
  31. #else   
  32.     #define __DLL_PREFIX    _T(“lib”)   
  33.     #define __DLL_SUFFIX    _T(“.so”)   
  34. #endif   
  35.   
  36.     // 声明DLL文件名常量   
  37. #define DECLARE_DLL_FILE(module) extern “C” const TCHAR* module;   
  38.   
  39.     // 定义DLL文件名常量   
  40. #if !defined(_LIB) && !defined(_USE_STATIC_LIB)   
  41.     #define DEFINE_DLL_FILE(module) extern “C” const TCHAR* module = _T(“./”)””__DLL_PREFIX””_T(#module)””__DLL_SUFFIX;   
  42. #else   
  43.     #define DEFINE_DLL_FILE(module)   
  44. #endif   
  45. }  
  46.   
  47. #endif  

 本例中使用了LoadLibrary,是windows的实现方法,在后面平台相关处理中,我会将linux的函数封装一下,和windows同名。此模板使用方法很简单:

  1. #if defined(_LIB) || defined(_USE_STATIC_LIB)   // 静态库版本   
  2.     #ifndef _LUA_ENGINE_API   
  3.         #define _LUA_ENGINE_API IMPORT_API   
  4.         #pragma comment(lib,  MAKE_LIB_NAME(LuaEngine))   
  5.     #endif   
  6.   
  7.     _LUA_ENGINE_API ILuaEngine* GlobalLuaEngine();  
  8. #else   
  9.     DECLARE_DLL_FILE(LuaEngine);  
  10.     class GlobalLuaEngine : public DllApi<LuaEngine>  
  11.     {  
  12.     typedef ILuaEngine* (*CREATE_PROC)();  
  13.     ILuaEngine* m_p;  
  14.     public:  
  15.         GlobalLuaEngine() : m_p(NULL)  
  16.         {  
  17.             Load();  
  18.             static CREATE_PROC func;  
  19.             if(func == NULL) func = (CREATE_PROC)::GetProcAddress(m_h, “GlobalLuaEngine”);  
  20.             if(func != NULL) m_p = func();  
  21.         }  
  22.         operator ILuaEngine* (){ return m_p; }  
  23.         ILuaEngine* operator ->(){ return m_p; }  
  24.     };  
  25. #endif  
#if defined(_LIB) || defined(_USE_STATIC_LIB)	// 静态库版本	#ifndef _LUA_ENGINE_API		#define _LUA_ENGINE_API IMPORT_API		#pragma comment(lib,  MAKE_LIB_NAME(LuaEngine))	#endif	_LUA_ENGINE_API ILuaEngine* GlobalLuaEngine();#else	DECLARE_DLL_FILE(LuaEngine);	class GlobalLuaEngine : public DllApi<LuaEngine>	{	typedef ILuaEngine* (*CREATE_PROC)();	ILuaEngine* m_p;	public:		GlobalLuaEngine() : m_p(NULL)		{			Load();			static CREATE_PROC func;			if(func == NULL) func = (CREATE_PROC)::GetProcAddress(m_h, "GlobalLuaEngine");			if(func != NULL) m_p = func();		}		operator ILuaEngine* (){ return m_p; }		ILuaEngine* operator ->(){ return m_p; }	};#endif

       如上面代码所示,LuaEngine是一个dll,我们在加载它的时候,使用了一个额外的类,在他的构造函数里面加载了共享库。而且在应用级上也与平台无关。

       3、跨平台的若干处理

       windows的处理相当简单,只是定义一些简单的宏。

  1. // gwindef.h : windows开发定义文件   
  2. #ifndef __G_WIN_DEF_H_   
  3. #define __G_WIN_DEF_H_   
  4.   
  5. #include <windows.h>   
  6. #include <process.h>   
  7. #include <tchar.h>   
  8. #include <unknwn.h>   
  9. #include <stdio.h>   
  10. #include <stdlib.h>   
  11.   
  12. #define SYS_API         WINAPI   
  13. #define STD_CALL        __stdcall   
  14. #if !defined(_LIB)   
  15. #define EXPORT_API      extern “C” _declspec(dllexport)   
  16. #else   
  17. #define EXPORT_API      extern “C”   
  18. #endif   
  19. #if !defined(_LIB) && !defined(_USE_STATIC_LIB)   
  20. #define IMPORT_API      extern “C” _declspec(dllimport)   
  21. #else   
  22. #define IMPORT_API      extern “C”   
  23. #endif   
  24.   
  25. #endif // ndef __G_WIN_DEF_H_  

 而为了开发的时候去除平台无关性,在linux的开发中,我们需要做一些包装,使其在开发过程中和window代码一致。

  1. // glindef.h : linux开发定义文件   
  2. #ifndef __G_LIN_DEF_H_   
  3. #define __G_LIN_DEF_H_   
  4. //    
  5. #include <stdlib.h>   
  6. #include <stdio.h>   
  7. #include <string.h>   
  8. #include <wchar.h>   
  9. #include <unistd.h>   
  10. #include <pthread.h>   
  11. #include <semaphore.h>   
  12. #include <errno.h>   
  13. #include <sys/times.h>   
  14. #include <time.h>   
  15. #include <dlfcn.h>   
  16. #include <sys/types.h>   
  17. #include <linux/unistd.h>   
  18.   
  19. inline _syscall0(pid_t, gettid)        /* Using syscall(2) may be preferable; see intro(2) */  
  20.   
  21. #ifdef UNICODE   
  22. #define _T(str)     L##str   
  23. #else   
  24. #define _T(str)     str   
  25. #endif   
  26.   
  27. #define TRUE        1   
  28. #define FALSE       0   
  29.   
  30. #define MAX_PATH        256   
  31.   
  32. #define SYS_API   
  33. #define STD_CALL   
  34. #define EXPORT_API      extern “C”   
  35. #define IMPORT_API      extern “C”   
  36.   
  37. /// HRESULT 常量定义   
  38. typedef long        HRESULT;  
  39. enum HResult  
  40. {  
  41.     S_OK = ((HRESULT)0x00000000),           /**< 成功,值为0 */  
  42.     S_FALSE = ((HRESULT)0x00000001),            /**< 成功,但值为1 */  
  43.     E_FAIL = _HRESULT_TYPEDEF_(0x80004005),     /**< 未定义错误 */  
  44.     E_NOTIMPL = _HRESULT_TYPEDEF_(0x80004001),      /**< 接口未实现 */  
  45.     E_OUTOFMEMORY = _HRESULT_TYPEDEF_(0x8007000E),  /**< 内存不足 */  
  46.     E_INVALIDARG = _HRESULT_TYPEDEF_(0x80070057),       /**< 无效参数 */  
  47.     E_NOINTERFACE = _HRESULT_TYPEDEF_(0x80004002),  /**< 接口不存在 */  
  48.     E_POINTER = _HRESULT_TYPEDEF_(0x80004003),      /**< 无效指针 */  
  49.     E_HANDLE = _HRESULT_TYPEDEF_(0x80070006),       /**< 无效句柄 */  
  50.     E_ABORT = _HRESULT_TYPEDEF_(0x80004004),        /**< 操作被取消 */  
  51.     E_ACCESSDENIED = _HRESULT_TYPEDEF_(0x80070005), /**< 访问拒绝 */  
  52.     E_PENDING = _HRESULT_TYPEDEF_(0x8000000A),      /**< 操作被挂起 */  
  53.     E_UNEXPECTED = _HRESULT_TYPEDEF_(0x8000FFFF)        /**< 未预料的错误 */  
  54. };  
  55.   
  56. /// 判定 HRESULT 值是否为成功值   
  57. #define SUCCEEDED(Status)   ((HRESULT)(Status) >= 0)   
  58. /// 判定 HRESULT 值是否为失败值   
  59. #define FAILED(Status)      ((HRESULT)(Status) < 0)   
  60.   
  61. /// GUID 类型定义   
  62. /** 
  63. 要定义 GUID 常量请使用 GUID 专门的生成工具(比如 VS 携带的 guidgen.exe 程序)来生成, 
  64. 以确保其唯一性。 
  65. 接口 ID(IID), 类 ID(CLSID)均为 GUID 的别名*/  
  66. struct GUID  
  67. {  
  68.     unsigned long  Data1;  
  69.     unsigned short Data2;  
  70.     unsigned short Data3;  
  71.     unsigned char  Data4[8];  
  72. };  
  73.   
  74. typedef GUID IID;  
  75. typedef GUID CLSID;  
  76. #define REFGUID const GUID&   
  77. #define REFIID const IID&   
  78. #define REFCLSID const CLSID&   
  79.   
  80. /// 判断两个 GUID 是否相等(内联版)   
  81. inline BOOL InlineIsEqualGUID(REFGUID rguid1, REFGUID rguid2)  
  82. {  
  83.     return ((long*)&rguid1)[0] == ((long*)&rguid2)[0] &&   
  84.         ((long*)&rguid1)[1] == ((long*)&rguid2)[1] &&  
  85.         ((long*)&rguid1)[2] == ((long*)&rguid2)[2] &&  
  86.         ((long*)&rguid1)[3] == ((long*)&rguid2)[3];  
  87. }  
  88.   
  89. /// 判断两个 GUID 是否相等   
  90. inline BOOL IsEqualGUID(REFGUID rguid1, REFGUID rguid2)  
  91. {  
  92.     return !memcmp(&rguid1, &rguid2, sizeof(GUID));  
  93. }  
  94.   
  95. #define CopyMemory(dest, src, len)      memcpy((dest), (src),(len))   
  96. #define ZeroMemory(dest, len)       memset((dest), 0, (len))   
  97. #define FillMemory(dest, len, value)        memset((dest), value, (len))   
  98. #define GetCurrentThreadId          gettid   
  99. #define OutputDebugString(str)      tprintf(_T(“%s”), str)   
  100. #define LoadLibrary(file)           dlopen(file, RTLD_NOW)   
  101. #define FreeLibrary         dlclose   
  102. #define GetProcAddress          dlsym   
  103.   
  104. inline int GetLastError()  
  105. {  
  106.     return errno;  
  107. }  
  108.   
  109. inline DWORD GetTickCount()  
  110. {  
  111.     static int clkTck = 0;  
  112.     if(clkTck == 0) clkTck = 1000 / ::sysconf(_SC_CLK_TCK);  
  113.     return (DWORD)::times(NULL) * clkTck;   // 不能溢出   
  114. }  
  115.   
  116. inline void Sleep(DWORD ms)  
  117. {  
  118.     struct timespec req, rem;  
  119.     req.tv_sec = ms / 1000; req.tv_nsec = (ms % 1000) * 1000000;  
  120.     while(::nanosleep(&req, &rem) && ::GetLastError() == EINTR) req = rem;  
  121. }  
  122.   
  123. inline long InterlockedIncrement(long volatile* v)  
  124. {  
  125.     long src = 1;  
  126.     /* Modern 486+ processor */  
  127.     __asm__ __volatile__(  
  128.         “lock xaddl %0, %1;”  
  129.         :”=r”(src), “=m”(*v)  
  130.         :”0″(src));  
  131.     return src + 1;  
  132. }  
  133.   
  134. inline long InterlockedDecrement(long volatile* v)  
  135. {  
  136.     long src = -1;  
  137.     /* Modern 486+ processor */  
  138.     __asm__ __volatile__(  
  139.         “lock xaddl %0, %1;”  
  140.         :”=r”(src), “=m”(*v)  
  141.         :”0″(src));  
  142.     return src – 1;  
  143. }  
  144.   
  145. #define stricmp                     strcasecmp   
  146.   
  147. #include <ctype.h>   
  148. inline void strupr(char *s)  
  149. {  
  150.     while (*s) {  
  151.         *s = toupper((unsigned char) *s);  
  152.         s++;  
  153.     }  
  154. }  
  155.   
  156. inline void strlwr(char *s)  
  157. {  
  158.     while (*s) {  
  159.         *s = tolower((unsigned char) *s);  
  160.         s++;  
  161.     }  
  162. }  
  163.   
  164. #endif // ndef __G_LIN_DEF_H_  
// glindef.h : linux开发定义文件
#ifndef __G_LIN_DEF_H_
#define __G_LIN_DEF_H_
// 
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <wchar.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <errno.h>
#include <sys/times.h>
#include <time.h>
#include <dlfcn.h>
#include <sys/types.h>
#include <linux/unistd.h>

inline _syscall0(pid_t, gettid)        /* Using syscall(2) may be preferable; see intro(2) */

#ifdef UNICODE
#define _T(str)		L##str
#else
#define _T(str)		str
#endif

#define TRUE		1
#define FALSE		0

#define MAX_PATH		256

#define SYS_API
#define STD_CALL
#define EXPORT_API		extern "C"
#define IMPORT_API		extern "C"

/// HRESULT 常量定义
typedef long		HRESULT;
enum HResult
{
	S_OK = ((HRESULT)0x00000000),			/**< 成功,值为0 */
	S_FALSE = ((HRESULT)0x00000001),			/**< 成功,但值为1 */
	E_FAIL = _HRESULT_TYPEDEF_(0x80004005),		/**< 未定义错误 */
	E_NOTIMPL = _HRESULT_TYPEDEF_(0x80004001),		/**< 接口未实现 */
	E_OUTOFMEMORY = _HRESULT_TYPEDEF_(0x8007000E),	/**< 内存不足 */
	E_INVALIDARG = _HRESULT_TYPEDEF_(0x80070057),		/**< 无效参数 */
	E_NOINTERFACE = _HRESULT_TYPEDEF_(0x80004002),	/**< 接口不存在 */
	E_POINTER = _HRESULT_TYPEDEF_(0x80004003),		/**< 无效指针 */
	E_HANDLE = _HRESULT_TYPEDEF_(0x80070006),		/**< 无效句柄 */
	E_ABORT = _HRESULT_TYPEDEF_(0x80004004),		/**< 操作被取消 */
	E_ACCESSDENIED = _HRESULT_TYPEDEF_(0x80070005),	/**< 访问拒绝 */
	E_PENDING = _HRESULT_TYPEDEF_(0x8000000A),		/**< 操作被挂起 */
	E_UNEXPECTED = _HRESULT_TYPEDEF_(0x8000FFFF)		/**< 未预料的错误 */
};

/// 判定 HRESULT 值是否为成功值
#define SUCCEEDED(Status)	((HRESULT)(Status) >= 0)
/// 判定 HRESULT 值是否为失败值
#define FAILED(Status)		((HRESULT)(Status) < 0)

/// GUID 类型定义
/**
要定义 GUID 常量请使用 GUID 专门的生成工具(比如 VS 携带的 guidgen.exe 程序)来生成,
以确保其唯一性。
接口 ID(IID), 类 ID(CLSID)均为 GUID 的别名*/
struct GUID
{
    unsigned long  Data1;
    unsigned short Data2;
    unsigned short Data3;
    unsigned char  Data4[8];
};

typedef GUID IID;
typedef GUID CLSID;
#define REFGUID const GUID&
#define REFIID const IID&
#define REFCLSID const CLSID&

/// 判断两个 GUID 是否相等(内联版)
inline BOOL InlineIsEqualGUID(REFGUID rguid1, REFGUID rguid2)
{
	return ((long*)&rguid1)[0] == ((long*)&rguid2)[0] && 
		((long*)&rguid1)[1] == ((long*)&rguid2)[1] &&
		((long*)&rguid1)[2] == ((long*)&rguid2)[2] &&
		((long*)&rguid1)[3] == ((long*)&rguid2)[3];
}

/// 判断两个 GUID 是否相等
inline BOOL IsEqualGUID(REFGUID rguid1, REFGUID rguid2)
{
    return !memcmp(&rguid1, &rguid2, sizeof(GUID));
}

#define CopyMemory(dest, src, len)		memcpy((dest), (src),(len))
#define ZeroMemory(dest, len)		memset((dest), 0, (len))
#define FillMemory(dest, len, value)		memset((dest), value, (len))
#define GetCurrentThreadId			gettid
#define OutputDebugString(str)		tprintf(_T("%s"), str)
#define LoadLibrary(file)			dlopen(file, RTLD_NOW)
#define FreeLibrary			dlclose
#define GetProcAddress			dlsym

inline int GetLastError()
{
	return errno;
}

inline DWORD GetTickCount()
{
	static int clkTck = 0;
	if(clkTck == 0) clkTck = 1000 / ::sysconf(_SC_CLK_TCK);
	return (DWORD)::times(NULL) * clkTck;	// 不能溢出
}

inline void Sleep(DWORD ms)
{
	struct timespec req, rem;
	req.tv_sec = ms / 1000; req.tv_nsec = (ms % 1000) * 1000000;
	while(::nanosleep(&req, &rem) && ::GetLastError() == EINTR) req = rem;
}

inline long InterlockedIncrement(long volatile* v)
{
	long src = 1;
	/* Modern 486+ processor */
	__asm__ __volatile__(
		"lock xaddl %0, %1;"
		:"=r"(src), "=m"(*v)
		:"0"(src));
	return src + 1;
}

inline long InterlockedDecrement(long volatile* v)
{
	long src = -1;
	/* Modern 486+ processor */
	__asm__ __volatile__(
		"lock xaddl %0, %1;"
		:"=r"(src), "=m"(*v)
		:"0"(src));
	return src - 1;
}

#define stricmp						strcasecmp

#include <ctype.h>
inline void strupr(char *s)
{
	while (*s) {
		*s = toupper((unsigned char) *s);
		s++;
	}
}

inline void strlwr(char *s)
{
	while (*s) {
		*s = tolower((unsigned char) *s);
		s++;
	}
}

#endif // ndef __G_LIN_DEF_H_

       代码都比较简单,我也不对这些做详细的解析,功能就是对一些常用函数改装成windows相关函数的名字。如果在开发中遇到了其他的情况,也可以加到此文件中,以方便应用开发。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/125579.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • emwin实体按键_qt指示灯控件

    emwin实体按键_qt指示灯控件分享一个emWin软键盘控件[复制链接]本帖最后由glcd于2016-6-2716:30编辑花了两天时间做了个emWin软键盘控件,并命名为ButtonSKB控件:image001.png(20.29KB,下载次数:0)2016-6-2716:19上传前言:(1)ButtonSKB已经是1个控件,即可以像使用Button控件一样使用ButtonSKB。(2)ButtonSKB…

    2022年10月14日
  • 剑指offer——二进制中1的个数(解释n & 0xFFFFFFFF)[通俗易懂]

    剑指offer——二进制中1的个数(解释n & 0xFFFFFFFF)[通俗易懂]题目描述:输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。解答如下:环境:python2.7.3正数的原码反码补码都一样负数的补码是其对应正数的反码加1这里需要弄清楚为什么python中负数需要和0xFFFFFFFF做与操作?在计算机中,所有的数字都是使用补码存储起来的。由于Python没有位数这个概念,所以得到二进制表示需要多一点操作,即将位数限制在32位,…

  • oracle创建索引的sql语句_mysql创建组合索引

    oracle创建索引的sql语句_mysql创建组合索引Oracle创建索引

  • idea 激活码【注册码】

    idea 激活码【注册码】,https://javaforall.cn/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

  • kafka教程_scala为什么用的很少

    kafka教程_scala为什么用的很少kafka教程第1章 Kafka概述1.1定义1.2消息队列1.2.1传统消息队列的应用场景消息队列的好处1.2.2消息队列的两种模式1.3什么是Kafka1.4Kafka架构1.5kafka名词解释1.6消息格式第2章Kafka集群部署2.1环境准备2.1.1集群规划2.1.2jar包下载2.2Kafka集群部署2.3Kafka命令行操作1)查看topic2)创建topic3)删除topic4)发送消息5)消费消息第3章Kafka工作流程分析3.1kafka工作流程及文件存

    2022年10月17日
  • 每天学点GDB 3

    每天学点GDB 3

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号