sm64coopdx/src/pc/network/packets/packet_player.c

342 lines
12 KiB
C

#include <stdio.h>
#include "../network.h"
#include "object_fields.h"
#include "object_constants.h"
#include "sm64.h"
#include "game/interaction.h"
#include "game/mario.h"
#include "game/area.h"
#include "audio/external.h"
#include "engine/surface_collision.h"
#include "game/object_list_processor.h"
#include "game/chat.h"
#pragma pack(1)
struct PacketPlayerData {
u32 rawData[80];
s16 cRawStickX;
s16 cRawStickY;
f32 cStickX;
f32 cStickY;
f32 cStickMag;
u16 cButtonDown;
u16 cButtonPressed;
s16 cExtStickX;
s16 cExtStickY;
s16 nodeFlags;
u16 input;
u32 flags;
u32 particleFlags;
u32 action;
u32 prevAction;
u16 actionState;
u16 actionTimer;
u32 actionArg;
f32 intendedMag;
s16 intendedYaw;
s16 invincTimer;
u8 framesSinceA;
u8 framesSinceB;
u8 wallKickTimer;
u8 doubleJumpTimer;
Vec3s faceAngle;
Vec3s angleVel;
s16 slideYaw;
s16 twirlYaw;
Vec3f pos;
Vec3f vel;
f32 forwardVel;
f32 slideVelX;
f32 slideVelZ;
s16 health;
u8 squishTimer;
f32 peakHeight;
s16 currentRoom;
u8 customFlags;
u8 heldSyncID;
u8 heldBySyncID;
u8 interactSyncID;
u8 usedSyncID;
u8 platformSyncID;
s16 currLevelNum;
s16 currAreaIndex;
};
static void read_packet_data(struct PacketPlayerData* data, struct MarioState* m) {
u8 heldSyncID = (m->heldObj != NULL) ? m->heldObj->oSyncID : 0;
u8 heldBySyncID = (m->heldByObj != NULL) ? m->heldByObj->oSyncID : 0;
u8 interactSyncID = (m->interactObj != NULL) ? m->interactObj->oSyncID : 0;
u8 usedSyncID = (m->usedObj != NULL) ? m->usedObj->oSyncID : 0;
u8 platformSyncID = (m->marioObj->platform != NULL) ? m->marioObj->platform->oSyncID : 0;
u8 customFlags = SET_BIT((m->freeze > 0), 0);
memcpy(data->rawData, m->marioObj->rawData.asU32, sizeof(u32) * 80);
data->nodeFlags = m->marioObj->header.gfx.node.flags;
data->cRawStickX = m->controller->rawStickX;
data->cRawStickY = m->controller->rawStickY;
data->cStickX = m->controller->stickX;
data->cStickY = m->controller->stickY;
data->cStickMag = m->controller->stickMag;
data->cButtonDown = m->controller->buttonDown;
data->cButtonPressed = m->controller->buttonPressed;
data->cExtStickX = m->controller->extStickX;
data->cExtStickY = m->controller->extStickY;
data->input = m->input;
data->flags = m->flags;
data->particleFlags = m->particleFlags;
data->action = m->action;
data->prevAction = m->prevAction;
data->actionState = m->actionState;
data->actionTimer = m->actionTimer;
data->actionArg = m->actionArg;
data->intendedMag = m->intendedMag;
data->intendedYaw = m->intendedYaw;
data->invincTimer = m->invincTimer;
data->framesSinceA = m->framesSinceA;
data->framesSinceB = m->framesSinceB;
data->wallKickTimer = m->wallKickTimer;
data->doubleJumpTimer = m->doubleJumpTimer;
memcpy(data->faceAngle, m->faceAngle, sizeof(s16) * 3);
memcpy(data->angleVel, m->angleVel, sizeof(s16) * 3);
data->slideYaw = m->slideYaw;
data->twirlYaw = m->twirlYaw;
memcpy(data->pos, m->pos, sizeof(f32) * 3);
memcpy(data->vel, m->vel, sizeof(f32) * 3);
data->forwardVel = m->forwardVel;
data->slideVelX = m->slideVelX;
data->slideVelZ = m->slideVelZ;
data->health = m->health;
data->squishTimer = m->squishTimer;
data->peakHeight = m->peakHeight;
data->currentRoom = m->currentRoom;
data->customFlags = customFlags;
data->heldSyncID = heldSyncID;
data->heldBySyncID = heldBySyncID;
data->interactSyncID = interactSyncID;
data->usedSyncID = usedSyncID;
data->platformSyncID = platformSyncID;
data->currLevelNum = gCurrLevelNum;
data->currAreaIndex = gCurrAreaIndex;
}
static void write_packet_data(struct PacketPlayerData* data, struct MarioState* m,
u8* customFlags, u8* heldSyncID, u8* heldBySyncID,
u8* interactSyncID, u8* usedSyncID, u8* platformSyncID) {
memcpy(m->marioObj->rawData.asU32, data->rawData, sizeof(u32) * 80);
m->marioObj->header.gfx.node.flags = data->nodeFlags;
m->controller->rawStickX = data->cRawStickX;
m->controller->rawStickY = data->cRawStickY;
m->controller->stickX = data->cStickX;
m->controller->stickY = data->cStickY;
m->controller->stickMag = data->cStickMag;
m->controller->buttonDown = data->cButtonDown;
m->controller->buttonPressed = data->cButtonPressed;
m->controller->extStickX = data->cExtStickX;
m->controller->extStickY = data->cExtStickY;
m->input = data->input;
m->flags = data->flags;
m->particleFlags = data->particleFlags;
m->action = data->action;
m->prevAction = data->prevAction;
m->actionState = data->actionState;
m->actionTimer = data->actionTimer;
m->actionArg = data->actionArg;
m->intendedMag = data->intendedMag;
m->intendedYaw = data->intendedYaw;
m->invincTimer = data->invincTimer;
m->framesSinceA = data->framesSinceA;
m->framesSinceB = data->framesSinceB;
m->wallKickTimer = data->wallKickTimer;
m->doubleJumpTimer = data->doubleJumpTimer;
memcpy(m->faceAngle, data->faceAngle, sizeof(s16) * 3);
memcpy(m->angleVel, data->angleVel, sizeof(s16) * 3);
m->slideYaw = data->slideYaw;
m->twirlYaw = data->twirlYaw;
memcpy(m->pos, data->pos, sizeof(f32) * 3);
memcpy(m->vel, data->vel, sizeof(f32) * 3);
m->forwardVel = data->forwardVel;
m->slideVelX = data->slideVelX;
m->slideVelZ = data->slideVelZ;
m->health = data->health;
m->squishTimer = data->squishTimer;
m->peakHeight = data->peakHeight;
m->currentRoom = data->currentRoom;
*customFlags = data->customFlags;
*heldSyncID = data->heldSyncID;
*heldBySyncID = data->heldBySyncID;
*interactSyncID = data->interactSyncID;
*usedSyncID = data->usedSyncID;
*platformSyncID = data->platformSyncID;
}
void network_send_player(u8 localIndex) {
if (gMarioStates[localIndex].marioObj == NULL) { return; }
struct PacketPlayerData data = { 0 };
read_packet_data(&data, &gMarioStates[localIndex]);
struct Packet p;
packet_init(&p, PACKET_PLAYER, false, false);
packet_write(&p, &gNetworkPlayers[localIndex].globalIndex, sizeof(u8));
packet_write(&p, &data, sizeof(struct PacketPlayerData));
// two-player hack: should be network_send_to_all_except()
network_send(&p);
}
void network_receive_player(struct Packet* p) {
u8 globalIndex = 0;
packet_read(p, &globalIndex, sizeof(u8));
struct NetworkPlayer* np = network_player_from_global_index(globalIndex);
if (np == NULL || np->localIndex == UNKNOWN_LOCAL_INDEX || !np->connected) { return; }
struct MarioState* m = &gMarioStates[np->localIndex];
if (m == NULL || m->marioObj == NULL) { return; }
// save previous state
struct PacketPlayerData oldData = { 0 };
read_packet_data(&oldData, m);
u16 playerIndex = np->localIndex;
u32 oldBehParams = m->marioObj->oBehParams;
// load mario information from packet
struct PacketPlayerData data = { 0 };
packet_read(p, &data, sizeof(struct PacketPlayerData));
// check to see if we should just drop this packet
if (oldData.action == ACT_JUMBO_STAR_CUTSCENE && data.action == ACT_JUMBO_STAR_CUTSCENE) {
return;
}
// check player level/area
u8 levelAreaMismatch = TRUE;
np->currLevelNum = data.currLevelNum;
np->currAreaIndex = data.currAreaIndex;
levelAreaMismatch = (data.currLevelNum != gCurrLevelNum || data.currAreaIndex != gCurrAreaIndex);
if (levelAreaMismatch) { np->fadeOpacity = 0; return; }
// apply data from packet to mario state
u8 heldSyncID = 0;
u8 heldBySyncID = 0;
u8 interactSyncID = 0;
u8 usedSyncID = 0;
u8 platformSyncID = 0;
u8 customFlags = 0;
write_packet_data(&data, m, &customFlags,
&heldSyncID, &heldBySyncID,
&interactSyncID, &usedSyncID,
&platformSyncID);
// read custom flags
m->freeze = GET_BIT(customFlags, 0);
// reset player index
m->playerIndex = playerIndex;
m->marioObj->oBehParams = oldBehParams;
// reset mario sound play flag so that their jump sounds work
if (m->action != oldData.action) {
m->flags &= ~(MARIO_ACTION_SOUND_PLAYED | MARIO_MARIO_SOUND_PLAYED);
}
// find and set their held object
if (heldSyncID != 0 && gSyncObjects[heldSyncID].o != NULL) {
// TODO: do we have to move graphics nodes around to make this visible?
struct Object* heldObj = gSyncObjects[heldSyncID].o;
if (gMarioStates[0].heldObj == heldObj && gNetworkType == NT_CLIENT) { // two-player hack: needs priority
mario_drop_held_object(&gMarioStates[0]);
force_idle_state(&gMarioStates[0]);
}
m->heldObj = heldObj;
heldObj->oHeldState = HELD_HELD;
heldObj->heldByPlayerIndex = 1;
} else {
m->heldObj = NULL;
}
// find and set their held-by object
if (heldBySyncID != 0 && gSyncObjects[heldBySyncID].o != NULL) {
// TODO: do we have to move graphics nodes around to make this visible?
m->heldByObj = gSyncObjects[heldBySyncID].o;
} else {
m->heldByObj = NULL;
}
// find and set their interact object
if (interactSyncID != 0 && gSyncObjects[interactSyncID].o != NULL) {
m->interactObj = gSyncObjects[interactSyncID].o;
}
// find and set their used object
if (usedSyncID != 0 && gSyncObjects[usedSyncID].o != NULL) {
m->usedObj = gSyncObjects[usedSyncID].o;
}
// place on top of platform
if (platformSyncID != 0 && gSyncObjects[platformSyncID].o != NULL) {
struct Surface* floor = NULL;
// search up to 500 units for the platform
f32 maxDifference = 500;
m->pos[1] += maxDifference;
// find the platform
gCheckingSurfaceCollisionsForObject = gSyncObjects[platformSyncID].o;
f32 height = find_floor(m->pos[0], m->pos[1], m->pos[2], &floor);
gCheckingSurfaceCollisionsForObject = NULL;
f32 difference = ABS((m->pos[1] - maxDifference) - height);
if (floor != NULL && difference <= maxDifference) {
// place on top of platform
m->pos[1] = height;
} else {
// search failed, reset position
m->pos[1] -= maxDifference;
}
}
// jump kicking: restore action state, otherwise it won't play
if (m->action == ACT_JUMP_KICK) {
m->actionState = oldData.actionState;
}
// punching:
if ((m->action == ACT_PUNCHING || m->action == ACT_MOVE_PUNCHING)) {
// play first punching sound, otherwise it will be missed
if (m->action != oldData.action) {
play_sound(SOUND_MARIO_PUNCH_YAH, m->marioObj->header.gfx.cameraToObject);
}
// make the first punch large, otherwise it will be missed
if (m->actionArg == 2 && oldData.actionArg == 1) {
m->marioBodyState->punchState = (0 << 6) | 4;
}
}
// inform of player death
if (oldData.action != ACT_BUBBLED && data.action == ACT_BUBBLED) {
chat_add_message("player died", CMT_SYSTEM);
}
// action changed, reset timer
if (m->action != oldData.action) {
m->actionTimer = 0;
}
// set model
m->marioObj->header.gfx.sharedChild = gLoadedGraphNodes[(np->globalIndex == 1) ? MODEL_LUIGI : MODEL_MARIO];
}
void network_update_player(void) {
network_send_player(0);
}