/* * Created by Hassan "Karajorma" Kazmi for the FreeSpace2 Source Code Project. * You may not sell or otherwise commercially exploit the source or things you * create based on the source. */ #include "network/multi_sexp.h" #include "network/psnet2.h" #include "network/multimsgs.h" #include "parse/sexp.h" #include "network/multi.h" #include "network/multiutil.h" #define SEND_PACKET_NOW 384 // (MAX_PACKET_SIZE/4)*3 used to tell when a packet is 3/4 full. #define PACKET_TERMINATOR 255 int TEMP_DATA_SIZE = -1; #define TYPE_NOT_DATA -1 #define TYPE_SEXP_OPERATOR 0 #define TYPE_ARGUMENT_COUNT 1 #define TYPE_DATA_TERMINATES 2 #define TYPE_INT 3 #define TYPE_SHIP 4 #define TYPE_STRING 5 #define TYPE_PARSE_OBJECT 6 #define TYPE_BOOLEAN 7 #define TYPE_FLOAT 8 // the type array holds information on the type of date held at the same index of the data array // types are not sent to the client and the entire array could be replaced with a couple of variables indexing the end of // the previous SEXP. However it is much more helpful when debugging to have the array int type[MAX_PACKET_SIZE]; int argument_count_index = -1; // index in the type and data arrays for the argument count int current_argument_count = 0; // number of bytes the data for this SEXP currently takes up // these 3 variable names must remain the same as those used in multimsgs.h in order for the macros to work ubyte data[MAX_PACKET_SIZE]; int packet_size = 0; int offset = 0; int Multi_sexp_bytes_left = 0; // number of bytes in incoming packet that still require processing int op_num = -1; //forward declarations void multi_sexp_maybe_send_packet(); /************************** HOST SIDE PACKET FUNCTIONS *************************/ void initalise_sexp_packet() { memset(data, 0, MAX_PACKET_SIZE); memset(type, -1, MAX_PACKET_SIZE); packet_size = 0; argument_count_index = -1; current_argument_count = 0; } void multi_start_packet() { if (!MULTIPLAYER_MASTER) { return; } //Write OP into the Type buffer. type[packet_size] = TYPE_SEXP_OPERATOR; //Write the SEXP_Operator number into the data buffer. Assert (!Current_sexp_operator.empty()); ADD_INT(Current_sexp_operator.back()); //Store the next data index as we'll need it later to write the COUNT. argument_count_index = packet_size; // store an invalid count, we'll come back and store the correct value once we know what it is. type[packet_size] = TYPE_ARGUMENT_COUNT; ADD_INT(TEMP_DATA_SIZE); } void multi_end_packet() { if (!MULTIPLAYER_MASTER) { return; } //write TERMINATOR into the Type and data buffers type[packet_size] = TYPE_DATA_TERMINATES; ubyte b = PACKET_TERMINATOR; ADD_DATA(b); //Write the COUNT into the data buffer at the index we saved earlier. int temp_packet_size = packet_size; packet_size = argument_count_index; ADD_INT(current_argument_count); packet_size = temp_packet_size; current_argument_count = 0; multi_sexp_maybe_send_packet(); } void multi_sexp_maybe_send_packet() { if (!MULTIPLAYER_MASTER) { return; } int packet_end = 0; int sub_packet_size = 0; int i, j; //If the index of the data buffer isn't high enough yet, bail if (packet_size < SEND_PACKET_NOW) { return; } //iterate back through the types array until we find a TERMINATOR and store the corresponding data index for (i = packet_size-1; i > 0; i--) { if ( type[i] == TYPE_DATA_TERMINATES) { packet_end = i; break; } } // we want the number of bytes not the index of the last one sub_packet_size = packet_end + 1; Assert (packet_end > 8); // At very least must include OP, COUNT, TERMINATOR // in the case of a corrupt packet, wipe everything and start again if (packet_end < 9) { initalise_sexp_packet(); return; } send_sexp_packet(data, packet_end + 1); j = 0; //Slide down any entries after the stored index to the start of the array. for (i = sub_packet_size; i < packet_size; i++) { data[j] = data[i]; type[j] = type[i]; j++; } // if we have an existing argument count we need to update where to put it too if (current_argument_count) { argument_count_index -= sub_packet_size; } packet_size = j; } // flushes out the packet and sends any data still in there void multi_sexp_flush_packet() { if (!MULTIPLAYER_MASTER) { return; } // possible to get here when there is nothing in the packet to send if (packet_size == 0){ return; } Assert (type[packet_size -1] == TYPE_DATA_TERMINATES); send_sexp_packet(data, packet_size); initalise_sexp_packet(); } /******************************** HOST SIDE DATA WRAPPER FUNCTIONS *******************************/ void multi_send_int(int value) { if (!MULTIPLAYER_MASTER) { return; } //Write INT into the Type buffer. type[packet_size] = TYPE_INT; //Write the int into the data buffer ADD_INT(value); //Increment the COUNT by 4 (i.e the size of an int). current_argument_count += sizeof(int); multi_sexp_maybe_send_packet(); } void multi_send_ship(int shipnum) { if (!MULTIPLAYER_MASTER) { return; } multi_send_ship(&Ships[shipnum]); } void multi_send_ship(ship *shipp) { if (!MULTIPLAYER_MASTER) { return; } //write into the Type buffer. type[packet_size] = TYPE_SHIP; //write the into the data buffer ADD_USHORT(Objects[shipp->objnum].net_signature); current_argument_count += sizeof(ushort); multi_sexp_maybe_send_packet(); } void multi_send_parse_object(p_object *pobjp) { if (!MULTIPLAYER_MASTER) { return; } //write into the Type buffer. type[packet_size] = TYPE_PARSE_OBJECT; //write the into the data buffer ADD_USHORT(pobjp->net_signature); current_argument_count += sizeof(ushort); multi_sexp_maybe_send_packet(); } void multi_send_string(char *string) { if (!MULTIPLAYER_MASTER) { return; } int start_size = packet_size; //write into the Type buffer. type[packet_size] = TYPE_STRING; //write the into the data buffer ADD_STRING(string); current_argument_count += packet_size - start_size; multi_sexp_maybe_send_packet(); } void multi_send_bool(bool value) { if (!MULTIPLAYER_MASTER) { return; } //Write INT into the Type buffer. type[packet_size] = TYPE_BOOLEAN; //Write the value into the data buffer ADD_DATA(value); //Increment the COUNT current_argument_count += sizeof(value); multi_sexp_maybe_send_packet(); } void multi_send_float(float value) { if (!MULTIPLAYER_MASTER) { return; } //Write INT into the Type buffer. type[packet_size] = TYPE_FLOAT; //Write the value into the data buffer ADD_FLOAT(value); //Increment the COUNT current_argument_count += sizeof(float); multi_sexp_maybe_send_packet(); } /**************************** CLIENT SIDE PACKET FUNCTIONS ***************************/ void sexp_packet_received(ubyte *received_packet, int num_ubytes) { int i; offset = 0; op_num = -1; for (i=0; i < MAX_PACKET_SIZE; i++) { data[i] = received_packet[i]; } Multi_sexp_bytes_left = num_ubytes; // start working through the packet multi_sexp_eval(); } int multi_sexp_get_next_operator() { GET_INT(op_num); Multi_sexp_bytes_left -= sizeof(int); GET_INT(current_argument_count); Multi_sexp_bytes_left -= sizeof(int); Assert (Multi_sexp_bytes_left); return op_num; } int multi_sexp_get_operator() { return op_num; } void multi_reduce_counts(int amount) { ubyte terminator; Multi_sexp_bytes_left -= amount; current_argument_count -= amount; if (Multi_sexp_bytes_left < 0 || current_argument_count < 0) { Warning(LOCATION, "multi_get_x function call has read an invalid amount of data. Trace out and fix this!"); } if (current_argument_count == 0) { // read in the terminator GET_DATA(terminator); if (terminator != PACKET_TERMINATOR) { Warning(LOCATION, "multi_get_x function call has been called on an improperly terminated packet. Trace out and fix this!"); // discard remainder of packet Multi_sexp_bytes_left = 0; return; } Multi_sexp_bytes_left--; op_num = -1; } } bool multi_sexp_discard_operator() { int i; ubyte dummy; ubyte terminator; // read in a number of bytes equal to the count for (i=0; itype == OBJ_SHIP) && (objp->instance >=0)){ value = objp->instance; return true; } Warning(LOCATION, "multi_get_ship called for object %d even though it is not a ship", objp->instance); return false; } bool multi_get_ship(ship* &shipp) { int shipnum; if (multi_get_ship(shipnum)) { shipp = &Ships[shipnum]; return true; } return false; } bool multi_get_parse_object(p_object*& pobjp) { ushort netsig; if (!Multi_sexp_bytes_left || !current_argument_count) { return false; } // get the net signature of the ship GET_USHORT(netsig); multi_reduce_counts(sizeof(ushort)); // lookup the object pobjp = mission_parse_get_arrival_ship(netsig); if(pobjp != NULL){ return true; } return false; } bool multi_get_string(char *buffer) { int starting_offset = offset; if (!Multi_sexp_bytes_left || !current_argument_count) { return false; } GET_STRING(buffer); multi_reduce_counts(offset - starting_offset); return true; } bool multi_get_bool(bool &value) { if (!Multi_sexp_bytes_left || !current_argument_count) { return false; } GET_DATA(value); multi_reduce_counts(sizeof(value)); return true; } bool multi_get_float(float &value) { if (!Multi_sexp_bytes_left || !current_argument_count) { return false; } GET_FLOAT(value); multi_reduce_counts(sizeof(float)); return true; }