make multiple controllers work

This commit is contained in:
Isaac0-dev 2025-06-11 22:34:12 +10:00
parent 18ac4b985d
commit aae3e57bb0
12 changed files with 125 additions and 45 deletions

View file

@ -575,7 +575,7 @@ void init_controllers(void) {
}
}
for (u8 i = 0; i < gNumPlayersLocal; i++) {
for (u8 i = 0; i < POSSIBLE_NUM_PLAYERS; i++) {
gControllers[i].controllerData = &gControllerPads[i];
}

View file

@ -211,6 +211,46 @@ void set_screen_rendering(u16 index) {
if (gNumPlayersLocal == 3 && index == 2) {
gSw = 2;
aspect_mask = 1.f;
aspect_mask = 2.f;
}
}
bool dummy_initialize(UNUSED enum NetworkType type, UNUSED bool reconnecting) { return true; }
s64 dummy_get_id(UNUSED u8 localIndex) { return 0; }
char* dummy_get_id_str(UNUSED u8 localIndex) { return "dummy_id"; }
void dummy_save_id(UNUSED u8 localIndex, UNUSED s64 networkId) {}
void dummy_clear_id(UNUSED u8 localIndex) {}
void* dummy_dup_addr(UNUSED u8 localIndex) { return NULL; }
bool dummy_match_addr(void* addr1, void* addr2) { return addr1 == addr2; }
void dummy_update(void) {}
int dummy_send(UNUSED u8 localIndex, UNUSED void* addr, UNUSED u8* data, UNUSED u16 dataLength) { return 0; }
void dummy_get_lobby_id(char* destination, u32 destLength) {
if (destLength > 0) {
strncpy(destination, "dummy_lobby", destLength - 1);
destination[destLength - 1] = '\0';
}
}
void dummy_get_lobby_secret(char* destination, u32 destLength) {
if (destLength > 0) {
strncpy(destination, "dummy_secret", destLength - 1);
destination[destLength - 1] = '\0';
}
}
void dummy_shutdown(UNUSED bool reconnecting) {}
struct NetworkSystem gNetworkSystemDummy = {
.initialize = dummy_initialize,
.get_id = dummy_get_id,
.get_id_str = dummy_get_id_str,
.save_id = dummy_save_id,
.clear_id = dummy_clear_id,
.dup_addr = dummy_dup_addr,
.match_addr = dummy_match_addr,
.update = dummy_update,
.send = dummy_send,
.get_lobby_id = dummy_get_lobby_id,
.get_lobby_secret = dummy_get_lobby_secret,
.shutdown = dummy_shutdown,
.requireServerBroadcast = false,
.name = "Offline",
};

View file

@ -30,6 +30,8 @@ extern struct HudDisplay gHudDisplays[];
extern struct Controller gSharedController;
extern struct Controller *gSharedCtr;
extern struct NetworkSystem gNetworkSystemDummy;
typedef struct { u8 w, h; f32 a; } ScreenSize;
struct GfxLoad {

View file

@ -360,7 +360,6 @@ void patch_mtx_interpolated(f32 delta) {
delta_interpolate_vec3f(focusInterp, sCameraNode->prevFocus, sCameraNode->focus, delta);
mtxf_lookat(camInterp.m, posInterp, focusInterp, sCameraNode->roll);
mtxf_to_mtx(&camInterp, camInterp.m);
printf("%d interp (%d, %d), curr: (%d, %d), interp: (%d, %d)\n", gCurrPlayer, (int) sCameraNode->prevPos[0], (int) sCameraNode->prevPos[2], (int) sCameraNode->pos[0], (int) sCameraNode->pos[2], (int) posInterp[0], (int) posInterp[2]);
// printf("%d interp (%d, %d), real: (%d, %d)\n", gCurrPlayer, (int) sCameraNode->focus[0], (int) sCameraNode->focus[2], (int) sCameraNode->prevFocus[0], (int) sCameraNode->prevFocus[2]);
}
@ -615,7 +614,6 @@ static void geo_process_camera(struct GraphNodeCamera *node) {
vec3f_copy(node->pos, sCameraNodes[gCurrPlayer].pos);
vec3f_copy(node->focus, sCameraNodes[gCurrPlayer].focus);
printf("%d cam (%d, %d), real: (%d, %d)\n", gCurrPlayer, (int) node->pos[0], (int) node->pos[2], (int) gLakituState.pos[0], (int) gLakituState.pos[2]);
// printf("%d cam (%d, %d), real: (%d, %d)\n", gCurrPlayer, (int) node->focus[0], (int) node->focus[2], (int) gLakituState.focus[0], (int) gLakituState.focus[2]);
vec3f_copy(node->prevPos, node->pos);

View file

@ -69,21 +69,24 @@ void osContGetReadData(OSContPad *pad) {
void osContGetReadDataIndex(OSContPad *pad, int i) {
osContResetPad(pad);
struct ControllerPlace *cntr = &gPlayerControllerInfos[i];
if (!cntr->connected) { return; }
struct ControllerInfo *cntr = &gPlayerControllerInfos[i];
if (cntr->type >= ARRAY_COUNT(controller_implementations)) {
return;
}
gReadingController = cntr;
controller_implementations[cntr->type]->read(pad);
gReadingController = NULL;
}
void osContGetReadDataIndexNoReset(OSContPad *pad, int i) {
struct ControllerPlace *cntr = &gPlayerControllerInfos[i];
struct ControllerInfo *cntr = &gPlayerControllerInfos[i];
if (!cntr->connected) { return; }
if (cntr->type >= ARRAY_COUNT(controller_implementations)) {
return;
}
gReadingController = cntr;
controller_implementations[cntr->type]->read(pad);
gReadingController = NULL;
}
u32 controller_get_raw_key(void) {

View file

@ -16,10 +16,12 @@
#include "controller_api.h"
#include "controller_sdl.h"
#include "controller_mouse.h"
#include "controller_system.h"
#include "pc/pc_main.h"
#include "pc/configfile.h"
#include "pc/platform.h"
#include "pc/fs/fs.h"
#include "game/local_multiplayer.h"
#include "game/level_update.h"
#include "game/first_person_cam.h"
@ -205,6 +207,14 @@ static void controller_sdl_read(OSContPad *pad) {
if (configDisableGamepads) { return; }
u8 readController = configGamepadNumber;
if (gNumPlayersLocal > 1 && gReadingController) {
readController = gReadingController->index;
sdl_cntrl = gReadingController->sdl_cntrl;
sdl_haptic = gReadingController->sdl_haptic;
sdl_joystick = gReadingController->sdl_joystick;
}
SDL_GameControllerUpdate();
if (sdl_cntrl != NULL && !SDL_GameControllerGetAttached(sdl_cntrl)) {
@ -214,21 +224,26 @@ static void controller_sdl_read(OSContPad *pad) {
sdl_haptic = NULL;
}
if ((!sdl_cntrl && !sdl_joystick) || last_gamepad != configGamepadNumber) {
if ((!sdl_cntrl && !sdl_joystick)) {
if (sdl_haptic) { SDL_HapticClose(sdl_haptic); sdl_haptic = NULL; }
if (sdl_cntrl) { SDL_GameControllerClose(sdl_cntrl); sdl_cntrl = NULL; }
if (sdl_joystick) { SDL_JoystickClose(sdl_joystick); sdl_joystick = NULL; }
last_gamepad = configGamepadNumber;
if (SDL_IsGameController(configGamepadNumber)) {
sdl_cntrl = SDL_GameControllerOpen(configGamepadNumber);
last_gamepad = readController;
if (SDL_IsGameController(readController)) {
sdl_cntrl = SDL_GameControllerOpen(readController);
if (sdl_cntrl != NULL) {
sdl_haptic = controller_sdl_init_haptics(configGamepadNumber);
sdl_haptic = controller_sdl_init_haptics(readController);
}
} else {
sdl_joystick = SDL_JoystickOpen(configGamepadNumber);
sdl_joystick = SDL_JoystickOpen(readController);
if (!sdl_joystick) { return; }
}
}
if (gReadingController) {
gReadingController->sdl_cntrl = sdl_cntrl;
gReadingController->sdl_haptic = sdl_haptic;
gReadingController->sdl_joystick = sdl_joystick;
}
int16_t leftx = 0, lefty = 0, rightx = 0, righty = 0;
int16_t ltrig = 0, rtrig = 0;

View file

@ -8,6 +8,7 @@
#include "pc/djui/djui_panel_splitscreen.h"
#include "engine/math_util.h"
#include "pc/network/network.h"
#include "pc/pc_main.h"
// Constants for clarity
#define MAX_GAMEPADS 10
@ -17,8 +18,10 @@
char gGamepadChoicesBuffer[MAX_GAMEPADS][MAX_NAME_LEN] = { 0 };
char *gGamepadChoices[MAX_GAMEPADS] = { 0 };
int gNumJoys = 0;
bool gSuppressConnectedPopup = true;
struct ControllerInfo *gReadingController = NULL;
struct ControllerPlace gPlayerControllerInfos[POSSIBLE_NUM_PLAYERS] = {{
struct ControllerInfo gPlayerControllerInfos[POSSIBLE_NUM_PLAYERS] = {{
.index = 0,
.type = 1, // Make player 1 the keyboard by default
.connected = true
@ -42,9 +45,8 @@ void controller_update_gamepad_choices() {
if (gNumJoys <= 0) { gNumJoys = 1; }
if (gNumJoys > MAX_GAMEPADS) { gNumJoys = MAX_GAMEPADS; }
gGamepadChoices[0] = gGamepadChoicesBuffer[0];
for (int i = 0; i < gNumJoys; i++) {
gGamepadChoices[i] = gGamepadChoicesBuffer[i];
const char *joystickName = SDL_JoystickNameForIndex(i);
snprintf(gGamepadChoices[i], MAX_NAME_LEN, "%s", joystickName ? joystickName : "Unknown");
@ -69,21 +71,29 @@ void controller_update_gamepad_choices() {
void controller_update_controller_count() {
static u16 prevNumPlayers = 1;
gNumPlayersLocal = clamp(SDL_NumJoysticks() + 1, 1, POSSIBLE_NUM_PLAYERS);
for (u16 i = 1; i < POSSIBLE_NUM_PLAYERS; i++) {
struct ControllerPlace *c = &gPlayerControllerInfos[i];
if (c->type == 1) {
for (u16 i = 0, index = 0; i < gNumPlayersLocal; i++) {
struct ControllerInfo *c = &gPlayerControllerInfos[i];
if (gNumPlayersLocal == 1 && c->type == 1 && i != 0) {
++gNumPlayersLocal;
break;
}
c->connected = true;
c->index = index;
if (c->type == 1) { continue; }
index++;
}
gSuppressConnectedPopup = gGameInited;
if (gNumPlayersLocal > prevNumPlayers) {
extern const struct PlayerPalette DEFAULT_MARIO_PALETTE;
network_player_connected(NPT_LOCAL, gNumPlayersLocal - 1, 0, &DEFAULT_MARIO_PALETTE, "Mario", "0");
char name[10];
snprintf(name, 10, "Player-%d", gNumPlayersLocal);
network_player_connected(NPT_LOCAL, gNumPlayersLocal - 1, 0, &DEFAULT_MARIO_PALETTE, name, "0");
} else if (gNumPlayersLocal < prevNumPlayers) {
u8 index = gNetworkPlayers[prevNumPlayers].globalIndex;
if (index == 0) { index = prevNumPlayers; }
network_player_disconnected(index);
}
gSuppressConnectedPopup = true;
prevNumPlayers = gNumPlayersLocal;
}

View file

@ -1,14 +1,18 @@
struct ControllerPlace {
struct ControllerInfo {
u8 index;
u32 type;
bool connected;
SDL_GameController *sdl_cntrl;
SDL_Joystick *sdl_joystick;
SDL_Haptic *sdl_haptic;
};
extern char *gGamepadChoices[];
extern bool gSuppressConnectedPopup;
extern int gNumJoys;
extern struct ControllerPlace gPlayerControllerInfos[];
extern struct ControllerInfo *gReadingController;
extern struct ControllerInfo gPlayerControllerInfos[];
void controller_update_gamepad_choices();
void controller_update_controller_count();
void controller_update_connected_controllers();

View file

@ -72,15 +72,21 @@ static void djui_hud_position_translate(f32* x, f32* y) {
if (sResolution == RESOLUTION_DJUI) {
djui_gfx_position_translate(x, y);
} else {
*x *= ((gSw == 1 && gSw == 1) ? 0.5f : 1.f);
*y *= ((gSh == 1 && gSw == 1) ? 0.5f : 1.f);
*x += (gfx_current_dimensions.aspect_ratio * SCREEN_HEIGHT * 0.5f) * gSx;
*y += (SCREEN_HEIGHT / 2) * gSy;
*x = GFX_DIMENSIONS_FROM_LEFT_EDGE(0) + *x;
*y = SCREEN_HEIGHT - *y;
}
// transform_y_f32(y, sResolution);
}
static void djui_hud_size_translate(f32* size) {
if (sResolution == RESOLUTION_DJUI) {
djui_gfx_size_translate(size);
} else {
*size *= ((gSh == 1 && gSw == 1) ? 0.5f : 1.f);
}
}
@ -252,7 +258,7 @@ u32 djui_hud_get_screen_width(void) {
u32 r = (sResolution == RESOLUTION_N64)
? gfx_current_dimensions.aspect_ratio * SCREEN_HEIGHT
: (windowWidth / djui_gfx_get_scale());
if (gSw == 1) { return r / 2; }
if (gSw == 1 && gSh != 1) { return r / 2; }
return r;
}
@ -263,7 +269,7 @@ u32 djui_hud_get_screen_height(void) {
u32 r = (sResolution == RESOLUTION_N64)
? SCREEN_HEIGHT
: (windowHeight / djui_gfx_get_scale());
if (gSh == 1) { return r / 2; }
if (gSh == 1 && gSw != 1) { return r / 2; }
return r;
}

View file

@ -14,20 +14,11 @@ struct DjuiSplitScreenWindow {
static struct DjuiSplitScreenWindow *sDjuiSplitScreenWindows[POSSIBLE_NUM_PLAYERS] = { 0 };
static void djui_panel_splitscreen_window_update_controller_text(struct DjuiSplitScreenWindow *window, u16 index) {
// Update the index translation
for (u16 i = 0, index = 0; i < POSSIBLE_NUM_PLAYERS; i++) {
struct ControllerPlace *c = &gPlayerControllerInfos[i];
c->index = index;
if (c->type == 1) { continue; }
index++;
}
struct ControllerPlace *cntr = &gPlayerControllerInfos[index];
struct ControllerInfo *cntr = &gPlayerControllerInfos[index];
const char *name = "Main Keyboard";
if (cntr->type != 1) {
name = SDL_JoystickNameForIndex(cntr->index);
name = name ? name : "Disconnected";
name = (name) ? name : "Disconnected";
}
djui_text_set_text(window->ctrText, name);
@ -54,13 +45,13 @@ void djui_panel_splitscreen_selection_box_changed(struct DjuiBase *caller) {
struct DjuiSplitScreenWindow *window = sDjuiSplitScreenWindows[i];
if (!window || window->selectionBox != selectionBox) { continue; }
struct ControllerPlace *cntr = &gPlayerControllerInfos[i];
struct ControllerInfo *cntr = &gPlayerControllerInfos[i];
if (cntr->type != 1) { continue; }
// This player is a keyboard
for (u16 j = 0; j < POSSIBLE_NUM_PLAYERS; j++) {
if (i == j) { continue; }
struct ControllerPlace *c = &gPlayerControllerInfos[j];
struct ControllerInfo *c = &gPlayerControllerInfos[j];
if (c->type == 1) {
c->type = 0;
struct DjuiSplitScreenWindow *window2 = sDjuiSplitScreenWindows[j];
@ -75,7 +66,7 @@ void djui_panel_splitscreen_selection_box_changed(struct DjuiBase *caller) {
static struct DjuiSplitScreenWindow *djui_panel_splitscreen_controller_window_create(struct DjuiBase *parent, u16 index) {
struct DjuiSplitScreenWindow *window = calloc(1, sizeof(struct DjuiSplitScreenWindow));
struct ControllerPlace *cntr = &gPlayerControllerInfos[index];
struct ControllerInfo *cntr = &gPlayerControllerInfos[index];
// Border
window->rect = djui_rect_create(parent);
@ -129,6 +120,7 @@ void djui_panel_splitscreen_options_create(struct DjuiBase* caller) {
struct DjuiThreePanel *panel = djui_panel_menu_create(DLANG(HOST, SPLITSCREEN), false);
struct DjuiBase *body = djui_three_panel_get_body(panel);
controller_update_controller_count();
{
for (u16 i = 0; i < POSSIBLE_NUM_PLAYERS; i += 2) {
struct DjuiFlowLayout* row = djui_flow_layout_create(body);

View file

@ -102,8 +102,6 @@ bool network_is_online() {
void network_set_system(enum NetworkSystemType nsType) {
network_forget_all_reliable();
if (!network_is_online()) { gNetworkSystem = NULL; }
switch (nsType) {
case NS_SOCKET: gNetworkSystem = &gNetworkSystemSocket; break;
#ifdef COOPNET
@ -111,6 +109,7 @@ void network_set_system(enum NetworkSystemType nsType) {
#endif
default: gNetworkSystem = &gNetworkSystemSocket; LOG_ERROR("Unknown network system: %d", nsType); break;
}
if (!network_is_online()) { gNetworkSystem = &gNetworkSystemDummy; }
}
bool network_init(enum NetworkType inNetworkType, bool reconnecting) {
@ -174,6 +173,14 @@ bool network_init(enum NetworkType inNetworkType, bool reconnecting) {
dynos_behavior_hook_all_custom_behaviors();
network_player_connected(NPT_LOCAL, 0, configPlayerModel, &configPlayerPalette, configPlayerName, get_local_discord_id());
extern const struct PlayerPalette DEFAULT_MARIO_PALETTE;
for (u8 i = 1; i < gNumPlayersLocal; i++) {
char name[10];
snprintf(name, 10, "Player-%d", i);
network_player_connected(NPT_LOCAL, i, 0, &DEFAULT_MARIO_PALETTE, name, "0");
}
extern u8* gOverrideEeprom;
gOverrideEeprom = NULL;

View file

@ -18,6 +18,7 @@
#include "game/mario.h"
#include "pc/djui/djui_unicode.h"
#include "game/local_multiplayer.h"
#include "pc/controller/controller_system.h"
struct NetworkPlayer gNetworkPlayers[MAX_PLAYERS] = { 0 };
struct NetworkPlayer *gNetworkPlayerLocal = NULL;
@ -207,6 +208,7 @@ void network_player_update(void) {
for (s32 i = 1; i < MAX_PLAYERS; i++) {
struct NetworkPlayer *np = &gNetworkPlayers[i];
if (!np->connected && i > 0) { continue; }
if (i < gNumPlayersLocal) { continue; }
float elapsed = (clock_elapsed() - np->lastPingSent);
if (elapsed > NETWORK_PLAYER_PING_TIMEOUT) {
network_send_ping(np);
@ -218,6 +220,7 @@ void network_player_update(void) {
for (s32 i = 1; i < MAX_PLAYERS; i++) {
struct NetworkPlayer *np = &gNetworkPlayers[i];
if (!np->connected && i > 0) { continue; }
if (i < gNumPlayersLocal) { continue; }
float elapsed = (clock_elapsed() - np->lastReceived);
#ifdef DEVELOPMENT
@ -352,7 +355,7 @@ u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex, u8 mode
}
// display connected popup
if (!gCurrentlyJoining && type != NPT_SERVER && (gNetworkType != NT_SERVER || type != NPT_LOCAL)) {
if (!gCurrentlyJoining && type != NPT_SERVER && (gNetworkType != NT_SERVER || type != NPT_LOCAL || !gSuppressConnectedPopup)) {
construct_player_popup(np, DLANG(NOTIF, CONNECTED), NULL);
}
LOG_INFO("player connected, local %d, global %d", localIndex, np->globalIndex);
@ -405,7 +408,7 @@ u8 network_player_disconnected(u8 globalIndex) {
LOG_INFO("player disconnected, local %d, global %d", i, globalIndex);
// display popup
if (np->localIndex >= gNumPlayersLocal) {
if (np->type != NPT_LOCAL || !gSuppressConnectedPopup) {
construct_player_popup(np, DLANG(NOTIF, DISCONNECTED), NULL);
}