Making client app, when server is done is nothing to worry about. We must add Client class at start:
class Client : public ZCom_Control { virtual void ZCom_cbConnectResult( ZCom_ConnID _id, eZCom_ConnectResult _result, ZCom_BitStream &_reply ) { other_id = _id; //Storing id of other computer } void ZCom_cbConnectionClosed( ZCom_ConnID _id, eZCom_CloseReason _reason, ZCom_BitStream &_reasondata ) { put_string("Connection to server closed.", ""); } // data was received void ZCom_cbDataReceived(ZCom_ConnID _id, ZCom_BitStream &_data) { put_string(_data.getString(), _data.getString()); } bool ZCom_cbConnectionRequest( ZCom_ConnID _id, ZCom_BitStream &_request, ZCom_BitStream &_reply ){return false;} void ZCom_cbConnectionSpawned( ZCom_ConnID _id ) {} bool ZCom_cbZoidRequest( ZCom_ConnID _id, zU8 _requested_level, ZCom_BitStream &_reason ) {return false;} void ZCom_cbZoidResult( ZCom_ConnID _id, eZCom_ZoidResult _result, zU8 _new_level, ZCom_BitStream &_reason ) {} void ZCom_cbNodeRequest_Dynamic( ZCom_ConnID _id, ZCom_ClassID _requested_class, ZCom_BitStream *_announcedata, eZCom_NodeRole _role, ZCom_NodeID _net_id ) {} void ZCom_cbNodeRequest_Tag( ZCom_ConnID _id, ZCom_ClassID _requested_class, ZCom_BitStream *_announcedata, eZCom_NodeRole _role, zU32 _tag ) {} bool ZCom_cbDiscoverRequest( const ZCom_Address &_addr, ZCom_BitStream &_request, ZCom_BitStream &_reply ) {return false;} void ZCom_cbDiscovered( const ZCom_Address & _addr, ZCom_BitStream &_reply ) {} };
It looks just like the server class, isn’t it?
Now, remember to change declaration:
Server* server = NULL;
to
Client* client = NULL;
And in shutdown add:
delete client;
Also in process() function you must change every word “server” to “client”.
Most of changes is in start() Delete everything what server used and add:
zcom = new ZoidCom("netlog.txt"); //creating new object //netlog.txt is a file //where zoidcom will save his log if (!zcom || !zcom->Init()) exit(255); //if initialization fails -> quit //Important thing, timeout, after this time (in miliseconds), //if the other machine isn't respondig we break connection //and func ZCom_cbConnectionClosed() is executed. zcom->setConnectionTimeout(2000); //Our client object based on class we defined eariler client = new Client(); client->ZCom_setDebugName("Chatic Client"); client->ZCom_initSockets(true, 0, 0); //Let computer decide put_string("Connecting...", ""); //Inform user that chat is //connecting //Addres variable ZCom_Address server_addr; //Setting addres, you can put there your IP:Port if you want server_addr.setAddress( eZCom_AddressUDP, 0, "localhost:10000"); //Try to connect client->ZCom_Connect(server_addr, NULL);
Complete source code:
#include <zoidcom.h> //Zoidcom library include #include <allegro.h> //Allegro library include #include <conio.h> //Windows library for getch() func BITMAP* buffer; BITMAP* talk_screen; BITMAP* talk_screen_temp; bool exit_chat = false; char* nickname; char message[256]; //Message array char ch = 0; //Single char for reading int index = 0; //index to message array bool sts = false; //Something to send variable //It tells program is there anything to send void put_string(char*, char*); ZCom_ConnID other_id; class Client : public ZCom_Control { virtual void ZCom_cbConnectResult( ZCom_ConnID _id, eZCom_ConnectResult _result, ZCom_BitStream &_reply ) { other_id = _id; //Storing id of other computer } void ZCom_cbConnectionClosed( ZCom_ConnID _id, eZCom_CloseReason _reason, ZCom_BitStream &_reasondata ) { put_string("Connection to server closed.", ""); } // data was received void ZCom_cbDataReceived(ZCom_ConnID _id, ZCom_BitStream &_data) { put_string(_data.getString(), _data.getString()); } bool ZCom_cbConnectionRequest( ZCom_ConnID _id, ZCom_BitStream &_request, ZCom_BitStream &_reply ){return false;} void ZCom_cbConnectionSpawned( ZCom_ConnID _id ) {} bool ZCom_cbZoidRequest( ZCom_ConnID _id, zU8 _requested_level, ZCom_BitStream &_reason ) {return false;} void ZCom_cbZoidResult( ZCom_ConnID _id, eZCom_ZoidResult _result, zU8 _new_level, ZCom_BitStream &_reason ) {} void ZCom_cbNodeRequest_Dynamic( ZCom_ConnID _id, ZCom_ClassID _requested_class, ZCom_BitStream *_announcedata, eZCom_NodeRole _role, ZCom_NodeID _net_id ) {} void ZCom_cbNodeRequest_Tag( ZCom_ConnID _id, ZCom_ClassID _requested_class, ZCom_BitStream *_announcedata, eZCom_NodeRole _role, zU32 _tag ) {} bool ZCom_cbDiscoverRequest( const ZCom_Address &_addr, ZCom_BitStream &_request, ZCom_BitStream &_reply ) {return false;} void ZCom_cbDiscovered( const ZCom_Address & _addr, ZCom_BitStream &_reply ) {} }; ZoidCom* zcom = NULL; Client* client = NULL; void put_string(char* msg, char* nick) { static int y_pos = 30; //Position where our message textprintf_ex(talk_screen, font, 1, y_pos, makecol(255,255,255), -1, "%s> %s", nick,msg); y_pos+=15; //Scroling if(y_pos>330) { blit(talk_screen, talk_screen_temp, 0, 0, 0, 0, talk_screen_temp->w, talk_screen_temp->h); clear_to_color(talk_screen, makecol(128, 128, 128)); blit(talk_screen_temp, talk_screen, 0, 105, 0, 0, talk_screen_temp->w, talk_screen_temp->h); y_pos-=105; } } void close_button_handler(void) { exit_chat = true; } void start() { allegro_init(); //Allegro needed function install_keyboard(); //Instaling keyboard //////////////// GRAPHICS INIT ///////////////////////////////// set_color_depth(16); if(set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0) <= -1) { set_color_depth(15); if(set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0) <= -1) { allegro_message("Error initializating graphics", NULL); exit(1); } } //////////////// WINDOW PROCEDURES //////////////////////////// // Window title, write everything you want here set_window_title("Chatic v0.01 CLIENT"); // callback function for this litte [X] button in top right of // your window, we will write it soon, if you dont want it // just comment this line set_close_button_callback(close_button_handler); //For working in background, very important. //You will get strange results if you dont put this line set_display_switch_mode(SWITCH_BACKGROUND); //For double buffering buffer = create_bitmap(SCREEN_W,SCREEN_H); //Our chat will be composited with two windows: //talk_screen where messages are being displayed, //and write_screen where you type your message. //write_screen isnt really exist, we will write //directly on buffer // (-81) is size of talk screen and also size of write_screen talk_screen = create_bitmap(SCREEN_W, SCREEN_H-81); //temporary bitmap, we will need it to make text move //smothly talk_screen_temp = create_bitmap(SCREEN_W, SCREEN_H-81); //clearing bitmaps clear_to_color(buffer, makecol(0, 0, 0)); clear_to_color(talk_screen, makecol(128, 128, 128)); clear_to_color(talk_screen_temp, makecol(128, 128, 128)); //Configuration //I've maked simple config file to read your nickname //and other options, if you don't want to use it, comment //this but rememer to declare char* nickname = "nickname"; push_config_state(); set_config_file("config.ini"); nickname = ustrdup(get_config_string("user", "name", "noname")); pop_config_state(); //Messages on start textprintf_ex(talk_screen, font, 1, 1, makecol(255,255,255), -1, "Chatic version 0.01 CLIENT started..."); textprintf_ex(talk_screen, font, 1, 15, makecol(255,255,255), -1, "All ok..."); zcom = new ZoidCom("netlog.txt"); //creating new object //netlog.txt is a file //where zoidcom will save his log if (!zcom || !zcom->Init()) exit(255); //if initialization fails -> quit //Important thing, timeout, after this time (in miliseconds), //if the other machine isn't respondig we break connection //and func ZCom_cbConnectionClosed() is executed. zcom->setConnectionTimeout(2000); //Our client object based on class we defined eariler client = new Client(); client->ZCom_setDebugName("Chatic Client"); client->ZCom_initSockets(true, 0, 0); //Let computer decide put_string("Connecting...", ""); //Inform user that chat is //connecting //Addres variable ZCom_Address server_addr; //Setting addres, you can put there your IP:Port if you want server_addr.setAddress( eZCom_AddressUDP, 0, "localhost:10000"); //Try to connect client->ZCom_Connect(server_addr, NULL); } void DrawAll() { //Lines for divide talk_screen from write_screen line(buffer, 0, SCREEN_H-79, SCREEN_W, SCREEN_H-79, makecol(192,192,192)); line(buffer, 0, SCREEN_H-80, SCREEN_W, SCREEN_H-80, makecol(255,255,255)); line(buffer, 0, SCREEN_H-81, SCREEN_W, SCREEN_H-81, makecol(192,192,192)); //Your nickname should be always drawed to write_screen //I will explain why, later textprintf_ex(buffer, font, 1, SCREEN_H-76, makecol(255,255,255), -1, "%s>", nickname); //Drawing talk_screen to buffer and buffer to screen blit(talk_screen, buffer, 0, 0, 0, 0, talk_screen->w, talk_screen->h); blit(buffer, screen, 0, 0, 0, 0, SCREEN_W, SCREEN_H); } void Process() { if(sts) { ZCom_BitStream *reply = new ZCom_BitStream(); //create stream reply->addString(nickname); //add your nick to stream reply->addString(message); //add your message to stream client->ZCom_sendData(other_id, reply); //send message to id //stored on start sts = false; //there is nothing more to send for(int u = 0; u < 256; u++) message[u] = 0; //clear message array } client->ZCom_processInput(); //zoidcom func processing all input client->ZCom_processOutput();//zoidcom func processing all output zcom->Sleep(1); //give rest of time to cpu } void GetInput() { if(key[KEY_ESC]) exit_chat = true; if(key[KEY_ENTER] || key[KEY_ENTER_PAD]) { put_string(message, nickname); //Drawing our message index = 0; //clearing index do{}while(key[KEY_ENTER] || key[KEY_ENTER_PAD]); //pausing clear_keybuf(); //clearing keyboard queue clear_to_color(buffer, makecol(0, 0, 0)); //clearing buffer sts = true; //telling our networking //engine (which doesn't exist //for now) that there is //something to send } if(key[KEY_BACKSPACE] && index > 0){ message[--index] = 0; do{}while(key[KEY_BACKSPACE]); clear_to_color(buffer, makecol(0, 0, 0)); textprintf_ex(buffer, font, text_length(font, nickname)+15 , SCREEN_H-76, makecol(255,255,255), makecol(0,0,0), "%s", message); clear_keybuf(); } if(keypressed()) { ch = readkey(); message[index++] = ch; textprintf_ex(buffer, font, text_length(font, nickname)+15, SCREEN_H-76, makecol(255,255,255), makecol(0,0,0), "%s", message); if(index>255) index = 255; //Brutal forcing index not to //writing over the array } } void shutdown() { destroy_bitmap(buffer); destroy_bitmap(talk_screen); destroy_bitmap(talk_screen_temp); delete client; delete zcom; allegro_exit(); } int main() { start(); do { DrawAll(); GetInput(); Process(); } while(!exit_chat); shutdown(); return 0; } END_OF_MAIN();
Now you have two application which can communicate. Just enter your ip address in correct place in client program and you can send this emergency chat client to every person you know. It will be usefull when icq fails, or your mailbox just blew up!:P
I must admit that this program don’t use even 10% possibilities of zoidcom library. This tutorial is only for simple start. It’s really great and easy library and I can’t wait to write some game in it. And I encourage all of you to do that!
Regards Matic