diff --git a/include/object_fields.h b/include/object_fields.h index 9e9998bf..23fd63b3 100644 --- a/include/object_fields.h +++ b/include/object_fields.h @@ -556,6 +556,7 @@ #define /*0x104*/ oGoombaBlinkTimer OBJECT_FIELD_S32(0x1F) #define /*0x108*/ oGoombaTurningAwayFromWall OBJECT_FIELD_S32(0x20) #define /*0x10C*/ oGoombaRelativeSpeed OBJECT_FIELD_F32(0x21) +#define /*0x110*/ oGoombaJumpCooldown OBJECT_FIELD_U32(0x22) /* Haunted Chair */ #define /*0x0F4*/ oHauntedChairUnkF4 OBJECT_FIELD_S32(0x1B) diff --git a/levels/castle_grounds/script.c b/levels/castle_grounds/script.c index 684aec35..fff563bd 100644 --- a/levels/castle_grounds/script.c +++ b/levels/castle_grounds/script.c @@ -90,9 +90,9 @@ static const LevelScript script_func_local_4[] = { OBJECT(/*model*/ MODEL_BUTTERFLY, /*pos*/ -1204, 326, 3296, /*angle*/ 0, 0, 0, /*behParam*/ 0x00000000, /*beh*/ bhvButterfly), OBJECT(/*model*/ MODEL_YOSHI, /*pos*/ 0, 3174, -5625, /*angle*/ 0, 0, 0, /*behParam*/ 0x00000000, /*beh*/ bhvYoshi), // TESTING BELOW - OBJECT(/*model*/ MODEL_BLACK_BOBOMB, /*pos*/ -2028, 260, 4664, /*angle*/ 0, 0, 0, /*behParam*/ 0x00000000, /*beh*/ bhvBobomb), - OBJECT(/*model*/ MODEL_BLACK_BOBOMB, /*pos*/ -1028, 260, 3664, /*angle*/ 0, 0, 0, /*behParam*/ 0x00000000, /*beh*/ bhvBobomb), - //OBJECT(/*model*/ MODEL_NONE, /*pos*/ -2028, 260, 3264, /*angle*/ 0, 0, 0, /*behParam*/ 0x00000000, /*beh*/ bhvGoombaTripletSpawner), + OBJECT(/*model*/ MODEL_BLACK_BOBOMB, /*pos*/ -528, 260, 4664, /*angle*/ 0, 0, 0, /*behParam*/ 0x00000000, /*beh*/ bhvBobomb), + //OBJECT(/*model*/ MODEL_BLACK_BOBOMB, /*pos*/ -1028, 260, 3664, /*angle*/ 0, 0, 0, /*behParam*/ 0x00000000, /*beh*/ bhvBobomb), + OBJECT(/*model*/ MODEL_NONE, /*pos*/ -528, 260, 3264, /*angle*/ 0, 0, 0, /*behParam*/ 0x00000000, /*beh*/ bhvGoombaTripletSpawner), RETURN(), }; diff --git a/network.sh b/network.sh index 0dbb36fc..affaf649 100644 --- a/network.sh +++ b/network.sh @@ -1,5 +1,5 @@ set -e make BETTERCAMERA=1 NODRAWINGDISTANCE=1 DEBUG=1 IMMEDIATELOAD=1 ./build/us_pc/sm64.us.f3dex2e.exe --server --configfile sm64config_server.txt & -#./build/us_pc/sm64.us.f3dex2e.exe --client --configfile sm64config_client.txt & -winpty cgdb ./build/us_pc/sm64.us.f3dex2e.exe -ex 'run --client --configfile sm64config_client.txt' -ex 'quit' +./build/us_pc/sm64.us.f3dex2e.exe --client --configfile sm64config_client.txt & +#winpty cgdb ./build/us_pc/sm64.us.f3dex2e.exe -ex 'run --client --configfile sm64config_client.txt' -ex 'quit' diff --git a/src/engine/behavior_script.c b/src/engine/behavior_script.c index f61f2bf4..4eaeab93 100644 --- a/src/engine/behavior_script.c +++ b/src/engine/behavior_script.c @@ -29,6 +29,7 @@ #define BHV_CMD_GET_ADDR_OF_CMD(index) (uintptr_t)(&gCurBhvCommand[index]) static u16 gRandomSeed16; +static u16 gSyncRandom; // Unused function that directly jumps to a behavior command and resets the object's stack index. static void goto_behavior_unused(const BehaviorScript *bhvAddr) { @@ -36,8 +37,53 @@ static void goto_behavior_unused(const BehaviorScript *bhvAddr) { gCurrentObject->bhvStackIndex = 0; } +void random_sync_reset(void) { + // seed the sync'd random seed with enough synchronzied information to be "unique enough" + gSyncRandom = (u16)gCurrentObject->oPosX + ^ (u16)gCurrentObject->oPosY + ^ (u16)gCurrentObject->oPosZ + ^ (u16)gCurrentObject->oVelX + ^ (u16)gCurrentObject->oVelY + ^ (u16)gCurrentObject->oVelZ + ^ (u16)gCurrentObject->oAction; +} + +// Generate a pseudorandom integer from 0 to 65535 from the synchronized seed, and update the seed. +u16 random_sync_u16(void) { + u16 temp1, temp2; + + if (gSyncRandom == 22026) { + gSyncRandom = 0; + } + + temp1 = (gSyncRandom & 0x00FF) << 8; + temp1 = temp1 ^ gSyncRandom; + + gSyncRandom = ((temp1 & 0x00FF) << 8) + ((temp1 & 0xFF00) >> 8); + + temp1 = ((temp1 & 0x00FF) << 1) ^ gSyncRandom; + temp2 = (temp1 >> 1) ^ 0xFF80; + + if ((temp1 & 1) == 0) { + if (temp2 == 43605) { + gSyncRandom = 0; + } + else { + gSyncRandom = temp2 ^ 0x1FF4; + } + } + else { + gSyncRandom = temp2 ^ 0x8180; + } + + return gSyncRandom; +} + // Generate a pseudorandom integer from 0 to 65535 from the random seed, and update the seed. u16 random_u16(void) { + // override this function for synchronized entities + if (gCurrentObject->oSyncID != 0) { return random_sync_u16(); } + u16 temp1, temp2; if (gRandomSeed16 == 22026) { diff --git a/src/game/behaviors/goomba.inc.c b/src/game/behaviors/goomba.inc.c index 5afec760..eb41fda9 100644 --- a/src/game/behaviors/goomba.inc.c +++ b/src/game/behaviors/goomba.inc.c @@ -126,6 +126,10 @@ void bhv_goomba_init(void) { o->oDamageOrCoinValue = sGoombaProperties[o->oGoombaSize].damage; o->oGravity = -8.0f / 3.0f * o->oGoombaScale; + + network_init_object(o); + network_init_object_field(o, &o->oGoombaTargetYaw); + network_init_object_field(o, &o->oGoombaWalkTimer); } /** @@ -136,6 +140,7 @@ static void goomba_begin_jump(void) { o->oAction = GOOMBA_ACT_JUMP; o->oForwardVel = 0.0f; o->oVelY = 50.0f / 3.0f * o->oGoombaScale; + o->oGoombaJumpCooldown = 10; } /** @@ -206,7 +211,7 @@ static void goomba_act_walk(void) { if (o->oGoombaWalkTimer != 0) { o->oGoombaWalkTimer -= 1; } else { - if (random_u16() & 3) { + if (random_u16() & 3 || o->oGoombaJumpCooldown > 0) { o->oGoombaTargetYaw = obj_random_fixed_turn(0x2000); o->oGoombaWalkTimer = random_linear_offset(100, 100); } else { @@ -219,6 +224,10 @@ static void goomba_act_walk(void) { cur_obj_rotate_yaw_toward(o->oGoombaTargetYaw, 0x200); } + + if (o->oGoombaJumpCooldown > 0) { + o->oGoombaJumpCooldown--; + } } /** @@ -276,6 +285,7 @@ void huge_goomba_weakly_attacked(void) { */ void bhv_goomba_update(void) { // PARTIAL_UPDATE + random_sync_reset(); f32 animSpeed; diff --git a/src/pc/network/network.c b/src/pc/network/network.c index 76a0fd02..91bd4e4c 100644 --- a/src/pc/network/network.c +++ b/src/pc/network/network.c @@ -76,7 +76,7 @@ void network_send(struct Packet* p) { void network_update(void) { if (networkType == NT_NONE) { return; } - network_send_player(); + network_update_player(); network_update_objects(); do { diff --git a/src/pc/network/network.h b/src/pc/network/network.h index 9d7acbde..32fbcb97 100644 --- a/src/pc/network/network.h +++ b/src/pc/network/network.h @@ -6,6 +6,7 @@ #include "../cliopts.h" #define MAX_SYNC_OBJECTS 256 +#define MAX_SYNC_OBJECT_FIELDS 16 #define PACKET_LENGTH 1024 #define NETWORKTYPESTR (networkType == NT_CLIENT ? "Client" : "Server") @@ -25,6 +26,8 @@ struct SyncObject { bool owned; unsigned int ticksSinceUpdate; unsigned int syncDeactive; + u8 extraFieldCount; + void* extraFields[MAX_SYNC_OBJECT_FIELDS]; }; extern struct MarioState gMarioStates[]; @@ -43,7 +46,7 @@ void packet_write(struct Packet* packet, void* data, int length); void packet_read(struct Packet* packet, void* data, int length); // packet headers -void network_send_player(void); +void network_update_player(void); void network_receive_player(struct Packet* p); void network_update_objects(void); diff --git a/src/pc/network/packets/packet_object.c b/src/pc/network/packets/packet_object.c index f015ea07..517efde5 100644 --- a/src/pc/network/packets/packet_object.c +++ b/src/pc/network/packets/packet_object.c @@ -11,10 +11,20 @@ void network_init_object(struct Object *o) { o->oSyncID = nextSyncID++; } assert(o->oSyncID < MAX_SYNC_OBJECTS); - syncObjects[o->oSyncID].o = o; - syncObjects[o->oSyncID].owned = false; - syncObjects[o->oSyncID].ticksSinceUpdate = -1; - syncObjects[o->oSyncID].syncDeactive = 0; + struct SyncObject* so = &syncObjects[o->oSyncID]; + so->o = o; + so->owned = false; + so->ticksSinceUpdate = -1; + so->syncDeactive = 0; + so->extraFieldCount = 0; + memset(so->extraFields, 0, sizeof(void*) * MAX_SYNC_OBJECT_FIELDS); +} + +void network_init_object_field(struct Object *o, void* field) { + assert(o->oSyncID != 0); + struct SyncObject* so = &syncObjects[o->oSyncID]; + int index = so->extraFieldCount++; + so->extraFields[index] = field; } void network_send_object(struct SyncObject* so) { @@ -29,6 +39,12 @@ void network_send_object(struct SyncObject* so) { packet_write(&p, &o->oHeldState, 4); packet_write(&p, &o->oMoveAngleYaw, 4); + packet_write(&p, &so->extraFieldCount, 1); + for (int i = 0; i < so->extraFieldCount; i++) { + assert(so->extraFields[i] != NULL); + packet_write(&p, so->extraFields[i], 4); + } + if (o->activeFlags == ACTIVE_FLAG_DEACTIVATED) { so->syncDeactive++; } so->ticksSinceUpdate = 0; network_send(&p); @@ -55,6 +71,15 @@ void network_receive_object(struct Packet* p) { packet_read(p, &o->oHeldState, 4); packet_read(p, &o->oMoveAngleYaw, 4); + // write extra fields + u8 extraFields = 0; + packet_read(p, &extraFields, 1); + assert(extraFields == so->extraFieldCount); + for (int i = 0; i < extraFields; i++) { + assert(so->extraFields[i] != NULL); + packet_read(p, so->extraFields[i], 4); + } + if (o->activeFlags == ACTIVE_FLAG_DEACTIVATED) { so->syncDeactive++; } } diff --git a/src/pc/network/packets/packet_player.c b/src/pc/network/packets/packet_player.c index 229584dd..3876a4da 100644 --- a/src/pc/network/packets/packet_player.c +++ b/src/pc/network/packets/packet_player.c @@ -37,3 +37,7 @@ void network_receive_player(struct Packet* p) { // restore action state, needed for jump kicking gMarioStates[1].actionState = oldActionState; } + +void network_update_player(void) { + network_send_player(); +} \ No newline at end of file