Atrinik Client 2.5
client/client.c
Go to the documentation of this file.
00001 /************************************************************************
00002 *            Atrinik, a Multiplayer Online Role Playing Game            *
00003 *                                                                       *
00004 *    Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team    *
00005 *                                                                       *
00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game)     *
00007 * and Crossfire (Multiplayer game for X-windows).                       *
00008 *                                                                       *
00009 * This program is free software; you can redistribute it and/or modify  *
00010 * it under the terms of the GNU General Public License as published by  *
00011 * the Free Software Foundation; either version 2 of the License, or     *
00012 * (at your option) any later version.                                   *
00013 *                                                                       *
00014 * This program is distributed in the hope that it will be useful,       *
00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00017 * GNU General Public License for more details.                          *
00018 *                                                                       *
00019 * You should have received a copy of the GNU General Public License     *
00020 * along with this program; if not, write to the Free Software           *
00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.             *
00022 *                                                                       *
00023 * The author can be reached at admin@atrinik.org                        *
00024 ************************************************************************/
00025 
00044 #include <global.h>
00045 
00047 Client_Player cpl;
00048 
00050 ClientSocket csocket;
00051 
00053 typedef void (*CmdProc)(unsigned char *, int len);
00054 
00055 struct CmdMapping
00056 {
00057     const char *cmdname;
00058     void (*cmdproc)(unsigned char *, int);
00059     enum CmdFormat cmdformat;
00060 };
00061 
00062 enum
00063 {
00064     BINARY_CMD_COMC = 1,
00065     BINARY_CMD_MAP2,
00066     BINARY_CMD_DRAWINFO,
00067     BINARY_CMD_DRAWINFO2,
00068     BINARY_CMD_FILE_UPD,
00069     BINARY_CMD_ITEMX,
00070     BINARY_CMD_SOUND,
00071     BINARY_CMD_TARGET,
00072     BINARY_CMD_UPITEM,
00073     BINARY_CMD_DELITEM,
00074     BINARY_CMD_STATS,
00075     BINARY_CMD_IMAGE,
00076     BINARY_CMD_FACE1,
00077     BINARY_CMD_ANIM,
00078     BINARY_CMD_SKILLRDY,
00079     BINARY_CMD_PLAYER,
00080     BINARY_CMD_MAPSTATS,
00081     BINARY_CMD_SPELL_LIST,
00082     BINARY_CMD_SKILL_LIST,
00083     BINARY_CMD_CLEAR,
00084     BINARY_CMD_ADDME_SUC,
00085     BINARY_CMD_ADDME_FAIL,
00086     BINARY_CMD_VERSION,
00087     BINARY_CMD_BYE,
00088     BINARY_CMD_SETUP,
00089     BINARY_CMD_QUERY,
00090     BINARY_CMD_DATA,
00091     BINARY_CMD_NEW_CHAR,
00092     BINARY_CMD_ITEMY,
00093     BINARY_CMD_BOOK,
00094     BINARY_CMD_PARTY,
00095     BINARY_CMD_QUICKSLOT,
00096     BINARY_CMD_SHOP,
00097     BINARY_CMD_QLIST,
00098     BINARY_CMD_REGION_MAP,
00099     BINARY_CMD_READY,
00100     BINARY_CMD_KEEPALIVE,
00101     /* last entry */
00102     BINAR_CMD
00103 };
00104 
00106 struct CmdMapping commands[] =
00107 {
00108     /* Order of this table doesn't make a difference.  I tried to sort
00109      * of cluster the related stuff together. */
00110     {"comc", CompleteCmd, SHORT_INT},
00111     {"map2", Map2Cmd, MIXED},
00112     {"drawinfo", (CmdProc) DrawInfoCmd, ASCII},
00113     {"drawinfo2", (CmdProc) DrawInfoCmd2, ASCII},
00114     {"request_upd", cmd_request_update, ASCII},
00115     {"itemx", ItemXCmd, MIXED},
00116     {"sound", SoundCmd, ASCII},
00117     {"to", TargetObject, ASCII},
00118     {"upditem", UpdateItemCmd, MIXED},
00119     {"delitem", DeleteItem, INT_ARRAY},
00120     {"stats", StatsCmd, STATS},
00121     {"image", ImageCmd, ASCII},
00122     {"face1", NULL, SHORT_ARRAY},
00123     {"anim", AnimCmd, SHORT_ARRAY},
00124     {"skill_rdy", (CmdProc) SkillRdyCmd, ASCII},
00125     {"player", PlayerCmd, MIXED},
00126     {"mapstats", MapStatsCmd, ASCII},
00127     {"splist", (CmdProc) SpelllistCmd, ASCII},
00128     {"sklist", (CmdProc) SkilllistCmd, ASCII},
00129     {"clr", NULL, ASCII},
00130     {"addme_success", AddMeSuccess, NODATA},
00131     {"addme_failed", AddMeFail, NODATA},
00132     {"version", (CmdProc) VersionCmd, NODATA},
00133     {"goodbye", NULL, NODATA},
00134     {"setup", (CmdProc) SetupCmd, ASCII},
00135     {"query", (CmdProc) handle_query, ASCII},
00136     {"data", (CmdProc) DataCmd, MIXED},
00137     {"new_char", (CmdProc) NewCharCmd, NODATA},
00138     {"itemy", ItemYCmd, MIXED},
00139     {"book", BookCmd, ASCII},
00140     {"pt", PartyCmd, ASCII},
00141     {"qs", QuickSlotCmd, ASCII},
00142     {"shop", ShopCmd, ASCII},
00143     {"qlist", QuestListCmd, ASCII},
00144     {"region_map", RegionMapCmd, ASCII},
00145     {"rd", ReadyCmd, INT_ARRAY},
00146     {"ka", NULL, NODATA},
00147 
00148     /* Unused! */
00149     {"magicmap", MagicMapCmd, NODATA},
00150     {"delinv", (CmdProc) DeleteInventory, NODATA},
00151 };
00152 
00156 void DoClient()
00157 {
00158     command_buffer *cmd;
00159 
00160     /* Handle all enqueued commands */
00161     while ((cmd = get_next_input_command()))
00162     {
00163         uint8 *data = cmd->data, *dest = NULL;
00164         size_t len = cmd->len;
00165 
00166         /* Binary command #0 is reserved for compressed data packets, so
00167          * attempt to uncompress it. */
00168         if (data[0] == 0)
00169         {
00170             unsigned long ucomp_len;
00171 
00172             /* Get original length so we can allocate a large enough
00173              * buffer. */
00174             ucomp_len = GetInt_String(data + 1) + 1;
00175             /* Allocate the buffer. */
00176             dest = malloc(ucomp_len);
00177 
00178             if (!dest)
00179             {
00180                 LOG(llevError, "DoClient(): Out of memory.\n");
00181             }
00182 
00183             uncompress((Bytef *) dest, (uLongf *) &ucomp_len, (const Bytef *) data + 5, (uLong) len - 5);
00184             data = dest;
00185             len = ucomp_len;
00186             data[len] = '\0';
00187         }
00188 
00189         if (!data[0] || data[0] > BINAR_CMD)
00190         {
00191             LOG(llevBug, "Bad command from server (%d)\n", data[0]);
00192         }
00193         else
00194         {
00195             script_trigger_event(commands[data[0] - 1].cmdname, data + 1, len - 1, commands[data[0] - 1].cmdformat);
00196             commands[data[0] - 1].cmdproc(data + 1, len - 1);
00197         }
00198 
00199         /* Should we free the data because it was allocated by previous
00200          * uncompression? */
00201         if (dest)
00202         {
00203             free(dest);
00204         }
00205 
00206         command_buffer_free(cmd);
00207     }
00208 }
00209 
00213 void SockList_Init(SockList *sl)
00214 {
00215     sl->len = 0;
00216     sl->buf = NULL;
00217 }
00218 
00223 void SockList_AddChar(SockList *sl, char c)
00224 {
00225     sl->buf[sl->len] = c;
00226     sl->len++;
00227 }
00228 
00233 void SockList_AddShort(SockList *sl, uint16 data)
00234 {
00235     sl->buf[sl->len++] = (data >> 8) & 0xff;
00236     sl->buf[sl->len++] = data & 0xff;
00237 }
00238 
00243 void SockList_AddInt(SockList *sl, uint32 data)
00244 {
00245     sl->buf[sl->len++] = (data >> 24) & 0xff;
00246     sl->buf[sl->len++] = (data >> 16) & 0xff;
00247     sl->buf[sl->len++] = (data >> 8) & 0xff;
00248     sl->buf[sl->len++] = data & 0xff;
00249 }
00250 
00255 void SockList_AddString(SockList *sl, char *data)
00256 {
00257     char c;
00258 
00259     while ((c = *data++))
00260     {
00261         sl->buf[sl->len] = c;
00262         sl->len++;
00263     }
00264 }
00265 
00270 void SockList_AddStringTerminated(SockList *sl, char *data)
00271 {
00272     char c;
00273 
00274     while ((c = *data++))
00275     {
00276         sl->buf[sl->len] = c;
00277         sl->len++;
00278     }
00279 
00280     sl->buf[sl->len] = c;
00281     sl->len++;
00282 }
00283 
00288 int GetInt_String(const unsigned char *data)
00289 {
00290     return ((data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3]);
00291 }
00292 
00297 sint64 GetInt64_String(const unsigned char *data)
00298 {
00299 #ifdef WIN32
00300     return (((sint64) data[0] << 56) + ((sint64) data[1] << 48) + ((sint64) data[2] << 40) + ((sint64) data[3] << 32) + ((sint64) data[4] << 24) + ((sint64) data[5] << 16) + ((sint64) data[6] << 8) + (sint64) data[7]);
00301 #else
00302     return (((uint64) data[0] << 56) + ((uint64) data[1] << 48) + ((uint64) data[2] << 40) + ((uint64) data[3] << 32) + ((uint64) data[4] << 24) + (data[5] << 16) + (data[6] << 8) + data[7]);
00303 #endif
00304 }
00305 
00310 short GetShort_String(const unsigned char *data)
00311 {
00312     return ((data[0] << 8) + data[1]);
00313 }
00314 
00322 char *GetString_String(uint8 *data, int *pos, char *dest, size_t dest_size)
00323 {
00324     size_t i = 0;
00325     char c;
00326 
00327     while ((c = (char) (data[(*pos)++])))
00328     {
00329         if (i < dest_size - 1)
00330         {
00331             dest[i++] = c;
00332         }
00333     }
00334 
00335     dest[i] = '\0';
00336     return dest;
00337 }
00338 
00345 int cs_write_string(char *buf, size_t len)
00346 {
00347     SockList sl;
00348 
00349     sl.len = (int) len;
00350     sl.buf = (unsigned char *) buf;
00351 
00352     return send_socklist(sl);
00353 }
00354 
00358 void check_animation_status(int anum)
00359 {
00360     /* Check if it has been loaded. */
00361     if (animations[anum].loaded)
00362     {
00363         return;
00364     }
00365 
00366     /* Mark this animation as loaded. */
00367     animations[anum].loaded = 1;
00368     /* Same as server sends it */
00369     AnimCmd((unsigned char *) anim_table[anum].anim_cmd, anim_table[anum].len);
00370 }