Co-op ripples (#118)

* First attempt

First attempt at having other Mario objects create ripples.

Works very inconsistently, the position of players not currently interacting with the painting seems to influence whether the ripples will work or not

* Moved nearest mario code from geo_painting_update

Instead of using the nearest mario object for geo_painting_update, I use it in painting.c functions that called for gPaintingMarioXYZPos, substituting the nearest Mario object's position instead, as well as using it for the last floor mario was over.

This method still isn't quite perfect and there's a few more things I'd like to fix/change.
1. If a Mario is closer to the painting (perhaps right against the middle) other Mario's can't trigger ripplings at all unless they get closer than the closest Mario
2. I would like for all Entry and Exit ripples to interrupt each other, meaning if multiple Marios jump in, each one triggers a ripple one after the other
3. I want to hear the other player's exit sounds

* Add currPositionValid

Sets currPositionValid to false for NetworkPlayers who are connected, who changed levels to a level different from the local player, and who are not the local player when the local player changes levels.

* Set currPositionValid

Sets currPositionValid to false for update packets that don't match local area.
Sets it to true for update packets that do match local area.

* Send change area/level immediately

Adds a function network_on_loaded_area2() which only sends a change level or area event and doesn't clear the sync ids.
Calls this function almost immediately as opposed to waiting for LOADING_LEVEL_THRESHOLD frames

* Add currPositionValid to NetworkPlayer

currPositionValid (which is used by painting.c to determine if a player should be considered for the closest player to the painting) is a variable that tells you if a network player's marioObj has a position which can be relied upon as a valid position for that player.

network_player_update_course_level sets it to false for a network player if the new location does not match the local player's location.
network_receive_player sets it to false if a network player's update is from a different location than the local player, but sets it to TRUE if the update is from the same location.
update_course does NOT set it to true, because the location is not sure to be valid until we've received a location from the player with the right location attached to it.

* Use currValidPosition correctly

Uses currValidPosition correctly, also add debug text for seeing closest player to painting.

* fix merge

* Fix merge

* Verboser logging and invpos on enter

* Multi collision arrays

* Removed nearest code, added comments

* Added simultaneous ripples on one painting

* Added commented Gamepad from Background line

* Removed debug logging

* renamed secondary network_on_loaded function

* Added early multiple paintings rippling at once

* Added multiple paintings rippling simultaneously

Co-authored-by: djoslin0 <djoslin0@users.noreply.github.com>
This commit is contained in:
HunterHeard 2022-08-07 03:08:00 -05:00 committed by GitHub
parent f1c2715fe7
commit ad5e7402fc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 671 additions and 171 deletions

File diff suppressed because it is too large Load diff

View file

@ -32,6 +32,22 @@
/// Painting that has one texture used for an environment map effect
#define PAINTING_ENV_MAP 1
// calculate_ripple_at_point modes
/// Only one ripple
#define SINGLE_RIPPLE 0
/// The sum of the ripples
#define ADD_RIPPLES 1
/// The highest ripple
#define HIGHEST_RIPPLE 2
/// The ripple furthest from 0
#define GREATEST_RIPPLE 3
typedef struct {
float ob[3]; /* x, y, z */
signed char n[3]; /* normal */
} Vtx_Interp;
struct Painting
{
s16 id;
@ -115,6 +131,38 @@ struct Painting
/// Uniformly scales the painting to a multiple of PAINTING_SIZE.
/// By default a painting is 614.0 x 614.0
f32 size;
/// Index of MarioState who entered the painting this frame
s32 enteredMarioIndex;
/// Index of MarioState who went under the painting this frame
s32 underMarioIndex;
/// Painting floor and under state information for each Mario
s8 lastFloors[MAX_PLAYERS + 1];
s8 currFloors[MAX_PLAYERS + 1];
s8 floorEntereds[MAX_PLAYERS + 1];
s8 wasUnders[MAX_PLAYERS + 1];
s8 isUnders[MAX_PLAYERS + 1];
s8 wentUnders[MAX_PLAYERS + 1];
f32 rippleXs[MAX_PLAYERS + 1];
f32 rippleYs[MAX_PLAYERS + 1];
f32 rippleTimers[MAX_PLAYERS + 1];
f32 currRippleMags[MAX_PLAYERS + 1];
f32 rippleDecays[MAX_PLAYERS + 1];
f32 rippleRates[MAX_PLAYERS + 1];
f32 dispersionFactors[MAX_PLAYERS + 1];
struct PaintingMeshVertex *paintingMesh;
Vec3f *paintingTriNorms;
Vtx_Interp sVertexBuffers[2][2 * 264 * 3];
u8 sVerticesCurIndex;
u8 sVertexSwaps;
Vtx_Interp* sVerticesCur;
Vtx_Interp* sVerticesPrev;
u32 sVerticesPrevTimestamp;
Vtx *sVerticesPtr[2];
s32 sVerticesCount;
};
/**

View file

@ -170,6 +170,21 @@ void network_on_loaded_area(void) {
}
}
// Same as network_on_loaded_area, but does not call area_remove_sync_ids_clear()
void network_on_loaded_area_no_clear(void) {
struct NetworkPlayer* np = gNetworkPlayerLocal;
if (np != NULL) {
bool levelMatch = (np->currCourseNum == gCurrCourseNum
&& np->currActNum == gCurrActStarNum
&& np->currLevelNum == gCurrLevelNum);
if (np->currLevelSyncValid && levelMatch && np->currAreaIndex != gCurrAreaIndex) {
network_send_change_area();
} else {
network_send_change_level();
}
}
}
static void network_remember_debug_packet(u8 id, bool sent) {
if (id == PACKET_ACK) { return; }
if (id == PACKET_KEEP_ALIVE) { return; }
@ -402,6 +417,10 @@ void network_update(void) {
// check for level loaded event
if (networkLoadingLevel < LOADING_LEVEL_THRESHOLD) {
networkLoadingLevel++;
// Send area/level update without LOADING_LEVEL_THRESHOLD delay
if (networkLoadingLevel == 1) {
network_on_loaded_area_no_clear();
}
if (!gNetworkAreaLoaded && networkLoadingLevel >= LOADING_LEVEL_THRESHOLD) {
gNetworkAreaLoaded = true;
network_on_loaded_area();
@ -488,6 +507,7 @@ void network_shutdown(bool sendLeaving, bool exiting) {
gNetworkType = NT_NONE;
#ifdef DISCORD_SDK
network_set_system(NS_DISCORD);
#endif

View file

@ -1,5 +1,6 @@
#include <stdio.h>
#include "network_player.h"
#include "types.h"
#include "object_fields.h"
#include "game/mario_misc.h"
#include "reservation_area.h"
#include "pc/djui/djui.h"
@ -221,6 +222,7 @@ u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex, u8 mode
np->currLevelAreaSeqId = 0;
np->currLevelSyncValid = false;
np->currAreaSyncValid = false;
np->currPositionValid = false;
network_player_update_course_level(np, 0, 0, gLevelValues.entryLevel, 1);
// update visuals
@ -363,6 +365,15 @@ void network_player_update_course_level(struct NetworkPlayer* np, s16 courseNum,
np->currLevelNum = levelNum;
np->currAreaIndex = areaIndex;
// Whether the new np location differs from the local location
bool mismatchLocal = (np->currCourseNum != gCurrCourseNum)
|| (np->currActNum != gCurrActNum)
|| (np->currLevelNum != gCurrLevelNum)
|| (np->currAreaIndex != gCurrAreaIndex);
if (mismatchLocal) {
np->currPositionValid = false;
}
if (mismatch) {
if (np == gNetworkPlayerLocal) {
network_send_level_area_inform();
@ -371,6 +382,13 @@ void network_player_update_course_level(struct NetworkPlayer* np, s16 courseNum,
so->txEventId = 0;
}
// If this machine's player changed to a different location, then all of the other np locations are no longer valid
for (u32 i = 0; i < MAX_PLAYERS + 1; i++) {
struct NetworkPlayer* npi = &gNetworkPlayers[i];
if ((!npi->connected) || npi == gNetworkPlayerLocal) { continue; }
npi->currPositionValid = false;
}
} else {
for (struct SyncObject* so = sync_object_get_first(); so != NULL; so = sync_object_get_next()) {
so->rxEventId[np->localIndex] = 0;

View file

@ -32,6 +32,7 @@ struct NetworkPlayer {
s16 currAreaIndex;
bool currLevelSyncValid;
bool currAreaSyncValid;
bool currPositionValid;
u8 fadeOpacity;
u8 onRxSeqId;
u8 modelIndex;

View file

@ -222,7 +222,7 @@ void network_receive_player(struct Packet* p) {
|| np->currActNum != gNetworkPlayerLocal->currActNum
|| np->currLevelNum != gNetworkPlayerLocal->currLevelNum
|| np->currAreaIndex != gNetworkPlayerLocal->currAreaIndex);
if (levelAreaMismatch) { return; }
if (levelAreaMismatch) { np->currPositionValid = false; return; }
// save previous state
struct PacketPlayerData oldData = { 0 };
@ -370,6 +370,9 @@ void network_receive_player(struct Packet* p) {
vec3s_copy(m->marioObj->header.gfx.angle, m->faceAngle);
}
// Player's position is valid since it's updated and in the same area as the local player
np->currPositionValid = true;
#ifndef DEVELOPMENT
if (gNetworkType == NT_SERVER && gServerSettings.enableCheats == 0) {
if (m->action == ACT_DEBUG_FREE_MOVE) {