PART IV

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

 
allegrozoidcomchat4.txt · Last modified: 2006/10/25 20:16 by matic
 
Recent changes RSS feed Creative Commons License Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki