mirror of
				https://github.com/coop-deluxe/sm64coopdx.git
				synced 2025-10-30 08:01:01 +00:00 
			
		
		
		
	Removed two-player hacks from cannon and object packets
Increased error checking of get_behavior_from_id Made failure logging for packet_object a lot better Changed debug logging to show global index instead of "Server/Client" Changed debug keyboard binds to support more keyboard types Made SyncObject's rxEventId de-duplication per-player instead of one-player Removed sizeof(enum) from packet_read/packet_write
This commit is contained in:
		
							parent
							
								
									aaa7e65b65
								
							
						
					
					
						commit
						c8a45235ca
					
				
					 15 changed files with 117 additions and 90 deletions
				
			
		| 
						 | 
				
			
			@ -524,5 +524,8 @@ enum BehaviorId get_id_from_behavior(const BehaviorScript* behavior) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
const BehaviorScript* get_behavior_from_id(enum BehaviorId id) {
 | 
			
		||||
    if (id < 0 || id >= id_bhv_max_count) {
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    return gBehaviorTable[id];
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -350,10 +350,10 @@
 | 
			
		|||
#define /*0x1AC*/ oTripletButterflyScalePhase        OBJECT_FIELD_S32(0x49)
 | 
			
		||||
 | 
			
		||||
/* Cannon */
 | 
			
		||||
#define /*0x0F4*/ oCannonUnkF4   OBJECT_FIELD_S32(0x1B)
 | 
			
		||||
#define /*0x0F8*/ oCannonUnkF8   OBJECT_FIELD_S32(0x1C)
 | 
			
		||||
#define /*0x10C*/ oCannonUnk10C  OBJECT_FIELD_S32(0x21)
 | 
			
		||||
#define /*0x110*/ oCannonIsLocal OBJECT_FIELD_S32(0x22)
 | 
			
		||||
#define /*0x0F4*/ oCannonUnkF4       OBJECT_FIELD_S32(0x1B)
 | 
			
		||||
#define /*0x0F8*/ oCannonUnkF8       OBJECT_FIELD_S32(0x1C)
 | 
			
		||||
#define /*0x10C*/ oCannonUnk10C      OBJECT_FIELD_S32(0x21)
 | 
			
		||||
#define /*0x110*/ oCannonPlayerIndex OBJECT_FIELD_S32(0x22)
 | 
			
		||||
 | 
			
		||||
/* Cap */
 | 
			
		||||
#define /*0x0F4*/ oCapUnkF4 OBJECT_FIELD_S32(0x1B)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,7 +29,7 @@ void opened_cannon_act_0(void) {
 | 
			
		|||
                o->oAction = 4;
 | 
			
		||||
                o->oCannonUnk10C = 1;
 | 
			
		||||
                o->oCannonUnkF8 = 1;
 | 
			
		||||
                o->oCannonIsLocal = TRUE;
 | 
			
		||||
                o->oCannonPlayerIndex = 0;
 | 
			
		||||
                network_send_object(o);
 | 
			
		||||
            } else {
 | 
			
		||||
                o->oInteractStatus = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -53,10 +53,12 @@ void opened_cannon_act_4(void) {
 | 
			
		|||
        o->oPosZ += (f32)((o->oTimer / 2 & 1) - 0.5) * 4;
 | 
			
		||||
        o->oAction = 6;
 | 
			
		||||
    }
 | 
			
		||||
    if (!o->oCannonIsLocal) {
 | 
			
		||||
        // two-player hack
 | 
			
		||||
        gMarioStates[1].marioObj->oMarioCannonObjectYaw = o->oMoveAngleYaw;
 | 
			
		||||
        gMarioStates[1].marioObj->oMarioCannonInputYaw = 0;
 | 
			
		||||
    if (o->oCannonPlayerIndex != 0) {
 | 
			
		||||
        struct MarioState* controlledBy = &gMarioStates[o->oCannonPlayerIndex];
 | 
			
		||||
        if (controlledBy->marioObj != NULL) {
 | 
			
		||||
            controlledBy->marioObj->oMarioCannonObjectYaw = o->oMoveAngleYaw;
 | 
			
		||||
            controlledBy->marioObj->oMarioCannonInputYaw = 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -74,16 +76,12 @@ void opened_cannon_act_6(void) {
 | 
			
		|||
                o->oCannonUnkF4 += 0x400;
 | 
			
		||||
            } else if (o->oTimer < 26) {
 | 
			
		||||
            } else {
 | 
			
		||||
                if (o->oCannonIsLocal) {
 | 
			
		||||
                    gMarioStates[0].marioObj->oMarioCannonObjectYaw = o->oMoveAngleYaw;
 | 
			
		||||
                    gMarioStates[0].marioObj->oMarioCannonInputYaw = 0;
 | 
			
		||||
                    gMarioStates[0].faceAngle[0] = 8192;
 | 
			
		||||
                } else {
 | 
			
		||||
                    // two-player hack
 | 
			
		||||
                    gMarioStates[1].marioObj->oMarioCannonObjectYaw = o->oMoveAngleYaw;
 | 
			
		||||
                    gMarioStates[1].marioObj->oMarioCannonInputYaw = 0;
 | 
			
		||||
                    gMarioStates[1].faceAngle[0] = 8192;
 | 
			
		||||
                struct MarioState* controlledBy = &gMarioStates[o->oCannonPlayerIndex];
 | 
			
		||||
                if (controlledBy->marioObj != NULL) {
 | 
			
		||||
                    controlledBy->marioObj->oMarioCannonObjectYaw = o->oMoveAngleYaw;
 | 
			
		||||
                    controlledBy->marioObj->oMarioCannonInputYaw = 0;
 | 
			
		||||
                }
 | 
			
		||||
                controlledBy->faceAngle[0] = 8192;
 | 
			
		||||
 | 
			
		||||
                o->oCannonUnkF4 = 0;
 | 
			
		||||
                o->oAction = 5;
 | 
			
		||||
| 
						 | 
				
			
			@ -109,16 +107,18 @@ void opened_cannon_act_5(void) {
 | 
			
		|||
 | 
			
		||||
void opened_cannon_act_1(void) {
 | 
			
		||||
    UNUSED s32 unused;
 | 
			
		||||
    if (o->oCannonIsLocal) { // two-player hack
 | 
			
		||||
    if (o->oCannonPlayerIndex == 0) {
 | 
			
		||||
        cur_obj_become_intangible();
 | 
			
		||||
        cur_obj_disable_rendering();
 | 
			
		||||
    } else {
 | 
			
		||||
        struct MarioState* marioState = &gMarioStates[1]; // two-player hack
 | 
			
		||||
        o->oMoveAnglePitch = 14563 + marioState->faceAngle[0] * -0.5f;
 | 
			
		||||
        o->oMoveAngleYaw = marioState->marioObj->oMarioCannonObjectYaw + marioState->marioObj->oMarioCannonInputYaw;
 | 
			
		||||
        struct MarioState* controlledBy = &gMarioStates[o->oCannonPlayerIndex];
 | 
			
		||||
        o->oMoveAnglePitch = 14563 + controlledBy->faceAngle[0] * -0.5f;
 | 
			
		||||
        if (controlledBy->marioObj != NULL) {
 | 
			
		||||
            o->oMoveAngleYaw = controlledBy->marioObj->oMarioCannonObjectYaw + controlledBy->marioObj->oMarioCannonInputYaw;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    o->oCannonUnk10C = 0;
 | 
			
		||||
    if (o->oCannonIsLocal) {
 | 
			
		||||
    if (o->oCannonPlayerIndex == 0) {
 | 
			
		||||
        gMarioShotFromCannon = 1;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -131,7 +131,6 @@ void opened_cannon_act_3(void) {
 | 
			
		|||
    UNUSED s32 unused;
 | 
			
		||||
    if (o->oTimer > 3) {
 | 
			
		||||
        o->oAction = 0;
 | 
			
		||||
        o->oCannonIsLocal = FALSE;
 | 
			
		||||
        if (o->heldByPlayerIndex == 0) { network_send_object(o); }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -144,39 +143,37 @@ u8 unused0EA1FC[] = { 2,  0,   0, 0, 0,  0,   0, 0, 63, 128, 0, 0, 2,  0,   0, 0
 | 
			
		|||
                      63, 128, 0, 0, 2,  0,   0, 0, 65, 160, 0, 0, 63, 128, 0, 0, 2,  0,   0, 0,
 | 
			
		||||
                      65, 160, 0, 0, 63, 128, 0, 0, 8,  0,   0, 0, 65, 32,  0, 0, 63, 128, 0, 0 };
 | 
			
		||||
 | 
			
		||||
u8 cannon_ignore_remote_updates(void) {
 | 
			
		||||
    // two-player hack
 | 
			
		||||
    return ((gNetworkType == NT_SERVER) && o->oCannonIsLocal);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void cannon_on_received_post(u8 fromLocalIndex) {
 | 
			
		||||
    // check if we're on in the cannon too
 | 
			
		||||
    struct MarioState* m = &gMarioStates[0];
 | 
			
		||||
    if (m->action != ACT_IN_CANNON) { return; }
 | 
			
		||||
    if (m->interactObj != o) { return; }
 | 
			
		||||
    // two-player hack
 | 
			
		||||
    if (gNetworkType == NT_SERVER) { return; }
 | 
			
		||||
    u8 shouldEject =  (m->action == ACT_IN_CANNON)
 | 
			
		||||
                   && (m->interactObj == o)
 | 
			
		||||
                   && gNetworkPlayers[fromLocalIndex].globalIndex < gNetworkPlayerLocal->globalIndex;
 | 
			
		||||
 | 
			
		||||
    // eject the player by shooting out of the cannon weakly
 | 
			
		||||
    m->forwardVel = 10.0f * coss(m->faceAngle[0]);
 | 
			
		||||
    m->vel[1] = 10.0f * sins(m->faceAngle[0]);
 | 
			
		||||
    m->pos[0] += 120.0f * coss(m->faceAngle[0]) * sins(m->faceAngle[1]);
 | 
			
		||||
    m->pos[1] += 120.0f * sins(m->faceAngle[0]);
 | 
			
		||||
    m->pos[2] += 120.0f * coss(m->faceAngle[0]) * coss(m->faceAngle[1]);
 | 
			
		||||
    set_mario_action(m, ACT_SHOT_FROM_CANNON, 0);
 | 
			
		||||
    if (shouldEject) {
 | 
			
		||||
        // eject the player by shooting out of the cannon weakly
 | 
			
		||||
        m->forwardVel = 10.0f * coss(m->faceAngle[0]);
 | 
			
		||||
        m->vel[1] = 10.0f * sins(m->faceAngle[0]);
 | 
			
		||||
        m->pos[0] += 120.0f * coss(m->faceAngle[0]) * sins(m->faceAngle[1]);
 | 
			
		||||
        m->pos[1] += 120.0f * sins(m->faceAngle[0]);
 | 
			
		||||
        m->pos[2] += 120.0f * coss(m->faceAngle[0]) * coss(m->faceAngle[1]);
 | 
			
		||||
        set_mario_action(m, ACT_SHOT_FROM_CANNON, 0);
 | 
			
		||||
 | 
			
		||||
    // reset things that got messed up
 | 
			
		||||
    m->marioObj->header.gfx.node.flags |= GRAPH_RENDER_ACTIVE;
 | 
			
		||||
    reset_camera(gCamera);
 | 
			
		||||
    o->oCannonIsLocal = FALSE;
 | 
			
		||||
    cur_obj_become_tangible();
 | 
			
		||||
    cur_obj_enable_rendering();
 | 
			
		||||
        // reset things that got messed up
 | 
			
		||||
        m->marioObj->header.gfx.node.flags |= GRAPH_RENDER_ACTIVE;
 | 
			
		||||
        reset_camera(gCamera);
 | 
			
		||||
        o->oCannonPlayerIndex = fromLocalIndex;
 | 
			
		||||
        cur_obj_become_tangible();
 | 
			
		||||
        cur_obj_enable_rendering();
 | 
			
		||||
    } else {
 | 
			
		||||
        o->oCannonPlayerIndex = fromLocalIndex;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void bhv_cannon_base_sanity_check(void) {
 | 
			
		||||
    // figure out if it's still in use
 | 
			
		||||
    u8 inUse = FALSE;
 | 
			
		||||
    if (o->oCannonIsLocal) {
 | 
			
		||||
    if (o->oCannonPlayerIndex == 0) {
 | 
			
		||||
        inUse = (gMarioStates[0].action == ACT_IN_CANNON && gMarioStates[0].interactObj == o);
 | 
			
		||||
    } else {
 | 
			
		||||
        for (int i = 0; i < MAX_PLAYERS; i++) {
 | 
			
		||||
| 
						 | 
				
			
			@ -208,11 +205,18 @@ static void bhv_cannon_base_sanity_check(void) {
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void bhv_cannon_override_ownership(u8* shouldOverride, u8* shouldOwn) {
 | 
			
		||||
    if ((o->oAction != 0) && (o->oCannonPlayerIndex == 0)) {
 | 
			
		||||
        *shouldOverride = TRUE;
 | 
			
		||||
        *shouldOwn = TRUE;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void bhv_cannon_base_loop(void) {
 | 
			
		||||
    if (!network_sync_object_initialized(o)) {
 | 
			
		||||
        struct SyncObject* so = network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS);
 | 
			
		||||
        so->ignore_if_true = cannon_ignore_remote_updates;
 | 
			
		||||
        so->on_received_post = cannon_on_received_post;
 | 
			
		||||
        so->override_ownership = bhv_cannon_override_ownership;
 | 
			
		||||
        network_init_object_field(o, &o->oAction);
 | 
			
		||||
        network_init_object_field(o, &o->oPrevAction);
 | 
			
		||||
        network_init_object_field(o, &o->oTimer);
 | 
			
		||||
| 
						 | 
				
			
			@ -227,7 +231,7 @@ void bhv_cannon_base_loop(void) {
 | 
			
		|||
 | 
			
		||||
    bhv_cannon_base_sanity_check();
 | 
			
		||||
 | 
			
		||||
    if (o->oAction != 0 && !o->oCannonIsLocal) {
 | 
			
		||||
    if ((o->oAction != 0) && (o->oCannonPlayerIndex != 0)) {
 | 
			
		||||
        cur_obj_push_mario_away_from_cylinder(220, 300);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -59,6 +59,7 @@ void bhv_koopa_shell_loop(void) {
 | 
			
		|||
    struct Surface *sp34;
 | 
			
		||||
    obj_set_hitbox(o, &sKoopaShellHitbox);
 | 
			
		||||
    cur_obj_scale(1.0f);
 | 
			
		||||
    struct MarioState* marioState = nearest_mario_state_to_object(o);
 | 
			
		||||
    struct Object* player = NULL;
 | 
			
		||||
    switch (o->oAction) {
 | 
			
		||||
        case 0:
 | 
			
		||||
| 
						 | 
				
			
			@ -66,8 +67,7 @@ void bhv_koopa_shell_loop(void) {
 | 
			
		|||
            cur_obj_if_hit_wall_bounce_away();
 | 
			
		||||
            if (o->oInteractStatus & INT_STATUS_INTERACTED) {
 | 
			
		||||
                o->oAction++;
 | 
			
		||||
                player = nearest_player_to_object(o);
 | 
			
		||||
                o->heldByPlayerIndex = (player == gMarioObject) ? 0 : 1;
 | 
			
		||||
                o->heldByPlayerIndex = marioState->playerIndex;
 | 
			
		||||
            }
 | 
			
		||||
            o->oFaceAngleYaw += 0x1000;
 | 
			
		||||
            cur_obj_move_standard(-20);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1188,10 +1188,12 @@ u32 interact_door(struct MarioState *m, UNUSED u32 interactType, struct Object *
 | 
			
		|||
 | 
			
		||||
u32 interact_cannon_base(struct MarioState *m, UNUSED u32 interactType, struct Object *o) {
 | 
			
		||||
    if (o->oAction != 0) { return FALSE; }
 | 
			
		||||
    if (m->playerIndex != 0) { return FALSE; }
 | 
			
		||||
 | 
			
		||||
    if (m->action != ACT_IN_CANNON) {
 | 
			
		||||
        mario_stop_riding_and_holding(m);
 | 
			
		||||
        o->oInteractStatus = INT_STATUS_INTERACTED;
 | 
			
		||||
        o->oCannonPlayerIndex = 0;
 | 
			
		||||
        m->interactObj = o;
 | 
			
		||||
        m->usedObj = o;
 | 
			
		||||
        return set_mario_action(m, ACT_IN_CANNON, 0);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -117,7 +117,7 @@ static void debug_suicide(void) {
 | 
			
		|||
 | 
			
		||||
void debug_keyboard_on_key_down(int scancode) {
 | 
			
		||||
    scancode = scancode;
 | 
			
		||||
    switch (scancode) {
 | 
			
		||||
    switch (scancode & 0xFF) {
 | 
			
		||||
        case SCANCODE_3: debug_breakpoint_here(); break;
 | 
			
		||||
#ifdef DEVELOPMENT
 | 
			
		||||
        case SCANCODE_6: debug_warp_level(warpToLevel); break;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,7 +10,7 @@
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    static void debuglog_print_network_type(void) {
 | 
			
		||||
        printf(" [%s] ", NETWORKTYPESTR);
 | 
			
		||||
        printf(" [%02d] ", (gNetworkPlayerLocal != NULL) ? gNetworkPlayerLocal->globalIndex : -1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static void debuglog_print_log_type(char* logType) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -49,7 +49,7 @@ struct SyncObject {
 | 
			
		|||
    clock_t clockSinceUpdate;
 | 
			
		||||
    void* behavior;
 | 
			
		||||
    u16 txEventId;
 | 
			
		||||
    u16 rxEventId;
 | 
			
		||||
    u16 rxEventId[MAX_PLAYERS];
 | 
			
		||||
    u16 randomSeed;
 | 
			
		||||
    u8 extraFieldCount;
 | 
			
		||||
    bool fullObjectSync;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -103,6 +103,7 @@ u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex) {
 | 
			
		|||
        np->type = type;
 | 
			
		||||
        np->lastReceived = clock();
 | 
			
		||||
        gNetworkSystem->save_id(i);
 | 
			
		||||
        for (int j = 0; j < MAX_SYNC_OBJECTS; j++) { gSyncObjects[j].rxEventId[i] = 0; }
 | 
			
		||||
        if (type == NPT_SERVER) { gNetworkPlayerServer = np; }
 | 
			
		||||
        else { chat_add_message("player connected", CMT_SYSTEM); }
 | 
			
		||||
        LOG_INFO("player connected, local %d, global %d", i, np->globalIndex);
 | 
			
		||||
| 
						 | 
				
			
			@ -139,6 +140,7 @@ u8 network_player_disconnected(u8 globalIndex) {
 | 
			
		|||
        if (gNetworkType == NT_SERVER) { network_send_leaving(np->globalIndex); }
 | 
			
		||||
        np->connected = false;
 | 
			
		||||
        gNetworkSystem->clear_id(i);
 | 
			
		||||
        for (int j = 0; j < MAX_SYNC_OBJECTS; j++) { gSyncObjects[j].rxEventId[i] = 0; }
 | 
			
		||||
        LOG_INFO("player disconnected, local %d, global %d", i, globalIndex);
 | 
			
		||||
        chat_add_message("player disconnected", CMT_SYSTEM);
 | 
			
		||||
        return i;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -48,7 +48,7 @@ void network_send_collect_coin(struct Object* o) {
 | 
			
		|||
 | 
			
		||||
    struct Packet p;
 | 
			
		||||
    packet_init(&p, PACKET_COLLECT_COIN, true, true);
 | 
			
		||||
    packet_write(&p, &behaviorId, sizeof(enum BehaviorId));
 | 
			
		||||
    packet_write(&p, &behaviorId, sizeof(u16));
 | 
			
		||||
    packet_write(&p, &o->oPosX, sizeof(f32) * 3);
 | 
			
		||||
    packet_write(&p, &gMarioStates[0].numCoins, sizeof(s16));
 | 
			
		||||
    packet_write(&p, &o->oDamageOrCoinValue, sizeof(s32));
 | 
			
		||||
| 
						 | 
				
			
			@ -62,7 +62,7 @@ void network_receive_collect_coin(struct Packet* p) {
 | 
			
		|||
    s16 numCoins = 0;
 | 
			
		||||
    s32 coinValue = 0;
 | 
			
		||||
 | 
			
		||||
    packet_read(p, &behaviorId, sizeof(enum BehaviorId));
 | 
			
		||||
    packet_read(p, &behaviorId, sizeof(u16));
 | 
			
		||||
    packet_read(p, &pos, sizeof(f32) * 3);
 | 
			
		||||
    packet_read(p, &numCoins, sizeof(s16));
 | 
			
		||||
    packet_read(p, &coinValue, sizeof(s32));
 | 
			
		||||
| 
						 | 
				
			
			@ -88,7 +88,7 @@ void network_receive_collect_coin(struct Packet* p) {
 | 
			
		|||
    if (COURSE_IS_MAIN_COURSE(gCurrCourseNum)
 | 
			
		||||
        && gMarioStates[0].numCoins - coin->oDamageOrCoinValue < 100
 | 
			
		||||
        && gMarioStates[0].numCoins >= 100) {
 | 
			
		||||
        bhv_spawn_star_no_level_exit(gMarioStates[1].marioObj, 6, FALSE);
 | 
			
		||||
        bhv_spawn_star_no_level_exit(gMarioStates[p->localIndex].marioObj, 6, FALSE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return;
 | 
			
		||||
| 
						 | 
				
			
			@ -102,6 +102,6 @@ SANITY_CHECK_COINS:;
 | 
			
		|||
    if (COURSE_IS_MAIN_COURSE(gCurrCourseNum)
 | 
			
		||||
        && oldCoinCount < 100
 | 
			
		||||
        && gMarioStates[0].numCoins >= 100) {
 | 
			
		||||
        bhv_spawn_star_no_level_exit(gMarioStates[1].marioObj, 6, FALSE);
 | 
			
		||||
        bhv_spawn_star_no_level_exit(gMarioStates[p->localIndex].marioObj, 6, FALSE);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -45,7 +45,7 @@ void network_send_collect_item(struct Object* o) {
 | 
			
		|||
 | 
			
		||||
    struct Packet p;
 | 
			
		||||
    packet_init(&p, PACKET_COLLECT_ITEM, true, true);
 | 
			
		||||
    packet_write(&p, &behaviorId, sizeof(enum BehaviorId));
 | 
			
		||||
    packet_write(&p, &behaviorId, sizeof(u16));
 | 
			
		||||
    packet_write(&p, &o->oPosX, sizeof(f32) * 3);
 | 
			
		||||
 | 
			
		||||
    network_send(&p);
 | 
			
		||||
| 
						 | 
				
			
			@ -55,7 +55,7 @@ void network_receive_collect_item(struct Packet* p) {
 | 
			
		|||
    enum BehaviorId behaviorId;
 | 
			
		||||
    f32 pos[3] = { 0 };
 | 
			
		||||
 | 
			
		||||
    packet_read(p, &behaviorId, sizeof(enum BehaviorId));
 | 
			
		||||
    packet_read(p, &behaviorId, sizeof(u16));
 | 
			
		||||
    packet_read(p, &pos, sizeof(f32) * 3);
 | 
			
		||||
 | 
			
		||||
    const void* behavior = get_behavior_from_id(behaviorId);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -52,7 +52,7 @@ void network_send_collect_star(struct Object* o, s16 coinScore, s16 starIndex) {
 | 
			
		|||
    packet_write(&p, &gCurrSaveFileNum, sizeof(s16));
 | 
			
		||||
    packet_write(&p, &gCurrCourseNum, sizeof(s16));
 | 
			
		||||
    packet_write(&p, &o->oPosX, sizeof(f32) * 3);
 | 
			
		||||
    packet_write(&p, &behaviorId, sizeof(enum BehaviorId));
 | 
			
		||||
    packet_write(&p, &behaviorId, sizeof(u16));
 | 
			
		||||
    packet_write(&p, &coinScore, sizeof(s16));
 | 
			
		||||
    packet_write(&p, &starIndex, sizeof(s16));
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -69,7 +69,7 @@ void network_receive_collect_star(struct Packet* p) {
 | 
			
		|||
    packet_read(p, &gCurrSaveFileNum, sizeof(s16));
 | 
			
		||||
    packet_read(p, &gCurrCourseNum, sizeof(s16));
 | 
			
		||||
    packet_read(p, &pos, sizeof(f32) * 3);
 | 
			
		||||
    packet_read(p, &behaviorId, sizeof(enum BehaviorId));
 | 
			
		||||
    packet_read(p, &behaviorId, sizeof(u16));
 | 
			
		||||
    packet_read(p, &coinScore, sizeof(s16));
 | 
			
		||||
    packet_read(p, &starIndex, sizeof(s16));
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,7 +6,7 @@
 | 
			
		|||
void network_send_kick(enum KickReasonType kickReason) {
 | 
			
		||||
    struct Packet p;
 | 
			
		||||
    packet_init(&p, PACKET_KICK, false, false);
 | 
			
		||||
    packet_write(&p, &kickReason, sizeof(enum KickReasonType));
 | 
			
		||||
    packet_write(&p, &kickReason, sizeof(u8));
 | 
			
		||||
    network_send_to(0, &p);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -22,7 +22,7 @@ void network_receive_kick(struct Packet* p) {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    enum KickReasonType kickReason;
 | 
			
		||||
    packet_read(p, &kickReason, sizeof(enum KickReasonType));
 | 
			
		||||
    packet_read(p, &kickReason, sizeof(u8));
 | 
			
		||||
    switch (kickReason) {
 | 
			
		||||
        case EKT_FULL_PARTY: custom_menu_error("The party is full.");              break;
 | 
			
		||||
        default:             custom_menu_error("Host has closed the connection."); break;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,6 +8,7 @@
 | 
			
		|||
#include "src/game/memory.h"
 | 
			
		||||
#include "src/game/object_helpers.h"
 | 
			
		||||
#include "src/game/obj_behaviors.h"
 | 
			
		||||
#include "pc/debuglog.h"
 | 
			
		||||
 | 
			
		||||
static u8 nextSyncID = 1;
 | 
			
		||||
struct SyncObject gSyncObjects[MAX_SYNC_OBJECTS] = { 0 };
 | 
			
		||||
| 
						 | 
				
			
			@ -42,7 +43,10 @@ static bool should_own_object(struct SyncObject* so) {
 | 
			
		|||
        if (gMarioStates[i].heldByObj == so->o) { return false; }
 | 
			
		||||
    }
 | 
			
		||||
    if (so->o->oHeldState == HELD_HELD && so->o->heldByPlayerIndex == 0) { return true; }
 | 
			
		||||
    if (player_distance(&gMarioStates[0], so->o) > player_distance(&gMarioStates[1], so->o)) { return false; }
 | 
			
		||||
    for (int i = 0; i < MAX_PLAYERS; i++) {
 | 
			
		||||
        if (!is_player_active(&gMarioStates[i])) { continue; }
 | 
			
		||||
        if (player_distance(&gMarioStates[0], so->o) > player_distance(&gMarioStates[i], so->o)) { return false; }
 | 
			
		||||
    }
 | 
			
		||||
    if (so->o->oHeldState == HELD_HELD && so->o->heldByPlayerIndex != 0) { return false; }
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -60,7 +64,9 @@ struct SyncObject* network_init_object(struct Object *o, float maxSyncDistance)
 | 
			
		|||
    so->clockSinceUpdate = clock();
 | 
			
		||||
    so->extraFieldCount = 0;
 | 
			
		||||
    so->behavior = (BehaviorScript*)o->behavior;
 | 
			
		||||
    so->rxEventId = 0;
 | 
			
		||||
    for (int i = 0; i < MAX_PLAYERS; i++) {
 | 
			
		||||
        so->rxEventId[i] = 0;
 | 
			
		||||
    }
 | 
			
		||||
    so->txEventId = 0;
 | 
			
		||||
    so->fullObjectSync = false;
 | 
			
		||||
    so->hasStandardFields = (maxSyncDistance >= 0);
 | 
			
		||||
| 
						 | 
				
			
			@ -141,10 +147,11 @@ static void packet_write_object_header(struct Packet* p, struct Object* o) {
 | 
			
		|||
    struct SyncObject* so = &gSyncObjects[o->oSyncID];
 | 
			
		||||
    enum BehaviorId behaviorId = get_id_from_behavior(o->behavior);
 | 
			
		||||
 | 
			
		||||
    packet_write(p, &gNetworkPlayerLocal->globalIndex, sizeof(u8));
 | 
			
		||||
    packet_write(p, &o->oSyncID, sizeof(u32));
 | 
			
		||||
    packet_write(p, &so->txEventId, sizeof(u16));
 | 
			
		||||
    packet_write(p, &so->randomSeed, sizeof(u16));
 | 
			
		||||
    packet_write(p, &behaviorId, sizeof(enum BehaviorId));
 | 
			
		||||
    packet_write(p, &behaviorId, sizeof(u16));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool allowable_behavior_change(struct SyncObject* so, BehaviorScript* behavior) {
 | 
			
		||||
| 
						 | 
				
			
			@ -162,19 +169,25 @@ static bool allowable_behavior_change(struct SyncObject* so, BehaviorScript* beh
 | 
			
		|||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct SyncObject* packet_read_object_header(struct Packet* p) {
 | 
			
		||||
static struct SyncObject* packet_read_object_header(struct Packet* p, u8* fromLocalIndex) {
 | 
			
		||||
    // figure out where the packet came from
 | 
			
		||||
    u8 fromGlobalIndex = 0;
 | 
			
		||||
    packet_read(p, &fromGlobalIndex, sizeof(u8));
 | 
			
		||||
    struct NetworkPlayer* np = network_player_from_global_index(fromGlobalIndex);
 | 
			
		||||
    *fromLocalIndex = (np != NULL) ? np->localIndex : p->localIndex;
 | 
			
		||||
 | 
			
		||||
    // get sync ID, sanity check
 | 
			
		||||
    u32 syncId = 0;
 | 
			
		||||
    packet_read(p, &syncId, sizeof(u32));
 | 
			
		||||
    if (syncId == 0 || syncId >= MAX_SYNC_OBJECTS) {
 | 
			
		||||
        printf("%s invalid SyncID %d!\n", NETWORKTYPESTR, syncId);
 | 
			
		||||
        LOG_ERROR("invalid SyncID: %d", syncId);
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // extract object, sanity check
 | 
			
		||||
    struct Object* o = gSyncObjects[syncId].o;
 | 
			
		||||
    if (o == NULL) {
 | 
			
		||||
        printf("%s invalid SyncObject!\n", NETWORKTYPESTR);
 | 
			
		||||
        LOG_ERROR("invalid SyncObject for %d", syncId);
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -193,20 +206,23 @@ static struct SyncObject* packet_read_object_header(struct Packet* p) {
 | 
			
		|||
    // make sure this is the newest event possible
 | 
			
		||||
    u16 eventId = 0;
 | 
			
		||||
    packet_read(p, &eventId, sizeof(u16));
 | 
			
		||||
    if (so->rxEventId > eventId && (u16)abs(eventId - so->rxEventId) < USHRT_MAX / 2) {
 | 
			
		||||
    if (so->rxEventId[*fromLocalIndex] > eventId && (u16)abs(eventId - so->rxEventId[*fromLocalIndex]) < USHRT_MAX / 2) {
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    so->rxEventId = eventId;
 | 
			
		||||
    so->rxEventId[*fromLocalIndex] = eventId;
 | 
			
		||||
 | 
			
		||||
    // update the random seed
 | 
			
		||||
    packet_read(p, &so->randomSeed, sizeof(u16));
 | 
			
		||||
 | 
			
		||||
    // make sure the behaviors match
 | 
			
		||||
    enum BehaviorId behaviorId;
 | 
			
		||||
    packet_read(p, &behaviorId, sizeof(enum BehaviorId));
 | 
			
		||||
    packet_read(p, &behaviorId, sizeof(u16));
 | 
			
		||||
    BehaviorScript* behavior = (BehaviorScript*)get_behavior_from_id(behaviorId);
 | 
			
		||||
    if (o->behavior != behavior && !allowable_behavior_change(so, behavior)) {
 | 
			
		||||
        printf("network_receive_object() behavior mismatch!\n");
 | 
			
		||||
    if (behavior == NULL) {
 | 
			
		||||
        LOG_ERROR("unable to find behavior %04X for id %d", behaviorId, syncId);
 | 
			
		||||
        return NULL;
 | 
			
		||||
    } if (o->behavior != behavior && !allowable_behavior_change(so, behavior)) {
 | 
			
		||||
        LOG_ERROR("behavior mismatch for %d: %04X vs %04X", syncId, get_id_from_behavior(o->behavior), get_id_from_behavior(behavior));
 | 
			
		||||
        network_forget_sync_object(so);
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -337,13 +353,13 @@ void network_send_object(struct Object* o) {
 | 
			
		|||
    if (!network_sync_object_initialized(o)) { return; }
 | 
			
		||||
    struct SyncObject* so = &gSyncObjects[o->oSyncID];
 | 
			
		||||
    if (so == NULL) { return; }
 | 
			
		||||
    if (o->behavior != so->behavior && !allowable_behavior_change(so, so->behavior)) {
 | 
			
		||||
        printf("network_send_object() BEHAVIOR MISMATCH!\n");
 | 
			
		||||
    if (o != so->o) {
 | 
			
		||||
        LOG_ERROR("object mismatch for %d", o->oSyncID);
 | 
			
		||||
        network_forget_sync_object(so);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    if (o != so->o) {
 | 
			
		||||
        printf("network_send_object() OBJECT MISMATCH!\n");
 | 
			
		||||
    if (o->behavior != so->behavior && !allowable_behavior_change(so, so->behavior)) {
 | 
			
		||||
        LOG_ERROR("behavior mismatch for %d: %04X vs %04X", o->oSyncID, get_id_from_behavior(o->behavior), get_id_from_behavior(so->behavior));
 | 
			
		||||
        network_forget_sync_object(so);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -357,14 +373,13 @@ void network_send_object_reliability(struct Object* o, bool reliable) {
 | 
			
		|||
    if (!network_sync_object_initialized(o)) { return; }
 | 
			
		||||
    struct SyncObject* so = &gSyncObjects[o->oSyncID];
 | 
			
		||||
    if (so == NULL) { return; }
 | 
			
		||||
 | 
			
		||||
    if (o->behavior != so->behavior && !allowable_behavior_change(so, so->behavior)) {
 | 
			
		||||
        printf("network_send_object() BEHAVIOR MISMATCH!\n");
 | 
			
		||||
    if (o != so->o) {
 | 
			
		||||
        LOG_ERROR("object mismatch for %d", o->oSyncID);
 | 
			
		||||
        network_forget_sync_object(so);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    if (o != so->o) {
 | 
			
		||||
        printf("network_send_object() OBJECT MISMATCH!\n");
 | 
			
		||||
    if (o->behavior != so->behavior && !allowable_behavior_change(so, so->behavior)) {
 | 
			
		||||
        LOG_ERROR("behavior mismatch for %d: %04X vs %04X", o->oSyncID, get_id_from_behavior(o->behavior), get_id_from_behavior(so->behavior));
 | 
			
		||||
        network_forget_sync_object(so);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -393,7 +408,8 @@ void network_send_object_reliability(struct Object* o, bool reliable) {
 | 
			
		|||
 | 
			
		||||
void network_receive_object(struct Packet* p) {
 | 
			
		||||
    // read the header and sanity check the packet
 | 
			
		||||
    struct SyncObject* so = packet_read_object_header(p);
 | 
			
		||||
    u8 fromLocalIndex = 0;
 | 
			
		||||
    struct SyncObject* so = packet_read_object_header(p, &fromLocalIndex);
 | 
			
		||||
    if (so == NULL) { return; }
 | 
			
		||||
    struct Object* o = so->o;
 | 
			
		||||
    if (!network_sync_object_initialized(o)) { return; }
 | 
			
		||||
| 
						 | 
				
			
			@ -412,7 +428,7 @@ void network_receive_object(struct Packet* p) {
 | 
			
		|||
        extern struct Object* gCurrentObject;
 | 
			
		||||
        struct Object* tmp = gCurrentObject;
 | 
			
		||||
        gCurrentObject = so->o;
 | 
			
		||||
        (*so->on_received_pre)(p->localIndex);
 | 
			
		||||
        (*so->on_received_pre)(fromLocalIndex);
 | 
			
		||||
        gCurrentObject = tmp;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -432,7 +448,7 @@ void network_receive_object(struct Packet* p) {
 | 
			
		|||
        extern struct Object* gCurrentObject;
 | 
			
		||||
        struct Object* tmp = gCurrentObject;
 | 
			
		||||
        gCurrentObject = so->o;
 | 
			
		||||
        (*so->on_received_post)(p->localIndex);
 | 
			
		||||
        (*so->on_received_post)(fromLocalIndex);
 | 
			
		||||
        gCurrentObject = tmp;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -464,7 +480,7 @@ void network_update_objects(void) {
 | 
			
		|||
 | 
			
		||||
        // check for stale sync object
 | 
			
		||||
        if (so->o->oSyncID != i) {
 | 
			
		||||
            printf("ERROR! Sync ID mismatch!\n");
 | 
			
		||||
            LOG_ERROR("sync id mismatch: %d vs %d", so->o->oSyncID, i);
 | 
			
		||||
            network_forget_sync_object(so);
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -57,7 +57,7 @@ void network_send_spawn_objects(struct Object* objects[], u32 models[], u8 objec
 | 
			
		|||
        enum BehaviorId behaviorId = get_id_from_behavior(o->behavior);
 | 
			
		||||
        packet_write(&p, &parentId, sizeof(u8));
 | 
			
		||||
        packet_write(&p, &model, sizeof(u32));
 | 
			
		||||
        packet_write(&p, &behaviorId, sizeof(enum BehaviorId));
 | 
			
		||||
        packet_write(&p, &behaviorId, sizeof(u16));
 | 
			
		||||
        packet_write(&p, &o->activeFlags, sizeof(s16));
 | 
			
		||||
        packet_write(&p, o->rawData.asU32, sizeof(s32) * 80);
 | 
			
		||||
        packet_write(&p, &o->header.gfx.scale[0], sizeof(f32));
 | 
			
		||||
| 
						 | 
				
			
			@ -99,7 +99,7 @@ void network_receive_spawn_objects(struct Packet* p) {
 | 
			
		|||
        Vec3f scale = { 0 };
 | 
			
		||||
        packet_read(p, &data.parentId, sizeof(u8));
 | 
			
		||||
        packet_read(p, &data.model, sizeof(u32));
 | 
			
		||||
        packet_read(p, &data.behaviorId, sizeof(enum BehaviorId));
 | 
			
		||||
        packet_read(p, &data.behaviorId, sizeof(u16));
 | 
			
		||||
        packet_read(p, &data.activeFlags, sizeof(s16));
 | 
			
		||||
        packet_read(p, &data.rawData, sizeof(s32) * 80);
 | 
			
		||||
        packet_read(p, &scale[0], sizeof(f32));
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue