1 /*
2 
3   Client DLL functions. (New to r1q2). The client dll is a separate project that exports
4   a bunch of stuff that the client engine can hook up to to manipulate local entities and
5   in some way manipulate the renderer too... example:
6 
7   Server sends event X on a dead body, client parses event x in normal entity parsing.
8   Event x is unhandled by the client, so it passes it on to the client DLL which could
9   do one of several things such as spawn local ents, create decals in the renderer, etc.
10 
11   The interface between the client DLL and the engine/renderer is (attempted) to be
12   controlled from this file.
13 
14   Eventually, most of the constants in the client parsing system should end up in
15   the client dll, for example, all tempents should be done via the client dll. A generic
16   dll will be supplied with r1q2 that maintains all the functionality of the default
17   engine - ie it can be dropped into any mod dir to emulate the functions that would
18   have been in the exe.
19 
20  */
21 
22 //shared by the client_dll project
23 #ifdef CLIENT_DLL
24 #include "client.h"
25 #include "../win32/winquake.h"
26 
27 HINSTANCE	cllib_library;		// Handle to client DLL
28 qboolean	cllib_active = false;
29 clexport_t	ce;
30 
31 /*
32 ==========
33 CL_FreeCllib
34 ==========
35 Unload the client dll and nuke anything it allocated.
36 */
CL_FreeCllib(void)37 void CL_FreeCllib (void)
38 {
39 	if ( !FreeLibrary( cllib_library ) )
40 		Com_Error( ERR_FATAL, "Cllib FreeLibrary failed" );
41 
42 	memset (&ce, 0, sizeof(ce));
43 
44 	//nuke anything the DLL allocated
45 	Z_FreeTags (TAGMALLOC_CLIENT_DLL);
46 
47 	cllib_library = NULL;
48 	cllib_active  = false;
49 }
50 
51 /*
52 ===========
53 CL_Z_Alloc
54 ===========
55 Allocate memory to the client DLL via Z_TagMalloc (but without the DLL
56 having to specify the tag) - used to free it all when the DLL is unloaded
57 above.
58 */
CL_Z_Alloc(int size)59 void *CL_Z_Alloc (int size)
60 {
61 	return (void *)Z_TagMalloc (size, TAGMALLOC_CLIENT_DLL);
62 }
63 
64 /*
65 ===========
66 CL_InitClientDLL
67 ===========
68 Attempt to load the dll, send it the exports and grab the imports.
69 */
CL_InitClientDLL(void)70 qboolean CL_InitClientDLL (void)
71 {
72 	char name[MAX_OSPATH];
73 	GetClAPI_t	GetClAPI;
74 	climport_t	ci;
75 
76 	Com_sprintf (name, sizeof(name), "%s/client_dll.dll", FS_Gamedir());
77 
78 	if ( cllib_active )
79 	{
80 		ce.Shutdown();
81 		CL_FreeCllib ();
82 	}
83 
84 	Com_Printf( "------ Loading client_dll.dll ------\n", LOG_CLIENT);
85 
86 	if ( ( cllib_library = LoadLibrary( name ) ) == 0 )
87 	{
88 		Com_Printf( "LoadLibrary(\"%s\") failed\n", LOG_CLIENT, name );
89 		return false;
90 	}
91 
92 	if ( ( GetClAPI = (GetClAPI_t)GetProcAddress( cllib_library, "GetClAPI" ) ) == 0 ) {
93 		Com_Printf("GetProcAddress failed on %s\n", LOG_CLIENT, name );
94 		return false;
95 	}
96 
97 	ci.MSG_ReadChar = MSG_ReadChar;
98 	ci.MSG_ReadByte = MSG_ReadByte;
99 	ci.MSG_ReadShort = MSG_ReadShort;
100 	ci.MSG_ReadLong = MSG_ReadLong;
101 	ci.MSG_ReadFloat = MSG_ReadFloat;
102 	ci.MSG_ReadString = MSG_ReadString;
103 	ci.MSG_ReadStringLine = MSG_ReadStringLine;
104 
105 	ci.MSG_ReadCoord= MSG_ReadCoord;
106 	ci.MSG_ReadPos = MSG_ReadPos;
107 	ci.MSG_ReadAngle = MSG_ReadAngle;
108 	ci.MSG_ReadAngle16 = MSG_ReadAngle16;
109 
110 	ci.MSG_ReadDir = MSG_ReadDir;
111 	ci.MSG_ReadData = MSG_ReadData;
112 
113 	ci.Cmd_AddCommand = Cmd_AddCommand;
114 	ci.Cmd_RemoveCommand = Cmd_RemoveCommand;
115 
116 	ci.Cmd_Argc = Cmd_Argc;
117 	ci.Cmd_Argv = Cmd_Argv;
118 
119 	ci.Cmd_ExecuteText = Cbuf_ExecuteText;
120 
121 	ci.Com_Printf = Com_Printf;
122 	ci.Com_Error = Com_Error;
123 
124 	ci.FS_LoadFile = FS_LoadFile;
125 	ci.FS_FreeFile = FS_FreeFile;
126 	ci.FS_Gamedir = FS_Gamedir;
127 
128 	ci.Z_Alloc = CL_Z_Alloc;
129 	ci.Z_Free = Z_Free;
130 
131 	ci.Cvar_Get = Cvar_Get;
132 	ci.Cvar_Set = Cvar_Set;
133 	ci.Cvar_SetValue = Cvar_SetValue;
134 
135 	ce = GetClAPI( ci );
136 
137 	switch (ce.api_version) {
138 		case 1:
139 			break;
140 		default:
141 			CL_FreeCllib ();
142 			Com_Printf (PRODUCTNAME " doesn't support your client dll version (%s)\n", LOG_CLIENT, name);
143 			return false;
144 	}
145 
146 	if ( ce.Init( global_hInstance ) == -1 )
147 	{
148 		ce.Shutdown();
149 		CL_FreeCllib ();
150 		return false;
151 	}
152 
153 	Com_Printf( "------------------------------------\n", LOG_CLIENT);
154 	cllib_active = true;
155 
156 	return true;
157 }
158 
159 /*
160 =============
161 CL_ClDLL_Restart_f
162 =============
163 (Re)load the client dll after switching games.
164 */
CL_ClDLL_Restart_f(void)165 void CL_ClDLL_Restart_f (void)
166 {
167 	if (!CL_InitClientDLL ()) {
168 		Com_Printf( "------------------------------------\n", LOG_CLIENT);
169 	}
170 }
171 #endif
172