PART III

Yea, thats the place when we can have some problems. But don’t worry, you can handle everything what you touch :p

At start, we have to declare our zoidcom classes. Because this is server application we start with the Server class.

Before that, we must add some declarations:

void put_string(char*, char*); //because we use it in Server class
ZCom_ConnID other_id           //variable to store id of computer
                               //which connects to ours.

Then, let’s go with class Server. First function we would like to add is connection request

class Server : public ZCom_Control 
{
  // someone tries to connect
  bool ZCom_cbConnectionRequest(ZCom_ConnID  _id, ZCom_BitStream &_request, ZCom_BitStream &_reply ) 
  {
    put_string("Requested connection...", "");
    return true; //Always returnig true will allow all users to connect
  }
};

Next, we should add a function which informs us about connection spawn and invite the other person to chat with us.

  // someone has connected
  void ZCom_cbConnectionSpawned( ZCom_ConnID _id ) 
  {
    put_string("Connection made...you can now write", "");
    
    other_id = _id; //Storing the id of other computer to later use
    ZCom_BitStream *welcome = new ZCom_BitStream();   
    welcome->addString(""); //There should be nick but we can 
                            //treat this as system message
                            //so i left it blank                                          
    welcome->addString("Connection made, you can now write");
    ZCom_sendData(other_id, welcome); //Sending message
    
 
  }

Now, we will add function which inform us about closing connection. Simple...

  void ZCom_cbConnectionClosed( ZCom_ConnID _id, eZCom_CloseReason _reason, ZCom_BitStream &_reasondata ) 
  {
    put_string("Connection closed.", "");
  }

Most important thing is to read data send to us. It is handled by other function

  // someone has sent data
  void ZCom_cbDataReceived(ZCom_ConnID  _id, ZCom_BitStream &_data) 
  {
      put_string(_data.getString(), _data.getString());     
  }

We must also write all unused functions to make zoidcom work. (just copy paste it)

  void ZCom_cbConnectResult( ZCom_ConnID _id, eZCom_ConnectResult _result, ZCom_BitStream &_reply ) {}
  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 )  {}

And this is enough for Server class, now needed declarations (after class description):

ZoidCom* zcom = NULL;
Server* server = NULL;

By the way you can add two lines to shutdown() function:

    delete server;
    delete zcom;

Now, we have to get back to start() function and on bottom of it add some stuff:

  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.
  // 10 seconds
  zcom->setConnectionTimeout(10000); 
 
  //Our server object based on class we defined eariler
  server = new Server();
  server->ZCom_setDebugName("Chatic Server");
  // port 10000
  server->ZCom_initSockets(true, 10000, 0);

Yeah, now we are almost done. Last thing is to use sts variable, remember it? Great, look at Process() func:

void Process()
{
      if(sts) 
      {
        sts = false;      
        for(int u = 0; u < 256; u++)
        message[u] = 0; 
      }
}

And make it look like this

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
      server->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
    }    
    server->ZCom_processInput(); //zoidcom func processing all input
    server->ZCom_processOutput();//zoidcom func processing all output    
    zcom->Sleep(1);  //give rest of time to cpu
}

Now, we have complete server application. All we have to do, is to save it somewhere, copy somewhere and make client application from the copy.

Complete source code for server app:

#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 Server : public ZCom_Control 
{
  bool ZCom_cbConnectionRequest(ZCom_ConnID  _id, ZCom_BitStream &_request, ZCom_BitStream &_reply ) 
  {
    put_string("Requested connection...", "");
    return true;
  }
 
  void ZCom_cbConnectionSpawned( ZCom_ConnID _id ) 
  {
    put_string("Connection made...you can now write", "");
    other_id = _id;
    ZCom_BitStream *welcome = new ZCom_BitStream();   
    welcome->addString("");                                          
    welcome->addString("Connection made, you can now write");
    ZCom_sendData(other_id, welcome);
  }
 
  void ZCom_cbConnectionClosed( ZCom_ConnID _id, eZCom_CloseReason _reason, ZCom_BitStream &_reasondata ) 
  {
    put_string("Connection closed.", "");
  }
 
  void ZCom_cbDataReceived(ZCom_ConnID  _id, ZCom_BitStream &_data) 
  {
      put_string(_data.getString(), _data.getString());     
  }
  
  void ZCom_cbConnectResult( ZCom_ConnID _id, eZCom_ConnectResult _result, ZCom_BitStream &_reply ) {}
  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;
Server* server = 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 SERWER");
 
   // 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 SERVER 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.
  //10 seconds timeout
  zcom->setConnectionTimeout(10000); 
 
  //Our server object based on class we defined eariler
  server = new Server();
  server->ZCom_setDebugName("Chatic Server");
  // port 10000
  server->ZCom_initSockets(true, 10000, 0);
   
}
 
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
      server->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
    }    
    server->ZCom_processInput(); //zoidcom func processing all input
    server->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 server;
    delete zcom;
    allegro_exit();
}
 
int main() 
{
    start();
    do {
        DrawAll();
        GetInput();
        Process();
 
        
    } while(!exit_chat);     
    shutdown();
 
    
  return 0;   
}
END_OF_MAIN();
 
allegrozoidcomchat3.txt · Last modified: 2006/10/25 20:16 by sharkyx
 
Recent changes RSS feed Creative Commons License Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki