00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #ifdef HAVE_CONFIG_H
00026 # include <config.h>
00027 #endif
00028
00029
00030 #ifdef USE_EXULTSTUDIO
00031
00032 #include <unistd.h>
00033 #include <fcntl.h>
00034
00035 #if HAVE_SYS_TYPES_H
00036 #include <sys/types.h>
00037 #endif
00038
00039 #if HAVE_SYS_TIME_H
00040 #include <sys/time.h>
00041 #endif
00042
00043 #if HAVE_SYS_SOCKET_H
00044 #include <sys/socket.h>
00045 #endif
00046
00047 #include <cstdio>
00048
00049 #ifdef _AIX
00050 #include <strings.h>
00051 #endif
00052
00053 #if HAVE_NETDB_H
00054 #include <netdb.h>
00055 #endif
00056
00057 #ifndef WIN32
00058 #include <sys/un.h>
00059 #endif
00060
00061 #include "server.h"
00062 #include "servemsg.h"
00063 #include "utils.h"
00064 #include "egg.h"
00065 #include "actors.h"
00066 #include "gamewin.h"
00067 #include "gamemap.h"
00068 #include "chunkter.h"
00069 #include "cheat.h"
00070 #include "objserial.h"
00071 #include "effects.h"
00072
00073 #ifdef USECODE_DEBUGGER
00074 #include "debugserver.h"
00075 #endif
00076
00077 #ifdef WIN32
00078 #include "servewin32.h"
00079 #include "cheat.h"
00080 #endif
00081
00082 using std::cout;
00083 using std::cerr;
00084 using std::endl;
00085
00086
00087
00088 extern int xfd;
00089 int listen_socket = -1;
00090 int client_socket = -1;
00091 int highest_fd = -1;
00092
00093 #ifdef __sun__
00094
00095 #define PF_LOCAL PF_UNIX
00096 #endif
00097
00098
00099
00100
00101 inline void Set_highest_fd
00102 (
00103 )
00104 {
00105 highest_fd = xfd;
00106 if (listen_socket > highest_fd)
00107 highest_fd = listen_socket;
00108 if (client_socket > highest_fd)
00109 highest_fd = client_socket;
00110 highest_fd++;
00111 }
00112
00113
00114
00115
00116
00117 void Server_init
00118 (
00119 )
00120 {
00121 #ifndef WIN32
00122
00123 std::string servename("");
00124 char *home = getenv("HOME");
00125 if (home)
00126 {
00127 servename = home;
00128 servename += "/.exult";
00129 if (U7exists(servename.c_str()))
00130 servename += "/exultserver";
00131 else
00132 servename = "";
00133 }
00134 if (servename == "")
00135 servename = get_system_path("<GAMEDAT>/exultserver");
00136
00137 unlink(servename.c_str());
00138 #if HAVE_GETADDRINFOX
00139
00140 int r;
00141 struct addrinfo hints,*ai;
00142
00143 memset(&hints,0,sizeof(hints));
00144 hints.ai_flags=AI_PASSIVE;
00145 r=getaddrinfo( 0,
00146 servename.c_str(),
00147 &hints,
00148 &ai);
00149 if(r!=0)
00150 {
00151 cerr << "getaddrinfo(): "<<gai_strerror(r) << endl;
00152 return;
00153 }
00154
00155 listen_socket = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
00156 #else
00157
00158 listen_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
00159 #endif
00160 if (listen_socket < 0)
00161 perror("Failed to open map-editor socket");
00162 else
00163 {
00164 #if HAVE_GETADDRINFOX
00165 if(bind(listen_socket,ai->ai_addr,ai->ai_addrlen) == -1 ||
00166 listen(listen_socket,1) == -1)
00167 #else
00168 struct sockaddr_un addr;
00169 addr.sun_family = AF_UNIX;
00170 strcpy(addr.sun_path, servename.c_str());
00171 if (bind(listen_socket, (struct sockaddr *) &addr,
00172 sizeof(addr.sun_family) + strlen(addr.sun_path)) == -1 ||
00173 listen(listen_socket, 1) == -1)
00174 #endif
00175 {
00176 perror("Bind or listen on socket failed");
00177 close(listen_socket);
00178 listen_socket = -1;
00179 }
00180 else
00181 {
00182 cout << "Listening on socket " << listen_socket
00183 << endl;
00184 fcntl(listen_socket, F_SETFL,
00185 fcntl(listen_socket, F_GETFL) | O_NONBLOCK);
00186 }
00187 #if HAVE_GETADDRINFOX
00188 freeaddrinfo(ai);
00189 #endif
00190 }
00191 Set_highest_fd();
00192 #else
00193
00194 listen_socket = client_socket = -1;
00195
00196 std::string servename = get_system_path("<STATIC>");
00197
00198 if (Exult_server::create_pipe(servename.c_str())) listen_socket = 1;
00199
00200 #endif
00201 }
00202
00203
00204
00205
00206
00207 void Server_close
00208 (
00209 )
00210 {
00211 #ifdef WIN32
00212 Exult_server::close_pipe();
00213 listen_socket = client_socket = -1;
00214 #else
00215
00216 #endif
00217 }
00218
00219
00220
00221
00222
00223
00224 static void Handle_client_message
00225 (
00226 int& fd
00227 )
00228 {
00229 unsigned char data[Exult_server::maxlength];
00230 Exult_server::Msg_type id;
00231 int datalen = Exult_server::Receive_data(fd, id, data, sizeof(data));
00232 if (datalen < 0)
00233 return;
00234 unsigned char *ptr = &data[0];
00235 Game_window *gwin = Game_window::get_instance();
00236 switch (id)
00237 {
00238 case Exult_server::obj:
00239 Game_object::update_from_studio(&data[0], datalen);
00240 break;
00241 case Exult_server::egg:
00242 Egg_object::update_from_studio(&data[0], datalen);
00243 break;
00244 case Exult_server::npc:
00245 Actor::update_from_studio(&data[0], datalen);
00246 break;
00247 case Exult_server::info:
00248 {
00249 unsigned char data[Exult_server::maxlength];
00250 unsigned char *ptr = &data[0];
00251 Game_info_out(client_socket, Exult_server::version,
00252 cheat.get_edit_lift(),
00253 gwin->skip_lift,
00254 cheat.in_map_editor(),
00255 cheat.show_tile_grid(),
00256 gwin->get_map()->was_map_modified(),
00257 (int) cheat.get_edit_mode());
00258 break;
00259 }
00260 case Exult_server::write_map:
00261 gwin->write_map();
00262 break;
00263 case Exult_server::read_map:
00264 gwin->read_map();
00265 break;
00266 case Exult_server::map_editing_mode:
00267 {
00268 int onoff = Read2(ptr);
00269 if ((onoff != 0) != cheat.in_map_editor())
00270 cheat.toggle_map_editor();
00271 break;
00272 }
00273 case Exult_server::tile_grid:
00274 {
00275 int onoff = Read2(ptr);
00276 if ((onoff != 0) != cheat.show_tile_grid())
00277 cheat.toggle_tile_grid();
00278 break;
00279 }
00280 case Exult_server::edit_lift:
00281 {
00282 int lift = Read2(ptr);
00283 cheat.set_edit_lift(lift);
00284 break;
00285 }
00286 case Exult_server::reload_usecode:
00287 gwin->reload_usecode();
00288 break;
00289 case Exult_server::locate_terrain:
00290 {
00291 int tnum = Read2(ptr);
00292 int cx = (short) Read2(ptr);
00293 int cy = (short) Read2(ptr);
00294 bool up = *ptr++ ? true : false;
00295 bool okay = gwin->get_map()->locate_terrain(tnum, cx, cy, up);
00296 ptr = &data[2];
00297 Write2(ptr, cx);
00298 Write2(ptr, cy);
00299 ptr++;
00300 *ptr++ = okay ? 1 : 0;
00301 Exult_server::Send_data(client_socket,
00302 Exult_server::locate_terrain, data, ptr - data);
00303 break;
00304 }
00305 case Exult_server::swap_terrain:
00306 {
00307 int tnum = Read2(ptr);
00308 bool okay = gwin->get_map()->swap_terrains(tnum);
00309 *ptr++ = okay ? 1 : 0;
00310 Exult_server::Send_data(client_socket,
00311 Exult_server::swap_terrain, data, ptr - data);
00312 break;
00313 }
00314 case Exult_server::insert_terrain:
00315 {
00316 int tnum = (short) Read2(ptr);
00317 bool dup = *ptr++ ? true : false;
00318 bool okay = gwin->get_map()->insert_terrain(tnum, dup);
00319 *ptr++ = okay ? 1 : 0;
00320 Exult_server::Send_data(client_socket,
00321 Exult_server::insert_terrain, data, ptr - data);
00322 break;
00323 }
00324 case Exult_server::delete_terrain:
00325 {
00326 int tnum = (short) Read2(ptr);
00327 bool okay = gwin->get_map()->delete_terrain(tnum);
00328 *ptr++ = okay ? 1 : 0;
00329 Exult_server::Send_data(client_socket,
00330 Exult_server::delete_terrain, data, ptr - data);
00331 break;
00332 }
00333 case Exult_server::send_terrain:
00334 {
00335 int tnum = (short) Read2(ptr);
00336 Write2(ptr, gwin->get_map()->get_num_chunk_terrains());
00337 Chunk_terrain *ter = gwin->get_map()->get_terrain(tnum);
00338 ter->write_flats(ptr);
00339 ptr += 512;
00340 Exult_server::Send_data(client_socket,
00341 Exult_server::send_terrain, data, ptr - data);
00342 break;
00343 }
00344 case Exult_server::terrain_editing_mode:
00345 {
00346 int onoff = (short) Read2(ptr);
00347
00348 gwin->skip_lift = onoff == 1 ? 0 : 16;
00349 static char *msgs[3] = {"Terrain-Editing Aborted",
00350 "Terrain-Editing Done",
00351 "Terrain-Editing Enabled"};
00352 if (onoff == 0)
00353 gwin->get_map()->commit_terrain_edits();
00354 else if (onoff == -1)
00355 gwin->get_map()->abort_terrain_edits();
00356 if (onoff >= -1 && onoff <= 1)
00357 gwin->get_effects()->center_text(msgs[onoff + 1]);
00358 gwin->set_all_dirty();
00359 break;
00360 }
00361 case Exult_server::set_edit_shape:
00362 {
00363 int shnum = (short) Read2(ptr);
00364 int frnum = (short) Read2(ptr);
00365 cheat.set_edit_shape(shnum, frnum);
00366 break;
00367 }
00368 case Exult_server::view_pos:
00369 {
00370 int tx = Read4(ptr);
00371 if (tx == -1)
00372 {
00373 gwin->send_location();
00374 break;
00375 }
00376 int ty = Read4(ptr);
00377
00378
00379
00380
00381 if (tx/c_tiles_per_chunk !=
00382 gwin->get_scrolltx()/c_tiles_per_chunk ||
00383 ty/c_tiles_per_chunk !=
00384 gwin->get_scrollty()/c_tiles_per_chunk)
00385 {
00386 gwin->set_scrolls(tx, ty);
00387 gwin->set_all_dirty();
00388 }
00389 break;
00390 }
00391 case Exult_server::set_edit_mode:
00392 {
00393 int md = Read2(ptr);
00394 if (md >= 0 && md <= 3)
00395 cheat.set_edit_mode((Cheat::Map_editor_mode) md);
00396 break;
00397 }
00398 case Exult_server::hide_lift:
00399 {
00400 int lift = Read2(ptr);
00401 gwin->skip_lift = lift;
00402 gwin->set_all_dirty();
00403 break;
00404 }
00405 case Exult_server::reload_shapes:
00406 Shape_manager::get_instance()->reload_shapes(Read2(ptr));
00407 break;
00408 case Exult_server::unused_shapes:
00409 {
00410 unsigned char data[Exult_server::maxlength];
00411 int sz = 1024/8;
00412 sz = sz > sizeof(data) ? sizeof(data) : sz;
00413 gwin->get_map()->find_unused_shapes(data, sz);
00414 Exult_server::Send_data(client_socket,
00415 Exult_server::unused_shapes, data, sz);
00416 break;
00417 }
00418 case Exult_server::locate_shape:
00419 {
00420 int shnum = Read2(ptr);
00421 bool up = *ptr++ ? true : false;
00422 bool okay = gwin->locate_shape(shnum, up);
00423 ptr = &data[2];
00424 ptr++;
00425 *ptr++ = okay ? 1 : 0;
00426 Exult_server::Send_data(client_socket,
00427 Exult_server::locate_shape, data, ptr - data);
00428 break;
00429 }
00430 case Exult_server::cut:
00431 cheat.cut(*ptr != 0);
00432 break;
00433 case Exult_server::paste:
00434 cheat.paste();
00435 break;
00436 case Exult_server::npc_info:
00437 Write2(ptr, gwin->get_num_npcs());
00438 Write2(ptr, gwin->get_unused_npc());
00439 Exult_server::Send_data(client_socket, Exult_server::npc_info,
00440 data, ptr - data);
00441 break;
00442 case Exult_server::edit_selected:
00443 {
00444 unsigned char basic = *ptr;
00445 const Game_object_vector& sel = cheat.get_selected();
00446 if (!sel.empty())
00447 if (basic)
00448 sel.back()->Game_object::edit();
00449 else
00450 sel.back()->edit();
00451 break;
00452 }
00453 case Exult_server::set_edit_chunknum:
00454 cheat.set_edit_chunknum((short) Read2(ptr));
00455 break;
00456
00457 case Exult_server::game_pos:
00458 {
00459 Tile_coord pos = gwin->get_main_actor()->get_tile();
00460 Write2(ptr, pos.tx);
00461 Write2(ptr, pos.ty);
00462 Write2(ptr, pos.tz);
00463 Exult_server::Send_data(client_socket,
00464 Exult_server::game_pos, data, ptr - data);
00465 break;
00466 }
00467
00468 #ifdef USECODE_DEBUGGER
00469 case Exult_server::usecode_debugging:
00470 Handle_debug_message(&data[0], datalen);
00471 break;
00472 #endif
00473 }
00474 }
00475
00476
00477
00478
00479
00480
00481 void Server_delay
00482 (
00483 Message_handler handle_message
00484 )
00485 {
00486 #ifndef WIN32
00487 extern int xfd;
00488 fd_set rfds;
00489 struct timeval timer;
00490 timer.tv_sec = 0;
00491 timer.tv_usec = 50000;
00492 FD_ZERO(&rfds);
00493 FD_SET(xfd, &rfds);
00494 if (listen_socket >= 0)
00495 FD_SET(listen_socket, &rfds);
00496 if (client_socket >= 0)
00497 FD_SET(client_socket, &rfds);
00498
00499 if (select(highest_fd, &rfds, 0, 0, &timer) > 0)
00500 {
00501 if (listen_socket >= 0 && FD_ISSET(listen_socket, &rfds))
00502 {
00503
00504 if (client_socket >= 0)
00505 close(client_socket);
00506 client_socket = accept(listen_socket, 0, 0);
00507 cout << "Accept returned client_socket = " <<
00508 client_socket << endl;
00509
00510 fcntl(client_socket, F_SETFL,
00511 fcntl(client_socket, F_GETFL) | O_NONBLOCK);
00512 Set_highest_fd();
00513 }
00514 if (client_socket >= 0 && FD_ISSET(client_socket, &rfds))
00515 {
00516 handle_message(client_socket);
00517
00518 if (client_socket == -1)
00519 Set_highest_fd();
00520 }
00521 }
00522 #else
00523 if (listen_socket == -1) return;
00524
00525 if (Exult_server::is_broken()) {
00526 std::cout << "Client disconnected." << endl;
00527 Exult_server::disconnect_from_client();
00528 Exult_server::setup_connect();
00529 client_socket = -1;
00530 }
00531
00532 SleepEx(20, TRUE);
00533
00534 if (client_socket == -1) {
00535
00536 if (!cheat.in_map_editor()) return;
00537
00538 std::string servename = get_system_path("<STATIC>");
00539 if (!Exult_server::try_connect_to_client(servename.c_str())) return;
00540 else client_socket = 1;
00541 std::cout << "Connected to client" << endl;
00542 }
00543
00544 if (Exult_server::peek_pipe() > 0)
00545 handle_message(client_socket);
00546
00547 if (Exult_server::is_broken()) {
00548 if (Exult_server::notify_connection_lost()) std::cout << "Client disconnected." << endl;
00549 Exult_server::disconnect_from_client();
00550 Exult_server::setup_connect();
00551 client_socket = -1;
00552 }
00553 #endif
00554
00555 }
00556
00557 void Server_delay()
00558 {
00559 Server_delay(Handle_client_message);
00560 }
00561
00562 #endif