static int ReadBytes(int offset, int n) { static WorstTime tm("LstnSrvrMsgs"); tm.Start(); #ifdef WIN32 int count = recv(sock_fd, (char *)&buff[offset], n, 0); #else int count = read(sock_fd, &buff[offset], n); #endif tm.Stop(); if (count == 0 || (count<0 && errno == EEXIST)) { // EEXIST can happen on windows if connection is broken gMode.Set(GameMode::ESC); count = 0; } if (count < 0) { if (errno != EAGAIN) { auto &ss = View::gErrorManager.GetStream(true, false); #ifdef WIN32 ss << "ListenForServerMessages1: Error " << errno << " length " << count; #else ss << "ListenForServerMessages1: Error " << errno << "(" << strerror(errno) << "), length" << count; #endif } count = 0; // This is not a fatal error, need to try again } return count; }
void SendMsg(unsigned char const *b, int n) { static WorstTime tm("SendMsg"); tm.Start(); #ifdef WIN32 int res = send(sock_fd, (char*)b, n, 0); #else int res = write(sock_fd, b, n); #endif tm.Stop(); if (res == -1) { perror("write socket"); } }
int main(int argc, char** argv) { if (!glfwInit()) { ErrorDialog("Failed to initialize GLFW\n"); exit(EXIT_FAILURE); } gCurrentFrameTime = 0.0; string optionsFilename = "ephenation.ini"; string dataDir; // The directory where the client can save data #ifdef unix const char *home = getenv("HOME"); // Save Linux Path dataDir = string(home) + "/.ephenation"; const char *ephenationPath = dataDir.c_str(); struct stat st; if (stat(ephenationPath,&st) != 0) { mkdir(ephenationPath, 0777); } if (home) optionsFilename = dataDir + "/" + optionsFilename; else optionsFilename = ".ephenation/ephenation.ini"; // Fallback #endif #ifdef WIN32 TCHAR home[MAX_PATH]; HRESULT res = SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, 0, 0, home); if (res == S_OK) { dataDir = string(home) + "\\ephenation"; const char *ephenationPath = dataDir.c_str(); struct _stat st; if (_stat(ephenationPath,&st) != 0) { res = _mkdir(ephenationPath); } optionsFilename = dataDir + "\\" + optionsFilename; // Fallback } #endif const char *host = "server1.ephenation.net"; int port = 57862; /* getopt_long stores the option index here. */ int option_index = 0; while(1) { int c = getopt_long (argc, argv, "", long_options, &option_index); /* Detect the end of the options. */ if (c == -1) break; } if (optind < argc) host = argv[optind]; #ifdef WIN32 if (!gDebugOpenGL && !gVerbose) FreeConsole(); const char *cacheName = "\\cache"; #else const char *cacheName = "/cache"; #endif char *cachePath = new char[strlen(dataDir.c_str()) + strlen(cacheName) + strlen(host) + 2]; strcpy(cachePath, dataDir.c_str()); #ifdef WIN32 strcat(cachePath, "\\cache"); strcat(cachePath, host); strcat(cachePath, "\\"); #else strcat(cachePath, "/cache"); strcat(cachePath, host); strcat(cachePath, "/"); #endif ChunkCache::fgChunkCache.SetCacheDir(cachePath); //printf("Game Path: %s\n", dataDir); gOptions.Init(optionsFilename); // This one should come early, as it is used to initalize things. // If there was a saved position, use it for imnitialization. if (gOptions.fPlayerX != 0 || gOptions.fPlayerY != 0 || gOptions.fPlayerZ != 0) Model::gPlayer.SetPosition(gOptions.fPlayerX, gOptions.fPlayerY, gOptions.fPlayerZ); unsigned maxThreads = gOptions.fNumThreads; if (sSingleThread) { maxThreads = 1; // Override this number std::cout << "Limit to minimum number of threads" << std::endl; } glswInit(); glswSetPath("shaders/", ".glsl"); ConnectToServer(host, port); gSoundControl.Init(); TSExec::gTSExec.Init(); // This must be called after initiating gSoundControl. if (gDebugOpenGL) printf("Number of threads: %d\n", maxThreads); int numChunkProc = maxThreads - 1; if (numChunkProc <= 0) numChunkProc = 1; gChunkProcess.Init(numChunkProc); //glfwOpenWindowHint(GLFW_OPENGL_VERSION_MAJOR, 3); //glfwOpenWindowHint(GLFW_OPENGL_VERSION_MINOR, 3); glfwOpenWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, gDebugOpenGL); // glfwOpenWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); //glfwOpenWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // Need to specify at least version 3.3 for this to work. if (!glfwOpenWindow(gOptions.fWindowWidth, gOptions.fWindowHeight, 0, 0, 0, 0, 16, 1, gOptions.fFullScreen ? GLFW_FULLSCREEN : GLFW_WINDOW)) { glfwTerminate(); ErrorDialog("Failed to open GLFW window"); } glfwSetWindowTitle("Ephenation"); checkError("glfwSetWindowTitle"); GLFWvidmode desktopMode; glfwGetDesktopMode(&desktopMode); if (gDebugOpenGL) printf("Desktop mode %d blue bits, %d green bits, %d red bits, %dx%d\n", desktopMode.BlueBits, desktopMode.GreenBits, desktopMode.RedBits, desktopMode.Width, desktopMode.Height); gDesktopAspectRatio = float(desktopMode.Width)/float(desktopMode.Height); // Initialize glew GLenum err=glewInit(); checkError("glewInit"); if(err!=GLEW_OK) { //problem: glewInit failed, something is seriously wrong printf("Fail to init glew: Error: %s\n", glewGetErrorString(err)); checkError("glewInit"); return -1; } // Only continue, if OpenGL of the expected version is supported. int major, minor, revision; glfwGetGLVersion(&major, &minor, &revision); if ((major == 3 && minor < 3) || major < 3) { ErrorDialog("OpenGL context version parsed by GLFW: %u.%u.%u. Version 3.3 required\n", major, minor, revision); } if (gDebugOpenGL) { dumpInfo(major, minor, revision); // Enable this to show some version information about the OpenGL and the graphics card. // dumpGraphicsMemoryStats(); // const GLubyte* sExtensions = glGetString(GL_EXTENSIONS); // printf("GL extensions: %s\n", sExtensions); // glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); if (glDebugMessageCallbackARB != 0) glDebugMessageCallbackARB(DebugFunc, (void*)15); else if (glDebugMessageCallbackAMD != 0) glDebugMessageCallbackAMD(DebugFuncAMD, (void*)15); } glfwSwapInterval(gOptions.fVSYNC); // 0 means do not wait for VSYNC, which would delay the FPS sometimes. ComputeRelativeChunksSortedDistances(); BlenderModel::InitModels(); Model::gPlayer.loginOk = true; gUniformBuffer.Init(); gDrawFont.Init("textures/georgia12"); // Must be done before gGameDialog. GameTexture::Init(); Controller::gGameDialog.init(); ChunkShader *shader = ChunkShader::Make(); gChunkShaderPicking.Init(); Tree::InitStatic(); gLantern.Init(shader); gQuadStage1.Init(); gBillboard.Init(); gSoundControl.RequestMusicMode(SoundControl::SMusicModeMenu); glEnable(GL_DEPTH_TEST); // Always enabled by default // Immediately clear screen, to minimize chance that something undefined is shown. glClearColor(0.0f, 0.0f, 0.0f, 1.0f ); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); glfwSwapBuffers(); if (sTestUser) Model::gPlayer.fTestPlayer = true; // Last thing before starting the game, update the save copy of the options. Options::sfSave = gOptions; while(glfwGetWindowParam(GLFW_OPENED)) { while (ListenForServerMessages()) continue; if (sTestUser && gMode.Get() == GameMode::LOGIN) { PerformLoginProcedure("", "", "", true); sTestUser = false; // Try this only once } static WorstTime tm(" Mainloop"); tm.Start(); gCurrentFrameTime = glfwGetTime(); if (gShowPing && gCurrentFrameTime - gLastPing > 5.0) { // It was a request, so we need to send a response unsigned char msg[4]; msg[0] = sizeof msg; msg[1] = 0; msg[2] = CMD_PING; msg[3] = 0; // 0 means request, 1 means response SendMsg(msg, sizeof msg); gLastPing = gCurrentFrameTime; gCurrentPing = 0.0; // Use a busy wait for the response, no time must be lost while (gCurrentPing == 0.0 && glfwGetTime() - gLastPing < 0.5) ListenForServerMessages(); } Controller::gGameDialog.Update(); Controller::gGameDialog.render(sHideGUI); glfwSwapBuffers(); if (gMode.Get() == GameMode::ESC) glfwCloseWindow(); tm.Stop(); } // The window is closed, request quit (which will save the player on the server side) unsigned char b[] = { 0x03, 0x00, CMD_QUIT }; SendMsg(b, sizeof b); // The logout acknowledge from the server may take sime time. Take the opportunity to // halt the process pool.ss gChunkProcess.RequestTerminate(); glswShutdown(); double timer = glfwGetTime(); // Wait for ack from server, but not indefinitely while (gMode.Get() == GameMode::GAME && glfwGetTime() - timer < 2.0) { glfwSleep(0.1); // Avoid a busy wait ListenForServerMessages(); // Wait for acknowledge } if (gMode.Get() == GameMode::GAME) { printf("Failed to disconnect from server\n"); } // The options will be saved by the destructor. Options::sfSave.fViewingDistance = maxRenderDistance; Options::sfSave.fPlayerX = Model::gPlayer.x; Options::sfSave.fPlayerY = Model::gPlayer.y; Options::sfSave.fPlayerZ = Model::gPlayer.z; gMode.Set(GameMode::EXIT); Options::sfSave.Save(); return 0; }