void GameEventsEnqueue(CArray *store, GameEvent e) { if (store->elemSize == 0) { return; } // If we're the server, broadcast any events that clients need // If we're the client, pass along to server, but only if it's for a local player // Otherwise we'd ping-pong the same updates from the server const GameEventEntry gee = sGameEventEntries[e.Type]; if (gee.Broadcast) { NetServerSendMsg(&gNetServer, NET_SERVER_BCAST, gee.Type, &e.u); } if (gee.Submit) { int actorUID = -1; bool actorIsLocal = false; switch (e.Type) { case GAME_EVENT_ACTOR_MOVE: actorUID = e.u.ActorMove.UID; break; case GAME_EVENT_ACTOR_STATE: actorUID = e.u.ActorState.UID; break; case GAME_EVENT_ACTOR_DIR: actorUID = e.u.ActorDir.UID; break; case GAME_EVENT_ACTOR_SLIDE: actorUID = e.u.ActorSlide.UID; break; case GAME_EVENT_ACTOR_SWITCH_GUN: actorUID = e.u.ActorSwitchGun.UID; break; case GAME_EVENT_ACTOR_PICKUP_ALL: actorUID = e.u.ActorPickupAll.UID; break; case GAME_EVENT_ACTOR_USE_AMMO: actorUID = e.u.UseAmmo.UID; break; case GAME_EVENT_ACTOR_MELEE: actorUID = e.u.Melee.UID; break; case GAME_EVENT_GUN_FIRE: if (e.u.GunFire.IsGun) { actorUID = e.u.GunFire.ActorUID; } break; case GAME_EVENT_GUN_RELOAD: actorIsLocal = PlayerIsLocal(e.u.GunReload.PlayerUID); break; case GAME_EVENT_GUN_STATE: actorUID = e.u.GunState.ActorUID; break; default: break; } if (actorUID >= 0) { actorIsLocal = ActorIsLocalPlayer(actorUID); } if (actorIsLocal) { NetClientSendMsg(&gNetClient, gee.Type, &e.u); } } CArrayPushBack(store, &e); }
static void OnReceive(NetClient *n, ENetEvent event) { const NetMsg msgType = (NetMsg)*(uint32_t *)event.packet->data; LOG(LM_NET, LL_TRACE, "recv msg(%u)", msgType); const NetMsgEntry nme = NetMsgGet(msgType); if (nme.Event != GAME_EVENT_NONE) { // Game event message; decode and add to event queue LOG(LM_NET, LL_DEBUG, "recv gameEvent(%d)", (int)nme.Event); GameEvent e = GameEventNew(nme.Event); if (nme.Fields != NULL) { NetDecode(event.packet, &e.u, nme.Fields); } // For actor events, check if UID is not for local player int actorUID = -1; bool actorIsLocal = false; switch (nme.Event) { case GAME_EVENT_ACTOR_ADD: // Note: ignore checking this event break; case GAME_EVENT_ACTOR_MOVE: actorUID = e.u.ActorMove.UID; break; case GAME_EVENT_ACTOR_STATE: actorUID = e.u.ActorState.UID; break; case GAME_EVENT_ACTOR_DIR: actorUID = e.u.ActorDir.UID; break; case GAME_EVENT_ADD_BULLET: actorIsLocal = PlayerIsLocal(e.u.AddBullet.PlayerIndex); break; default: break; } if (actorUID >= 0) { actorIsLocal = ActorIsLocalPlayer(actorUID); } if (actorIsLocal) { LOG(LM_NET, LL_TRACE, "game event is for local player, ignoring"); } else { GameEventsEnqueue(&gGameEvents, e); } } else { switch (msgType) { case MSG_CLIENT_ID: { CASSERT( n->ClientId == -1, "unexpected client ID message, already set"); NetMsgClientId cid; NetDecode(event.packet, &cid, NetMsgClientId_fields); LOG(LM_NET, LL_DEBUG, "NetClient: received client ID %d", cid.Id); n->ClientId = cid.Id; } break; case MSG_CAMPAIGN_DEF: if (gCampaign.IsLoaded) { LOG(LM_NET, LL_INFO, "WARNING: unexpected campaign def msg received"); } else { LOG(LM_NET, LL_DEBUG, "NetClient: received campaign def, loading..."); NetMsgCampaignDef def; NetDecode(event.packet, &def, NetMsgCampaignDef_fields); char campaignPath[CDOGS_PATH_MAX]; GameMode mode; NetMsgCampaignDefConvert(&def, campaignPath, &mode); CampaignEntry entry; if (CampaignEntryTryLoad(&entry, campaignPath, mode) && CampaignLoad(&gCampaign, &entry)) { gCampaign.IsClient = true; } else { printf("Error: failed to load campaign def\n"); gCampaign.IsError = true; } } break; case MSG_PLAYER_DATA: { NetMsgPlayerData pd; NetDecode(event.packet, &pd, NetMsgPlayerData_fields); AddMissingPlayers(pd.PlayerIndex); LOG(LM_NET, LL_DEBUG, "recv player data name(%s) id(%d) total(%d)", pd.Name, pd.PlayerIndex, (int)gPlayerDatas.size); NetMsgPlayerDataUpdate(&pd); } break; case MSG_ADD_PLAYERS: { NetMsgAddPlayers ap; NetDecode(event.packet, &ap, NetMsgAddPlayers_fields); LOG(LM_NET, LL_DEBUG, "NetClient: received new players %d", (int)ap.PlayerIds_count); // Add new players // If they are local players, set them up with defaults const bool isLocal = ap.ClientId == n->ClientId; for (int i = 0; i < ap.PlayerIds_count; i++) { const int playerId = (int)ap.PlayerIds[i]; AddMissingPlayers(playerId); PlayerData *p = CArrayGet(&gPlayerDatas, playerId); p->IsLocal = isLocal; if (isLocal) { PlayerDataSetLocalDefaults(p, i); } } } break; case MSG_GAME_START: LOG(LM_NET, LL_DEBUG, "NetClient: received game start"); gMission.HasStarted = true; break; case MSG_GAME_END: LOG(LM_NET, LL_DEBUG, "NetClient: received game end"); gMission.isDone = true; break; default: CASSERT(false, "unexpected message type"); break; } } enet_packet_destroy(event.packet); }