diff --git a/src/network/network_command.cpp b/src/network/network_command.cpp index 26f551f847..05837f50c3 100644 --- a/src/network/network_command.cpp +++ b/src/network/network_command.cpp @@ -111,6 +111,12 @@ inline auto MakeCallbackTable(std::index_sequence) noexcept /** Type-erased table of callbacks. */ static auto _callback_table = MakeCallbackTable(std::make_index_sequence<_callback_tuple_size>{}); +template struct CallbackArgsHelper; +template +struct CallbackArgsHelper { + using Args = std::tuple...>; +}; + /* Helpers to generate the command dispatch table from the command traits. */ @@ -125,10 +131,22 @@ struct CommandDispatch { UnpackDispatchT Unpack; }; +template +constexpr UnpackNetworkCommandProc MakeUnpackNetworkCommandCallback() noexcept +{ + /* Check if the callback matches with the command arguments. If not, don't generate an Unpack proc. */ + using Tcallback = std::tuple_element_t; + if constexpr (std::is_same_v || std::is_same_v || std::is_same_v::CbArgs, typename CallbackArgsHelper::Args>) { + return &UnpackNetworkCommand; + } else { + return nullptr; + } +} + template constexpr UnpackDispatchT MakeUnpackNetworkCommand(std::index_sequence) noexcept { - return UnpackDispatchT{{ {&UnpackNetworkCommand}... }}; + return UnpackDispatchT{{ {MakeUnpackNetworkCommandCallback()}...}}; } template @@ -315,6 +333,7 @@ void NetworkExecuteLocalCommandQueue() _current_company = cp->company; size_t cb_index = FindCallbackIndex(cp->callback); assert(cb_index < _callback_tuple_size); + assert(_cmd_dispatch[cp->cmd].Unpack[cb_index] != nullptr); _cmd_dispatch[cp->cmd].Unpack[cb_index](cp); queue.Pop(); @@ -410,7 +429,7 @@ const char *NetworkGameSocketHandler::ReceiveCommand(Packet *p, CommandPacket *c cp->data = _cmd_dispatch[cp->cmd].Sanitize(p->Recv_buffer()); byte callback = p->Recv_uint8(); - if (callback >= _callback_table.size()) return "invalid callback"; + if (callback >= _callback_table.size() || _cmd_dispatch[cp->cmd].Unpack[callback] == nullptr) return "invalid callback"; cp->callback = _callback_table[callback]; return nullptr; @@ -430,7 +449,7 @@ void NetworkGameSocketHandler::SendCommand(Packet *p, const CommandPacket *cp) p->Send_buffer(cp->data); size_t callback = FindCallbackIndex(cp->callback); - if (callback > UINT8_MAX) { + if (callback > UINT8_MAX || _cmd_dispatch[cp->cmd].Unpack[callback] == nullptr) { Debug(net, 0, "Unknown callback for command; no callback sent (command: {})", cp->cmd); callback = 0; // _callback_table[0] == nullptr } @@ -507,13 +526,6 @@ CommandDataBuffer SanitizeCmdStrings(const CommandDataBuffer &data) return EndianBufferWriter::FromValue(args); } - -template struct CallbackArgsHelper; -template -struct CallbackArgsHelper { - using Args = std::tuple...>; -}; - /** * Unpack a generic command packet into its actual typed components. * @tparam Tcmd Command type to be unpacked. @@ -524,12 +536,5 @@ template void UnpackNetworkCommand(const CommandPacket* cp) { auto args = EndianBufferReader::ToValue::Args>(cp->data); - - /* Check if the callback matches with the command arguments. If not, drop the callback. */ - using Tcallback = std::tuple_element_t; - if constexpr (std::is_same_v || std::is_same_v || std::is_same_v::CbArgs, typename CallbackArgsHelper::Args>) { - Command::PostFromNet(cp->err_msg, std::get(_callback_tuple), cp->my_cmd, cp->tile, args); - } else { - Command::PostFromNet(cp->err_msg, (CommandCallback *)nullptr, cp->my_cmd, cp->tile, args); - } + Command::PostFromNet(cp->err_msg, std::get(_callback_tuple), cp->my_cmd, cp->tile, args); }