1 // ----------------------------------------------------------------------
2 // RakNet version 1.411
3 // BitStreamSample.cpp
4 // Created by Rakkar Software (rakkar@jenkinssoftware.com) December 8, 2003
5 // Shows simple use of the bitstream class
6 // ----------------------------------------------------------------------
7 
8 #include "RakPeerInterface.h"
9 #include "RakNetworkFactory.h"
10 #include "BitStream.h"
11 #include "RakSleep.h"
12 #include <stdlib.h> // For atoi
13 #include <cstring> // For strlen
14 #include <stdio.h>
15 #include <string.h>
16 #include "Kbhit.h"
17 
18 #ifdef _COMPATIBILITY_1
19 #include "Compatibility1Includes.h" // Developers of a certain platform will know what to do here.
20 #elif defined(_PS3) || defined(__PS3__)
21 #include "Console2SampleIncludes.h"
22 #elif defined (_XBOX)
23 #elif defined(_WIN32)
24 #include "WindowsIncludes.h" // Sleep
25 #else
26 #include <unistd.h> // usleep
27 #include <cstdio>
28 #endif
29 
30 bool quit;
31 
32 using namespace RakNet;
33 
34 // We want to send information about a person and their job.
35 // We are interested in their name, age, salary, and years employed.
36 // For this sample we encode the data as follows:
37 // 1. Number of characters of the person's name
38 // 2. Person's name (not null terminated)
39 // 3. Person's age (compressed unsigned char)
40 // 4. The EmploymentStruct (below)
41 struct EmploymentStruct
42 {
43 	int salary;
44 	unsigned char yearsEmployed;
45 };
46 
47 // You can parse the input data in two ways.
48 // Either cast input to a struct (such as if you sent a struct)
49 // Or create a BitStream instance with input as data such as
50 // BitStream myBitStream(input, (numberOfBitsOfData-1)/8+1);
51 // where (numberOfBitsOfData-1)/8+1 is the number of bytes of data
52 // If you didn't pass any data then of course you don't do either
53 // Here we pass a bitstream
clientRPC(RPCParameters * rpcParameters)54 void clientRPC(RPCParameters *rpcParameters)
55 {
56 	// Since we were passed a bitstream, to make things easier to parse convert the input into into a BitStream.
57 	// We can either do this in the constructor which takes the data and the number of BYTES
58 	// BitStream b(input, (numberOfBitsOfData-1)/8+1);
59 	// or we can do it by writing out the bits
60 	// BitStream b;
61 	// b.WriteBits(input, numberOfBitsOfData);
62 
63 	// Here I will do the constructor version because it is easier.  numberOfBitsOfData is always > 0
64 	// The third parameter of false means don't internally copy input but just maintain a pointer to it.  This is fine because we never change it
65 	BitStream b(rpcParameters->input, BITS_TO_BYTES(rpcParameters->numberOfBitsOfData), false);
66 	char name[200];
67 
68 //	printf("GOT RPC:\n");
69 //	b.PrintBits();
70 
71 	// The length of the person's name.  It is critical to read the same types in the same order using the same level of compression as we wrote them
72 	unsigned char nameLength;
73 	b.Read(nameLength);
74 	if (b.Read(name, nameLength)==false) // Name is not null terminated
75 		// Note we always check if the read functions return false.  This is important in a real example in case hackers or programmer error causes too-short bitstreams
76 		// You would probably also log this event or throw an assert in a real game
77 	{
78 		printf("Name was not null-terminated!\n");
79 		return;
80 	}
81 
82 	name[nameLength]=0; // Name is now null terminated
83 
84 	printf("In clientRPC:\n");
85 	printf("Name is %s\n", name);
86 
87 	unsigned int age;
88 	// We used WriteCompressed for the age, so have to use ReadCompressed to get it
89 	if (b.ReadCompressed(age)==false)
90 		return;
91 
92 	printf("Age is %i\n", age);
93 	fflush(stdout);
94 
95 	bool wroteEmploymentStruct;
96 	if (b.Read(wroteEmploymentStruct)==false)
97 	{
98 		return;
99 	}
100 
101 	if (wroteEmploymentStruct)
102 	{
103 		printf("We are employed.\n");
104 
105 		EmploymentStruct employmentStruct;
106 		// Reading a struct consists of deserializing the bitstream:
107 		if (b.Read(employmentStruct.salary)==false) return;
108 		if (b.Read(employmentStruct.yearsEmployed)==false) return;
109 
110 		printf("Salary is %i.  Years employed is %i\n", employmentStruct.salary, (int)employmentStruct.yearsEmployed);
111 	}
112 	else
113 		printf("We are between jobs :)\n");
114 
115 	quit=true;
116 }
117 
118 #if defined(_PS3) || defined(__PS3__)
119 _PS3_SetSystemProcessParams
120 #endif
121 
main(void)122 int main(void)
123 {
124 	RakPeerInterface *rakClient=RakNetworkFactory::GetRakPeerInterface();
125 	RakPeerInterface *rakServer=RakNetworkFactory::GetRakPeerInterface();
126 #ifndef WIN32
127 #define getch getchar
128 #endif
129 
130 #if defined(_PS3) || defined(__PS3__)
131 	PS3LoadModules();
132 #endif
133 	quit=false;
134 	char text[255];
135 
136 	// Defined in RakNetTypes.h.
137 	// You can register a function anytime
138 	REGISTER_STATIC_RPC(rakClient, clientRPC);
139 
140 	//rakServer->InitializeSecurity(0,0,0,0);
141 
142 	SocketDescriptor socketDescriptor(10000,0);
143 	if (rakServer->Startup(1,30,&socketDescriptor, 1)==false)
144 	{
145 		printf("Start call failed!\n");
146 
147 		fflush(stdout);
148 		fgets(text, sizeof(text), stdin);
149 		printf("\n");
150 		return 0;
151 	}
152 	rakServer->SetMaximumIncomingConnections(1);
153 	socketDescriptor.port=0;
154 	rakClient->Startup(1, 30, &socketDescriptor, 1);
155 	if (rakClient->Connect("127.0.0.1", 10000, 0, 0)==false)
156 	{
157 		printf("Connect call failed\n");
158 		fflush(stdout);
159 		fgets(text, sizeof(text), stdin);
160 		printf("\n");
161 		return 0;
162 	}
163 
164 	BitStream outgoingBitstream;
165 	unsigned int age;
166 
167 	printf("A sample on how to use RakNet's bitstream class\n");
168 	printf("Difficulty: Beginner\n\n");
169 
170 	printf("Enter your name.\n");
171 	fflush(stdout);
172 	fgets(text, sizeof(text), stdin);
173 	printf("\n");
174 	if (text[0]==0)
175 		strcpy(text, "Unnamed!");
176 	// Write the number of characters of the name into the bitstream
177 	// We put the unsigned char cast to use the overload that writes 1 byte.
178 	outgoingBitstream.Write((unsigned char)strlen(text));
179 
180 	// Now write the name to the bitstream.  This overload takes a char* and the number of bytes to write
181 	outgoingBitstream.Write(text, (int) strlen(text));
182 
183 	printf("Enter your age (numbers only).\n");
184 	fflush(stdout);
185 	fgets(text, sizeof(text), stdin);
186 	printf("\n");
187 	if (text[0]==0)
188 		age=0;
189 	else
190 		age=atoi(text);
191 
192 	// Write age to the bitstream.  Since the range of age is
193 	// probably pretty low compared to the range of the variable (uint),
194 	// we use a compressed write.  This can reduce the number
195 	// of bits used.
196 	outgoingBitstream.WriteCompressed(age);
197 
198 	// Now demonstrate dynamic packets by choosing one of two paths in which to write different amounts / types of data.
199 	printf("Are you employed (y/n)?\n");
200 	fflush(stdout);
201 	fgets(text, sizeof(text), stdin);
202 	printf("\n");
203 	if (text[0]=='y')
204 	{
205 		outgoingBitstream.Write(true); // Writing a bool takes 1 bit
206 
207 		// Read some data into a struct
208 		EmploymentStruct employmentStruct;
209 		printf("What is your salary (enter a number only)?\n");
210 		fflush(stdout);
211 		fgets(text, sizeof(text), stdin);
212 		printf("\n");
213 		employmentStruct.salary = atoi(text);
214 		printf("How many years have you been employed (enter a number only)?\n");
215 		fflush(stdout);
216 		fgets(text, sizeof(text), stdin);
217 		printf("\n");
218 		employmentStruct.yearsEmployed = atoi(text);
219 
220 		// We can write structs to a bitstream but this is not portable due to:
221 		//  1. Different-endian CPUs
222 		//  2. Different 'padding' of structs depending on compiler, etc
223 		// The only safe way to send a struct is by using the BitStream
224 		// to write out every single member which you want to send.
225 		outgoingBitstream.Write(employmentStruct.salary);
226 		outgoingBitstream.Write(employmentStruct.yearsEmployed);
227 		// We're done writing to the struct
228 	}
229 	else
230 	{
231 		//printf("Number of bits before [false]: %d\n",
232 		//outgoingBitstream.GetNumberOfBitsUsed() );
233 		outgoingBitstream.Write(false); // Writing a bool takes 1 bit
234 		// We're done writing to the struct.  Compare this to the example above - we wrote quite a bit less.
235 	}
236 
237 	printf("Waiting for connection...\n");
238 	while (rakClient->GetSystemAddressFromIndex(0)==UNASSIGNED_SYSTEM_ADDRESS)
239 		RakSleep(30);
240 	printf("Connected.\n");
241 
242 //	printf("SEND RPC:\n");
243 //	outgoingBitstream.PrintBits();
244 
245 	// RPC functions as well as send can take bitstreams directly
246 	bool success = rakServer->RPC("clientRPC",&outgoingBitstream, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID, 0); // broadcast to everyone, which happens to be our one client
247 	if (!success)
248 		printf("RPC call failed\n");
249 
250 	while (!quit)
251 	{
252 		rakClient->DeallocatePacket(rakClient->Receive());
253 		rakServer->DeallocatePacket(rakServer->Receive());
254 
255 		RakSleep(30);
256 	}
257 	printf("Press enter to quit\n");
258 	fflush(stdout);
259 	fgets(text, sizeof(text), stdin);
260 	printf("\n");
261 
262 	rakClient->Shutdown(100,0);
263 	rakServer->Shutdown(100,0);
264 
265 	// This is not necessary since on shutdown everything is unregistered.  This is just here to show usage
266 	UNREGISTER_STATIC_RPC(rakClient, clientRPC);
267 
268 	RakNetworkFactory::DestroyRakPeerInterface(rakClient);
269 	RakNetworkFactory::DestroyRakPeerInterface(rakServer);
270 
271 	return 0;
272 }
273