void IN_StartupJoystick (void) { int i; int nummappings; char controllerdb[MAX_OSPATH]; SDL_GameController *gamecontroller; if (COM_CheckParm("-nojoy")) return; if (SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) == -1 ) { Con_Warning("could not initialize SDL Game Controller\n"); return; } // Load additional SDL2 controller definitions from gamecontrollerdb.txt q_snprintf (controllerdb, sizeof(controllerdb), "%s/gamecontrollerdb.txt", com_basedir); nummappings = SDL_GameControllerAddMappingsFromFile(controllerdb); if (nummappings > 0) Con_Printf("%d mappings loaded from gamecontrollerdb.txt\n", nummappings); // Also try host_parms->userdir if (host_parms->userdir != host_parms->basedir) { q_snprintf (controllerdb, sizeof(controllerdb), "%s/gamecontrollerdb.txt", host_parms->userdir); nummappings = SDL_GameControllerAddMappingsFromFile(controllerdb); if (nummappings > 0) Con_Printf("%d mappings loaded from gamecontrollerdb.txt\n", nummappings); } for (i = 0; i < SDL_NumJoysticks(); i++) { const char *joyname = SDL_JoystickNameForIndex(i); if ( SDL_IsGameController(i) ) { const char *controllername = SDL_GameControllerNameForIndex(i); gamecontroller = SDL_GameControllerOpen(i); if (gamecontroller) { Con_Printf("detected controller: %s\n", controllername != NULL ? controllername : "NULL"); joy_active_instaceid = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(gamecontroller)); joy_active_controller = gamecontroller; break; } else { Con_Warning("failed to open controller: %s\n", controllername != NULL ? controllername : "NULL"); } } else { Con_Warning("joystick missing controller mappings: %s\n", joyname != NULL ? joyname : "NULL" ); } } }
ControllerMgr::ControllerMgr() : m_KBCtrl(), m_GameCtrl(), m_MenuCtrl(m_GameCtrl) { m_GameCtrl.Add(&m_KBCtrl); std::string mappings = Resources::Map("gamecontrollerdb.txt"); if(SDL_GameControllerAddMappingsFromFile(mappings.c_str())<0 ) { log_errorf("Couldn't load %s. Some controllers might not work.\n",mappings.c_str()); } // scan for already-attached controllers int i; for(i=0; i<SDL_NumJoysticks(); ++i) { if (!SDL_IsGameController(i)) { // printf("joy %d is not controller\n",i); continue; } SDLController* c = new SDLController(i); m_Attached.push_back(c); m_GameCtrl.Add(c); // printf("Found controller: %d\n",c->InstanceID()); break; } }
inline int add_controller_mapping_from_file(const std::string& filename) { int result = SDL_GameControllerAddMappingsFromFile(filename.c_str()); if(result == -1) { GUM_ERROR_HANDLER(result); } return result; }
void JoyInit(CArray *joys) { char buf[CDOGS_PATH_MAX]; GetDataFilePath(buf, "data/gamecontrollerdb.txt"); if (SDL_GameControllerAddMappingsFromFile(buf) == -1) { LOG(LM_INPUT, LL_ERROR, "cannot load controller mappings file: %s", SDL_GetError()); } GetDataFilePath(buf, "data/gamecontrollerbuttondb.txt"); if (SDLJBN_AddMappingsFromFile(buf) == -1) { LOG(LM_INPUT, LL_ERROR, "cannot load button mappings file: %s", SDLJBN_GetError()); } CArrayInit(joys, sizeof(Joystick)); // Detect all current controllers const int n = SDL_NumJoysticks(); LOG(LM_INPUT, LL_INFO, "%d controllers found", n); if (n == 0) { return; } for (int i = 0; i < n; i++) { JoyAdded(i); } }
void load_mappings(const char* filename) { int result = SDL_GameControllerAddMappingsFromFile(filename); if (result == -1) { printf("Error loading controller mappings\n"); } else { printf("Loaded %d controller mappings\n", result); } }
/* * Add controller mappings from the specified file */ void S2D_AddControllerMappingsFromFile(const char *path) { if (!S2D_FileExists(path)) { S2D_Log(S2D_WARN, "Controller mappings file not found: %s", path); return; } int mappings_added = SDL_GameControllerAddMappingsFromFile(path); if (mappings_added == -1) { S2D_Error("SDL_GameControllerAddMappingsFromFile", SDL_GetError()); } else { S2D_Log(S2D_INFO, "Added %i controller mapping(s)", mappings_added); } }
bool Input::init(const std::string& inputDBFilename) { m_Keyboard = new Keyboard(); m_Mouse = new Mouse(); SDL_GameControllerAddMappingsFromFile(inputDBFilename.c_str()); int numOfJoypads = SDL_NumJoysticks(); for (int i = 0; i < numOfJoypads; i++) { //Is the joypad able to use the new controller interface if (SDL_IsGameController(i)) { SDL_GameController *controller = SDL_GameControllerOpen(i); Joypad * joypad = new Joypad(controller); m_AttachedJoypads.push_back(joypad); } } return true; }
void initGameControllers() { SDL_GameControllerAddMappingsFromFile("gamecontrollerdb.txt"); int c = 0; bool found = false; //TODO: Bugger this and implement multi-controller support. game_controller = new GameController(); for (c = 0; c < SDL_NumJoysticks() && !found; ++c) //TODO: Bugger this and implement multi-controller support on a player-by-player basis. { if (SDL_IsGameController(c) && game_controller->open(c)) { printlog("(Device %d successfully initialized as game controller.)\n", c); found = true; //TODO: Bugger this and implement multi-controller support. } else { printlog("Info: device %d is not a game controller! Joysticks are not supported.\n", c); } } if (!found) { printlog("Info: No game controller detected!"); } }
int main(int argc, char *argv[]) { int i; int nController = 0; int retcode = 0; char guid[64]; SDL_GameController *gamecontroller; /* Enable standard application logging */ SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); /* Initialize SDL (Note: video is required to start event loop) */ if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) < 0) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError()); return 1; } SDL_GameControllerAddMappingsFromFile("gamecontrollerdb.txt"); /* Print information about the controller */ for (i = 0; i < SDL_NumJoysticks(); ++i) { const char *name; const char *description; SDL_JoystickGetGUIDString(SDL_JoystickGetDeviceGUID(i), guid, sizeof(guid)); if (SDL_IsGameController(i)) { nController++; name = SDL_GameControllerNameForIndex(i); description = "Controller"; } else { name = SDL_JoystickNameForIndex(i); description = "Joystick"; } SDL_Log("%s %d: %s (guid %s)\n", description, i, name ? name : "Unknown", guid); } SDL_Log("There are %d game controller(s) attached (%d joystick(s))\n", nController, SDL_NumJoysticks()); if (argv[1]) { SDL_bool reportederror = SDL_FALSE; SDL_bool keepGoing = SDL_TRUE; SDL_Event event; int device = atoi(argv[1]); if (device >= SDL_NumJoysticks()) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "%i is an invalid joystick index.\n", device); retcode = 1; } else { SDL_JoystickGetGUIDString(SDL_JoystickGetDeviceGUID(device), guid, sizeof(guid)); SDL_Log("Attempting to open device %i, guid %s\n", device, guid); gamecontroller = SDL_GameControllerOpen(device); /* - this requires SDL 2.0.4 if (gamecontroller != NULL) { SDL_assert(SDL_GameControllerFromInstanceID(SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(gamecontroller))) == gamecontroller); } */ while (keepGoing) { if (gamecontroller == NULL) { if (!reportederror) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open gamecontroller %d: %s\n", device, SDL_GetError()); retcode = 1; keepGoing = SDL_FALSE; reportederror = SDL_TRUE; } } else { reportederror = SDL_FALSE; keepGoing = WatchGameController(gamecontroller); SDL_GameControllerClose(gamecontroller); } gamecontroller = NULL; if (keepGoing) { SDL_Log("Waiting for attach\n"); } while (keepGoing) { SDL_WaitEvent(&event); if ((event.type == SDL_QUIT) || (event.type == SDL_FINGERDOWN) || (event.type == SDL_MOUSEBUTTONDOWN)) { keepGoing = SDL_FALSE; } else if (event.type == SDL_CONTROLLERDEVICEADDED) { gamecontroller = SDL_GameControllerOpen(event.cdevice.which); /* - this requires SDL 2.0.4 if (gamecontroller != NULL) { SDL_assert(SDL_GameControllerFromInstanceID(SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(gamecontroller))) == gamecontroller); } */ break; } } } } } SDL_QuitSubSystem(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER); return retcode; }
void SdlManager::TryLoadControllerMappingsFromFile(const char* fileName) { SDL_GameControllerAddMappingsFromFile(fileName); }
s32 proc() { #if _WIN32 SetProcessDPIAware(); #endif #if defined(__APPLE__) SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, "1"); #endif // Initialize SDL if (SDL_Init( SDL_INIT_VIDEO | SDL_INIT_EVENTS | SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC | SDL_INIT_TIMER | SDL_INIT_JOYSTICK ) < 0) { fprintf(stderr, "Failed to initialize SDL: %s\n", SDL_GetError()); return -1; } Loader::data_directory = SDL_GetPrefPath("HelveticaScenario", "Yearning"); SDL_GameControllerAddMappingsFromFile("gamecontrollerdb.txt"); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0); { SDL_DisplayMode display; SDL_GetDesktopDisplayMode(0, &display); Loader::settings_load(display.w, display.h); } if (SDL_SetRelativeMouseMode(SDL_TRUE) != 0) { fprintf(stderr, "Failed to set relative mouse mode: %s\n", SDL_GetError()); return -1; } window = SDL_CreateWindow ( "The Yearning", 0, 0, Settings::width, Settings::height, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_INPUT_GRABBED | SDL_WINDOW_INPUT_FOCUS | SDL_WINDOW_MOUSE_FOCUS | SDL_WINDOW_MOUSE_CAPTURE | SDL_WINDOW_ALLOW_HIGHDPI | (Settings::fullscreen ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_BORDERLESS) ); #if defined(__APPLE__) SDL_SetWindowGrab(window, SDL_TRUE); #endif // Open a window and create its OpenGL context if (!window) { fprintf(stderr, "Failed to open SDL window. Most likely your GPU is out of date! %s\n", SDL_GetError()); SDL_Quit(); return -1; } SDL_GLContext context = SDL_GL_CreateContext(window); if (!context) { fprintf(stderr, "Failed to create GL context: %s\n", SDL_GetError()); return -1; } if (SDL_GL_SetSwapInterval(Settings::vsync ? 1 : 0) != 0) { fprintf(stderr, "Failed to set OpenGL swap interval: %s\n", SDL_GetError()); return -1; } { glewExperimental = true; // Needed for core profile GLenum glew_result = glewInit(); if (glew_result != GLEW_OK) { fprintf(stderr, "Failed to initialize GLEW: %s\n", glewGetErrorString(glew_result)); return -1; } } glGetError(); // Clear initial error caused by GLEW render_init(); // Launch threads Sync<LoopSync> render_sync; LoopSwapper swapper_render_update = render_sync.swapper(0); LoopSwapper swapper_render = render_sync.swapper(1); Sync<PhysicsSync, 1> physics_sync; PhysicsSwapper swapper_physics = physics_sync.swapper(); PhysicsSwapper swapper_physics_update = physics_sync.swapper(); std::thread thread_physics(Physics::loop, &swapper_physics); std::thread thread_update(Loop::loop, &swapper_render_update, &swapper_physics_update); std::thread thread_ai(AI::loop); LoopSync* sync = swapper_render.get(); r64 last_time = SDL_GetTicks() / 1000.0; b8 has_focus = true; SDL_PumpEvents(); const u8* sdl_keys = SDL_GetKeyboardState(0); refresh_controllers(); while (true) { render(sync); // Swap buffers SDL_GL_SwapWindow(window); SDL_PumpEvents(); memcpy(sync->input.keys, sdl_keys, sizeof(sync->input.keys)); sync->input.keys[(s32)KeyCode::MouseWheelDown] = false; sync->input.keys[(s32)KeyCode::MouseWheelUp] = false; SDL_Event sdl_event; while (SDL_PollEvent(&sdl_event)) { if (sdl_event.type == SDL_QUIT) sync->quit = true; else if (sdl_event.type == SDL_MOUSEWHEEL) { b8 up = sdl_event.wheel.y > 0; if (sdl_event.wheel.direction == SDL_MOUSEWHEEL_FLIPPED) up = !up; if (up) sync->input.keys[(s32)KeyCode::MouseWheelUp] = true; else sync->input.keys[(s32)KeyCode::MouseWheelDown] = true; } else if (sdl_event.type == SDL_JOYDEVICEADDED || sdl_event.type == SDL_JOYDEVICEREMOVED) refresh_controllers(); else if (sdl_event.type == SDL_WINDOWEVENT) { if (sdl_event.window.event == SDL_WINDOWEVENT_FOCUS_GAINED) has_focus = true; else if (sdl_event.window.event == SDL_WINDOWEVENT_FOCUS_LOST) has_focus = false; } } sync->input.focus = has_focus; s32 mouse_buttons = SDL_GetRelativeMouseState(&sync->input.cursor_x, &sync->input.cursor_y); sync->input.keys[(s32)KeyCode::MouseLeft] = mouse_buttons & (1 << 0); sync->input.keys[(s32)KeyCode::MouseMiddle] = mouse_buttons & (1 << 1); sync->input.keys[(s32)KeyCode::MouseRight] = mouse_buttons & (1 << 2); s32 active_gamepads = 0; for (s32 i = 0; i < MAX_GAMEPADS; i++) { SDL_GameController* controller = controllers[i]; Gamepad* gamepad = &sync->input.gamepads[i]; gamepad->active = controller != 0; gamepad->btns = 0; if (gamepad->active) { gamepad->left_x = (r32)SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTX) / 32767.0f; gamepad->left_y = (r32)SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTY) / 32767.0f; gamepad->right_x = (r32)SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX) / 32767.0f; gamepad->right_y = (r32)SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY) / 32767.0f; gamepad->left_trigger = (r32)SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_TRIGGERLEFT) / 32767.0f; gamepad->right_trigger = (r32)SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_TRIGGERRIGHT) / 32767.0f; if (gamepad->left_trigger > 0.5f) gamepad->btns |= Gamepad::Btn::LeftTrigger; if (gamepad->right_trigger > 0.5f) gamepad->btns |= Gamepad::Btn::RightTrigger; if (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_LEFTSHOULDER)) gamepad->btns |= Gamepad::Btn::LeftShoulder; if (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER)) gamepad->btns |= Gamepad::Btn::RightShoulder; if (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_LEFTSTICK)) gamepad->btns |= Gamepad::Btn::LeftClick; if (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_RIGHTSTICK)) gamepad->btns |= Gamepad::Btn::RightClick; if (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_A)) gamepad->btns |= Gamepad::Btn::A; if (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_B)) gamepad->btns |= Gamepad::Btn::B; if (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_X)) gamepad->btns |= Gamepad::Btn::X; if (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_Y)) gamepad->btns |= Gamepad::Btn::Y; if (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_BACK)) gamepad->btns |= Gamepad::Btn::Back; if (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_START)) gamepad->btns |= Gamepad::Btn::Start; if (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_UP)) gamepad->btns |= Gamepad::Btn::DUp; if (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_DOWN)) gamepad->btns |= Gamepad::Btn::DDown; if (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_LEFT)) gamepad->btns |= Gamepad::Btn::DLeft; if (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_RIGHT)) gamepad->btns |= Gamepad::Btn::DRight; if (gamepad->rumble > 0.0f) SDL_HapticRumblePlay(haptics[i], gamepad->rumble, 33); gamepad->rumble = 0.0f; active_gamepads++; } else { gamepad->left_x = 0.0f; gamepad->left_y = 0.0f; gamepad->right_x = 0.0f; gamepad->right_y = 0.0f; gamepad->left_trigger = 0.0f; gamepad->right_trigger = 0.0f; gamepad->rumble = 0.0f; } } SDL_GetWindowSize(window, &sync->input.width, &sync->input.height); r64 time = (SDL_GetTicks() / 1000.0); sync->time.total = (r32)time; sync->time.delta = vi_min((r32)(time - last_time), 0.25f); last_time = time; b8 quit = sync->quit; sync = swapper_render.swap<SwapType_Read>(); if (quit || sync->quit) break; } AI::quit(); thread_update.join(); thread_physics.join(); thread_ai.join(); SDL_GL_DeleteContext(context); SDL_DestroyWindow(window); // SDL sucks for (s32 i = 0; i < MAX_GAMEPADS; i++) { if (haptics[i]) SDL_HapticClose(haptics[i]); } SDL_Quit(); return 0; }
int main(int argc, char *argv[]) { // Get path char *ip = NULL; unsigned short connect_port = 0; unsigned short listen_port = 0; int net_mode = NET_MODE_NONE; int ret = 0; // Path manager if(pm_init() != 0) { err_msgbox(pm_get_errormsg()); return 1; } // Check arguments if(argc >= 2) { if(strcmp(argv[1], "-v") == 0) { printf("OpenOMF v%d.%d.%d\n", V_MAJOR, V_MINOR, V_PATCH); printf("Source available at https://github.com/omf2097/ under MIT License\n"); printf("(C) 2097 Tuomas Virtanen, Andrew Thompson, Hunter and others\n"); goto exit_0; } else if(strcmp(argv[1], "-h") == 0) { printf("Arguments:\n"); printf("-h Prints this help\n"); printf("-c [ip] [port] Connect to server\n"); printf("-l [port] Start server\n"); goto exit_0; } else if(strcmp(argv[1], "-c") == 0) { if(argc >= 3) { ip = strcpy(malloc(strlen(argv[2])+1), argv[2]); } if(argc >= 4) { connect_port = atoi(argv[3]); } net_mode = NET_MODE_CLIENT; } else if(strcmp(argv[1], "-l") == 0) { if(argc >= 3) { listen_port = atoi(argv[2]); } net_mode = NET_MODE_SERVER; } } // Init log #if defined(DEBUGMODE) || defined(STANDALONE_SERVER) if(log_init(0)) { err_msgbox("Error while initializing log!"); goto exit_0; } #else if(log_init(pm_get_local_path(LOG_PATH))) { err_msgbox("Error while initializing log '%s'!", pm_get_local_path(LOG_PATH)); goto exit_0; } #endif // Simple header INFO("Starting OpenOMF v%d.%d.%d", V_MAJOR, V_MINOR, V_PATCH); // Dump pathmanager log pm_log(); // Random seed rand_seed(time(NULL)); // Init stringparser sd_stringparser_lib_init(); // Init config if(settings_init(pm_get_local_path(CONFIG_PATH))) { err_msgbox("Failed to initialize settings file"); goto exit_1; } settings_load(); // Find plugins and make sure they are valid plugins_init(); // Network game override stuff if(ip) { DEBUG("Connect IP overridden to %s", ip); settings_get()->net.net_connect_ip = ip; } if(connect_port > 0 && connect_port < 0xFFFF) { DEBUG("Connect Port overridden to %u", connect_port&0xFFFF); settings_get()->net.net_connect_port = connect_port; } if(listen_port > 0 && listen_port < 0xFFFF) { DEBUG("Listen Port overridden to %u", listen_port&0xFFFF); settings_get()->net.net_listen_port = listen_port; } // Init SDL2 unsigned int sdl_flags = SDL_INIT_TIMER; #ifndef STANDALONE_SERVER sdl_flags |= SDL_INIT_VIDEO; #endif if(SDL_Init(sdl_flags)) { err_msgbox("SDL2 Initialization failed: %s", SDL_GetError()); goto exit_2; } SDL_version sdl_linked; SDL_GetVersion(&sdl_linked); INFO("Found SDL v%d.%d.%d", sdl_linked.major, sdl_linked.minor, sdl_linked.patch); INFO("Running on platform: %s", SDL_GetPlatform()); #ifndef STANDALONE_SERVER if(SDL_InitSubSystem(SDL_INIT_JOYSTICK|SDL_INIT_GAMECONTROLLER|SDL_INIT_HAPTIC)) { err_msgbox("SDL2 Initialization failed: %s", SDL_GetError()); goto exit_2; } // Attempt to find gamecontrollerdb.txt, either from resources or from // built-in header SDL_RWops *rw = SDL_RWFromConstMem(gamecontrollerdb, strlen(gamecontrollerdb)); SDL_GameControllerAddMappingsFromRW(rw, 1); char *gamecontrollerdbpath = malloc(128); snprintf(gamecontrollerdbpath, 128, "%s/gamecontrollerdb.txt", pm_get_local_path(RESOURCE_PATH)); int mappings_loaded = SDL_GameControllerAddMappingsFromFile(gamecontrollerdbpath); if (mappings_loaded > 0) { DEBUG("loaded %d mappings from %s", mappings_loaded, gamecontrollerdbpath); } free(gamecontrollerdbpath); // Load up joysticks INFO("Found %d joysticks attached", SDL_NumJoysticks()); SDL_Joystick *joy; char guidstr[33]; for (int i = 0; i < SDL_NumJoysticks(); i++) { joy = SDL_JoystickOpen(i); if (joy) { SDL_JoystickGUID guid = SDL_JoystickGetGUID(joy); SDL_JoystickGetGUIDString(guid, guidstr, 33); INFO("Opened Joystick %d", i); INFO(" * Name: %s", SDL_JoystickNameForIndex(i)); INFO(" * Number of Axes: %d", SDL_JoystickNumAxes(joy)); INFO(" * Number of Buttons: %d", SDL_JoystickNumButtons(joy)); INFO(" * Number of Balls: %d", SDL_JoystickNumBalls(joy)); INFO(" * Number of Hats: %d", SDL_JoystickNumHats(joy)); INFO(" * GUID : %s", guidstr); } else { INFO("Joystick %d is unsupported", i); } if (SDL_JoystickGetAttached(joy)) { SDL_JoystickClose(joy); } } // Init libDumb dumb_register_stdfiles(); #endif // Init enet if(enet_initialize() != 0) { err_msgbox("Failed to initialize enet"); goto exit_3; } // Initialize engine if(engine_init()) { err_msgbox("Failed to initialize game engine."); goto exit_4; } // Run engine_run(net_mode); // Close everything engine_close(); exit_4: enet_deinitialize(); exit_3: SDL_Quit(); exit_2: dumb_exit(); settings_save(); settings_free(); exit_1: sd_stringparser_lib_deinit(); INFO("Exit."); log_close(); exit_0: if (ip) { free(ip); } plugins_close(); pm_free(); return ret; }