Browse Source

Implement UI errors

pull/527/head
Anders Jenbo 6 years ago
parent
commit
961e7f58c4
  1. 1
      CMakeLists.txt
  2. 22
      SourceX/DiabloUI/diabloui.cpp
  3. 1
      SourceX/DiabloUI/diabloui.h
  4. 45
      SourceX/DiabloUI/dialogs.cpp
  5. 43
      SourceX/DiabloUI/mainmenu.cpp
  6. 19
      SourceX/DiabloUI/progress.cpp
  7. 57
      SourceX/DiabloUI/selgame.cpp
  8. 40
      SourceX/DiabloUI/selhero.cpp
  9. 86
      SourceX/DiabloUI/selok.cpp
  10. 11
      SourceX/DiabloUI/selok.h
  11. 3
      SourceX/DiabloUI/selyesno.cpp
  12. 2
      SourceX/DiabloUI/selyesno.h
  13. 5
      SourceX/dvlnet/abstract_net.h
  14. 5
      SourceX/dvlnet/frame_queue.h
  15. 15
      SourceX/dvlnet/packet.h
  16. 12
      SourceX/dvlnet/tcp_client.cpp
  17. 1
      SourceX/dvlnet/tcp_server.cpp
  18. 5
      SourceX/dvlnet/tcp_server.h
  19. 15
      SourceX/dvlnet/udp_p2p.cpp

1
CMakeLists.txt

@ -273,6 +273,7 @@ set(devilutionx_SRCS
SourceX/DiabloUI/selgame.cpp
SourceX/DiabloUI/selhero.cpp
SourceX/DiabloUI/selyesno.cpp
SourceX/DiabloUI/selok.cpp
SourceX/DiabloUI/text_draw.cpp
SourceX/DiabloUI/text.cpp
SourceX/DiabloUI/title.cpp

22
SourceX/DiabloUI/diabloui.cpp

@ -36,6 +36,7 @@ Art ArtBackground;
Art ArtCursor;
Art ArtHero;
bool gbSpawned;
int heroLevel;
void (*gfnSoundFunction)(char *file);
void (*gfnListFocus)(int value);
@ -416,6 +417,27 @@ BOOL UiValidPlayerName(char *name)
if (*letter < 0x20 || (*letter > 0x7E && *letter < 0xC0))
return false;
char *reserved[] = {
"gvdl",
"dvou",
"tiju",
"cjudi",
"bttipmf",
"ojhhfs",
"cmj{{bse",
"benjo",
};
char tmpname[PLR_NAME_LEN];
strcpy(tmpname, name);
for (size_t i = 0, n = strlen(tmpname); i < n; i++)
tmpname[i]++;
for (int i = 0; i < sizeof(reserved) / sizeof(*reserved); i++) {
if (strstr(tmpname, reserved[i]))
return false;
}
return true;
}

1
SourceX/DiabloUI/diabloui.h

@ -26,6 +26,7 @@ extern Art ArtBackground;
extern Art ArtCursor;
extern Art ArtHero;
extern bool gbSpawned;
extern int heroLevel;
constexpr auto MAINMENU_BACKGROUND = UiImage(&ArtBackground, { 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT });
constexpr auto MAINMENU_LOGO = UiImage(&ArtLogos[LOGO_MED], /*animated=*/true, /*frame=*/0, { 0, 0, 0, 0 }, UIS_CENTER);

45
SourceX/DiabloUI/dialogs.cpp

@ -16,7 +16,6 @@ extern SDL_Surface *pal_surface;
namespace {
Art dialogArt;
Art progressArt;
char dialogText[256];
char dialogCaption[1024];
bool fontWasLoaded;
@ -25,29 +24,17 @@ bool textInputWasActive;
UiItem *dialogItems;
std::size_t dialogItemsSize;
enum class State {
DEFAULT = 0,
OK,
CANCEL,
};
State state;
bool dialogEnd;
void DialogActionOK()
{
state = State::OK;
}
void DialogActionCancel()
{
state = State::CANCEL;
dialogEnd = true;
}
constexpr auto DIALOG_ART_S = UiImage(&dialogArt, { 180, 168, 280, 144 });
constexpr auto DIALOG_ART_L = UiImage(&dialogArt, { 127, 100, 385, 280 });
UiItem OK_DIALOG[] = {
DIALOG_ART_S,
UiImage(&dialogArt, { 180, 168, 280, 144 }),
UiText(dialogText, { 200, 211, 240, 80 }, UIS_CENTER),
MakeSmlButton("OK", &DialogActionOK, 265, 265),
};
@ -59,26 +46,6 @@ UiItem OK_DIALOG_WITH_CAPTION[] = {
MakeSmlButton("OK", &DialogActionOK, 264, 335),
};
UiItem PROGRESS_DIALOG[] = {
DIALOG_ART_S,
UiText(dialogText, { 180, 177, 280, 43 }, UIS_CENTER),
UiImage(&progressArt, { 205, 220, 228, 38 }),
MakeSmlButton("Cancel", &DialogActionCancel, 330, 265),
};
UiListItem SELOK_DIALOG_ITEMS[] = {
{ "OK", 0 }
};
UiItem SELOK_DIALOG[] = {
UiText(dialogText, { 140, 210, 400, 168 }, UIS_CENTER),
UiList(SELOK_DIALOG_ITEMS, 230, 390, 180, 35, UIS_CENTER),
};
UiItem SPAWNERR_DIALOG[] = {
UiText("The Rogue and Sorcerer are only available in the full retail version of Diablo. For ordering information visit https://www.gog.com/game/diablo.", { 140, 199, 400, 177 }),
UiArtTextButton("OK", &DialogActionOK, { 230, 407, 180, 43 }),
};
// clang-format off
#define BLANKCOLOR { 0, 0xFF, 0, 0 }
// clang-format on
@ -248,7 +215,7 @@ void Deinit()
void DialogLoop(UiItem *items, std::size_t num_items, UiItem *render_behind, std::size_t render_behind_size)
{
SDL_Event event;
state = State::DEFAULT;
dialogEnd = false;
if (render_behind_size == 0) {
LoadBackgroundArt("ui_art\\black.pcx");
if (ArtBackground.surface == nullptr) {
@ -266,7 +233,7 @@ void DialogLoop(UiItem *items, std::size_t num_items, UiItem *render_behind, std
switch (GetMenuAction(event)) {
case MenuAction::BACK:
case MenuAction::SELECT:
state = State::OK;
dialogEnd = true;
break;
default:
break;
@ -284,7 +251,7 @@ void DialogLoop(UiItem *items, std::size_t num_items, UiItem *render_behind, std
UiRenderItems(items, num_items);
DrawMouse();
UiFadeIn();
} while (state == State::DEFAULT);
} while (!dialogEnd);
}
} // namespace

43
SourceX/DiabloUI/mainmenu.cpp

@ -1,5 +1,6 @@
#include "devilution.h"
#include "DiabloUI/diabloui.h"
#include "DiabloUI/selok.h"
namespace dvl {
@ -8,11 +9,11 @@ DWORD dwAttractTicks;
int MainMenuResult;
UiListItem MAINMENU_DIALOG_ITEMS[] = {
{"Single Player", MAINMENU_SINGLE_PLAYER},
{"Multi Player", MAINMENU_MULTIPLAYER},
{"Replay Intro", MAINMENU_REPLAY_INTRO},
{"Show Credits", MAINMENU_SHOW_CREDITS},
{"Exit Diablo", MAINMENU_EXIT_DIABLO}
{ "Single Player", MAINMENU_SINGLE_PLAYER },
{ "Multi Player", MAINMENU_MULTIPLAYER },
{ "Replay Intro", MAINMENU_REPLAY_INTRO },
{ "Show Credits", MAINMENU_SHOW_CREDITS },
{ "Exit Diablo", MAINMENU_EXIT_DIABLO }
};
UiItem MAINMENU_DIALOG[] = {
MAINMENU_BACKGROUND,
@ -41,8 +42,6 @@ void mainmenu_Load(char *name, void (*fnSound)(char *file))
gfnSoundFunction = fnSound;
MAINMENU_DIALOG[size(MAINMENU_DIALOG) - 1].art_text.text = name;
MainMenuResult = 0;
if (!gbSpawned) {
LoadBackgroundArt("ui_art\\mainmenu.pcx");
} else {
@ -59,23 +58,31 @@ void mainmenu_Free()
BOOL UiMainMenuDialog(char *name, int *pdwResult, void (*fnSound)(char *file), int attractTimeOut)
{
mainmenu_attract_time_out = attractTimeOut;
mainmenu_Load(name, fnSound);
MainMenuResult = 0;
while (MainMenuResult == 0) {
mainmenu_attract_time_out = attractTimeOut;
mainmenu_Load(name, fnSound);
mainmenu_restart_repintro(); // for automatic starts
mainmenu_restart_repintro(); // for automatic starts
while (MainMenuResult == 0) {
UiPollAndRender();
if (GetTickCount() >= dwAttractTicks) {
MainMenuResult = MAINMENU_ATTRACT_MODE;
while (MainMenuResult == 0) {
UiPollAndRender();
if (!gbSpawned && GetTickCount() >= dwAttractTicks) {
MainMenuResult = MAINMENU_ATTRACT_MODE;
}
}
}
BlackPalette();
mainmenu_Free();
BlackPalette();
mainmenu_Free();
if (gbSpawned && MainMenuResult == MAINMENU_REPLAY_INTRO) {
UiSelOkDialog(nullptr, "The Diablo introduction cinematic is only available in the full retail version of Diablo. Visit https://www.gog.com/game/diablo to purchase.", true);
MainMenuResult = 0;
}
}
*pdwResult = MainMenuResult;
return true;
}
}
} // namespace dvl

19
SourceX/DiabloUI/progress.cpp

@ -8,12 +8,29 @@
namespace dvl {
Art dialogArt;
char dialogText[256];
Art progressArt;
Art ArtPopupSm;
Art ArtProgBG;
Art ProgFil;
SDL_Surface *msgSurface;
SDL_Surface *cancleSurface;
int textWidth;
bool endMenu;
void DialogActionCancel()
{
endMenu = true;
}
// TODO use PROGRESS_DIALOG for rendering the progressbar or delete it
UiItem PROGRESS_DIALOG[] = {
UiImage(&dialogArt, { 180, 168, 280, 144 }),
UiText(dialogText, { 180, 177, 280, 43 }, UIS_CENTER),
UiImage(&progressArt, { 205, 220, 228, 38 }),
MakeSmlButton("Cancel", &DialogActionCancel, 330, 265),
};
void progress_Load(char *msg)
{
@ -82,7 +99,7 @@ BOOL UiProgressDialog(HWND window, char *msg, int enable, int (*fnfunc)(), int r
{
progress_Load(msg);
bool endMenu = false;
endMenu = false;
int progress = 0;
SDL_Event event;

57
SourceX/DiabloUI/selgame.cpp

@ -5,6 +5,7 @@
#include "DiabloUI/diabloui.h"
#include "DiabloUI/text.h"
#include "DiabloUI/dialogs.h"
#include "DiabloUI/selok.h"
namespace dvl {
@ -26,6 +27,9 @@ constexpr UiArtTextButton SELGAME_CANCEL = UiArtTextButton("CANCEL", &UiFocusNav
UiArtText SELGAME_DESCRIPTION(selgame_Description, { 35, 256, 205, 192 });
namespace {
char title[32];
UiListItem SELDIFF_DIALOG_ITEMS[] = {
{ "Normal", DIFF_NORMAL },
{ "Nightmare", DIFF_NIGHTMARE },
@ -34,7 +38,7 @@ UiListItem SELDIFF_DIALOG_ITEMS[] = {
UiItem SELDIFF_DIALOG[] = {
MAINMENU_BACKGROUND,
MAINMENU_LOGO,
UiArtText("Create Game", { 24, 161, 590, 35 }, UIS_CENTER | UIS_BIG),
UiArtText(title, { 24, 161, 590, 35 }, UIS_CENTER | UIS_BIG),
UiArtText(selgame_Label, { 34, 211, 205, 33 }, UIS_CENTER | UIS_BIG), // DIFF
SELGAME_DESCRIPTION,
UiArtText("Select Difficulty", { 299, 211, 295, 35 }, UIS_CENTER | UIS_BIG),
@ -43,7 +47,7 @@ UiItem SELDIFF_DIALOG[] = {
SELGAME_CANCEL,
};
constexpr UiArtText SELUDPGAME_TITLE = UiArtText("Join TCP/UDP Games", { 24, 161, 590, 35 }, UIS_CENTER | UIS_BIG);
constexpr UiArtText SELUDPGAME_TITLE = UiArtText(title, { 24, 161, 590, 35 }, UIS_CENTER | UIS_BIG);
constexpr UiArtText SELUDPGAME_DESCRIPTION_LABEL = UiArtText("Description:", { 35, 211, 205, 192 }, UIS_MED);
UiListItem SELUDPGAME_DIALOG_ITEMS[] = {
@ -86,6 +90,8 @@ UiItem ENTERPASSWORD_DIALOG[] = {
SELGAME_CANCEL,
};
} // namespace
void selgame_Free()
{
ArtBackground.Unload();
@ -103,6 +109,7 @@ void selgame_GameSelection_Init()
}
getIniValue("Phone Book", "Entry1", selgame_Ip, 128);
strcpy(title, "Client-Server (TCP)");
UiInitList(0, 1, selgame_GameSelection_Focus, selgame_GameSelection_Select, selgame_GameSelection_Esc, SELUDPGAME_DIALOG, size(SELUDPGAME_DIALOG));
}
@ -126,9 +133,11 @@ void selgame_GameSelection_Select(int value)
switch (value) {
case 0:
strcpy(title, "Create Game");
UiInitList(0, NUM_DIFFICULTIES - 1, selgame_Diff_Focus, selgame_Diff_Select, selgame_Diff_Esc, SELDIFF_DIALOG, size(SELDIFF_DIALOG));
break;
case 1:
strcpy(title, "Join TCP Games");
UiInitList(0, 0, NULL, selgame_Password_Init, selgame_GameSelection_Init, ENTERIP_DIALOG, size(ENTERIP_DIALOG));
break;
}
@ -160,8 +169,32 @@ void selgame_Diff_Focus(int value)
WordWrapArtStr(selgame_Description, SELGAME_DESCRIPTION.rect.w);
}
bool IsDifficultyAllowed(int value)
{
if (value == 0 || (value == 1 && heroLevel >= 20) || (value == 2 && heroLevel >= 30)) {
return true;
}
selgame_Free();
BlackPalette();
if (value == 1)
UiSelOkDialog(title, "Your character must reach level 20 before you can enter a multiplayer game of Nightmare difficulty.", false);
if (value == 2)
UiSelOkDialog(title, "Your character must reach level 30 before you can enter a multiplayer game of Hell difficulty.", false);
LoadBackgroundArt("ui_art\\selgame.pcx");
return false;
}
void selgame_Diff_Select(int value)
{
if (!IsDifficultyAllowed(value)) {
selgame_GameSelection_Select(0);
return;
}
gbDifficulty = value;
if (provider == SELCONN_LOOPBACK) {
@ -193,13 +226,18 @@ void selgame_Password_Select(int value)
if (selgame_selectedGame) {
setIniValue("Phone Book", "Entry1", selgame_Ip);
if (SNetJoinGame(selgame_selectedGame, selgame_Ip, selgame_Password, NULL, NULL, gdwPlayerId)) {
if (!IsDifficultyAllowed(m_client_info->initdata->bDiff)) {
selgame_GameSelection_Select(1);
return;
}
UiInitList(0, 0, NULL, NULL, NULL, NULL, 0);
selgame_endMenu = true;
} else {
UiErrorOkDialog(
"Unable to establish a connection.",
PROJECT_NAME " v" PROJECT_VERSION " game not found or password invalid.",
ENTERPASSWORD_DIALOG, size(ENTERPASSWORD_DIALOG));
selgame_Free();
BlackPalette();
UiSelOkDialog("Multi Player Game", SDL_GetError(), false);
LoadBackgroundArt("ui_art\\selgame.pcx");
selgame_Password_Init(selgame_selectedGame);
}
return;
@ -212,7 +250,10 @@ void selgame_Password_Select(int value)
UiInitList(0, 0, NULL, NULL, NULL, NULL, 0);
selgame_endMenu = true;
} else {
UiErrorOkDialog("Unable to create game.", ENTERPASSWORD_DIALOG, size(ENTERPASSWORD_DIALOG));
selgame_Free();
BlackPalette();
UiSelOkDialog("Multi Player Game", SDL_GetError(), false);
LoadBackgroundArt("ui_art\\selgame.pcx");
selgame_Password_Init(0);
}
}
@ -239,4 +280,4 @@ int UiSelectGame(int a1, _SNETPROGRAMDATA *client_info, _SNETPLAYERDATA *user_in
return selgame_enteringGame;
}
}
} // namespace dvl

40
SourceX/DiabloUI/selhero.cpp

@ -5,10 +5,12 @@
#include <random>
#include "DiabloUI/diabloui.h"
#include "DiabloUI/dialogs.h"
#include "../../DiabloUI/diabloui.h"
#include "devilution.h"
#include "scrollbar.h"
#include "selyesno.h"
#include "DiabloUI/dialogs.h"
#include "DiabloUI/scrollbar.h"
#include "DiabloUI/selyesno.h"
#include "DiabloUI/selok.h"
namespace dvl {
@ -58,7 +60,7 @@ UiListItem SELLIST_DIALOG_ITEMS[kMaxViewportItems];
UiItem SELLIST_DIALOG[] = {
UiArtText("Select Hero", { 264, 211, 320, 33 }, UIS_CENTER | UIS_BIG),
UiList(SELLIST_DIALOG_ITEMS, 265, 256, 320, 26, UIS_CENTER | UIS_MED | UIS_GOLD),
MakeScrollBar({585, 244, 25, 178}),
MakeScrollBar({ 585, 244, 25, 178 }),
UiArtTextButton("OK", &UiFocusNavigationSelect, { 239, 429, 120, 35 }, UIS_CENTER | UIS_BIG | UIS_GOLD),
UiArtTextButton("Delete", &selhero_UiFocusNavigationYesNo, { 364, 429, 120, 35 }, UIS_CENTER | UIS_BIG | UIS_DISABLED),
UiArtTextButton("Cancel", &UiFocusNavigationEsc, { 489, 429, 120, 35 }, UIS_CENTER | UIS_BIG | UIS_GOLD)
@ -238,6 +240,15 @@ void selhero_ClassSelector_Focus(int value)
void selhero_ClassSelector_Select(int value)
{
if (gbSpawned && (value == 1 || value == 2)) {
selhero_Free();
BlackPalette();
UiSelOkDialog(nullptr, "The Rogue and Sorcerer are only available in the full retail version of Diablo. Visit https://www.gog.com/game/diablo to purchase.", false);
LoadBackgroundArt("ui_art\\selhero.pcx");
selhero_List_Select(selhero_SaveCount);
return;
}
strcpy(title, "New Single Player Hero");
if (selhero_isMultiPlayer) {
strcpy(title, "New Multi Player Hero");
@ -261,14 +272,24 @@ void selhero_ClassSelector_Esc()
void selhero_Name_Select(int value)
{
if (gfnHeroCreate(&selhero_heroInfo)) {
if (!UiValidPlayerName(selhero_heroInfo.name)) {
selhero_Free();
BlackPalette();
UiSelOkDialog(title, "Invalid name. A name cannot contain spaces, reserved characters, or reserved words.\n", false);
LoadBackgroundArt("ui_art\\selhero.pcx");
} else if (gfnHeroCreate(&selhero_heroInfo)) {
UiInitList(0, 0, NULL, NULL, NULL, NULL, 0);
selhero_endMenu = true;
return;
} else {
UiErrorOkDialog("Unable to create character.", SELHERO_DIALOG, size(SELHERO_DIALOG));
memset(selhero_heroInfo.name, '\0', sizeof(selhero_heroInfo.name));
selhero_ClassSelector_Select(selhero_heroInfo.heroclass);
}
memset(selhero_heroInfo.name, '\0', sizeof(selhero_heroInfo.name));
#ifdef PREFILL_PLAYER_NAME
strcpy(selhero_heroInfo.name, selhero_GenerateName(selhero_heroInfo.heroclass));
#endif
selhero_ClassSelector_Select(selhero_heroInfo.heroclass);
}
void selhero_Name_Esc()
@ -336,15 +357,14 @@ BOOL UiSelHeroDialog(
}
BlackPalette();
selhero_Free();
if (selhero_navigateYesNo) {
if (!UiSelHeroDelYesNoDialog(gfnHeroDelete, &selhero_heroInfo, selhero_isMultiPlayer))
app_fatal("Unable to load Yes/No dialog");
UiSelHeroDelYesNoDialog(gfnHeroDelete, &selhero_heroInfo, selhero_isMultiPlayer);
}
} while (selhero_navigateYesNo);
*dlgresult = selhero_result;
strcpy(name, selhero_heroInfo.name);
heroLevel = selhero_heroInfo.level;
UnloadScrollBar();
return true;

86
SourceX/DiabloUI/selok.cpp

@ -0,0 +1,86 @@
#include "devilution.h"
#include "DiabloUI/diabloui.h"
#include "DiabloUI/text.h"
#include "DiabloUI/selok.h"
namespace dvl {
namespace {
char dialogText[256];
} // namespace
int selok_endMenu;
char selok_title[32];
void selok_Free()
{
ArtBackground.Unload();
}
void selok_Select(int value)
{
selok_endMenu = true;
}
void selok_Esc()
{
selok_endMenu = true;
}
UiListItem SELOK_DIALOG_ITEMS[] = {
{ "OK", 0 }
};
UiItem SELOK_DIALOG[] = {
MAINMENU_BACKGROUND,
MAINMENU_LOGO,
UiArtText(selok_title, { 24, 161, 590, 35 }, UIS_CENTER | UIS_BIG),
UiArtText(dialogText, { 140, 210, 560, 168 }, UIS_MED),
UiList(SELOK_DIALOG_ITEMS, 230, 390, 180, 35, UIS_CENTER | UIS_BIG | UIS_GOLD)
};
UiItem SPAWNERR_DIALOG[] = {
MAINMENU_BACKGROUND,
MAINMENU_LOGO,
UiArtText(dialogText, { 140, 197, 560, 168 }, UIS_MED),
UiList(SELOK_DIALOG_ITEMS, 230, 390, 180, 35, UIS_CENTER | UIS_BIG | UIS_GOLD)
};
void UiSelOkDialog(const char *title, const char *body, bool background)
{
if (!background) {
LoadBackgroundArt("ui_art\\black.pcx");
} else {
if (!gbSpawned) {
LoadBackgroundArt("ui_art\\mainmenu.pcx");
} else {
LoadBackgroundArt("ui_art\\swmmenu.pcx");
}
}
UiItem *items = SPAWNERR_DIALOG;
int itemCnt = size(SPAWNERR_DIALOG);
if (title != nullptr) {
strcpy(selok_title, title);
items = SELOK_DIALOG;
itemCnt = size(SELOK_DIALOG);
}
strcpy(dialogText, body);
WordWrapArtStr(dialogText, 280);
UiInitList(0, 0, NULL, selok_Select, selok_Esc, items, itemCnt, false, NULL);
selok_endMenu = false;
while (!selok_endMenu) {
UiRenderItems(items, itemCnt);
UiPollAndRender();
}
BlackPalette();
selok_Free();
}
} // namespace dvl

11
SourceX/DiabloUI/selok.h

@ -0,0 +1,11 @@
#pragma once
#include "devilution.h"
namespace dvl {
void UiSelOkDialog(const char *title, const char *body, bool background);
void selok_Free();
void selok_Select(int value);
void selok_Esc();
}

3
SourceX/DiabloUI/selyesno.cpp

@ -45,7 +45,7 @@ void selyesno_Esc()
selyesno_endMenu = true;
}
BOOL UiSelHeroDelYesNoDialog(
void UiSelHeroDelYesNoDialog(
BOOL (*fnremove)(_uiheroinfo *),
_uiheroinfo *selectHero,
bool isMultiplayer)
@ -74,6 +74,5 @@ BOOL UiSelHeroDelYesNoDialog(
BlackPalette();
selyesno_Free();
return true;
}
}

2
SourceX/DiabloUI/selyesno.h

@ -3,7 +3,7 @@
#include "devilution.h"
namespace dvl {
BOOL UiSelHeroDelYesNoDialog(BOOL (*fnremove)(_uiheroinfo *), _uiheroinfo *selectHero, bool isMultiplayer);
void UiSelHeroDelYesNoDialog(BOOL (*fnremove)(_uiheroinfo *), _uiheroinfo *selectHero, bool isMultiplayer);
void selyesno_Free();
void selyesno_Select(int value);
void selyesno_Esc();

5
SourceX/dvlnet/abstract_net.h

@ -13,6 +13,11 @@ namespace net {
typedef std::vector<unsigned char> buffer_t;
typedef unsigned long provider_t;
class dvlnet_exception : public std::exception {
public:
const char *what() const throw() override
{
return "Network error";
}
};
class abstract_net {

5
SourceX/dvlnet/frame_queue.h

@ -8,6 +8,11 @@ namespace dvl {
namespace net {
class frame_queue_exception : public dvlnet_exception {
public:
const char *what() const throw() override
{
return "Incorrect frame size";
}
};
typedef uint32_t framesize_t;

15
SourceX/dvlnet/packet.h

@ -35,6 +35,11 @@ static constexpr plr_t PLR_MASTER = 0xFE;
static constexpr plr_t PLR_BROADCAST = 0xFF;
class packet_exception : public dvlnet_exception {
public:
const char *what() const throw() override
{
return "Incorrect package size";
}
};
class packet {
@ -57,7 +62,7 @@ protected:
public:
packet(const key_t &k)
: key(k) {};
: key(k) {};
const buffer_t &data();
@ -152,7 +157,7 @@ void packet_in::process_element(T &x)
throw packet_exception();
std::memcpy(&x, decrypted_buffer.data(), sizeof(T));
decrypted_buffer.erase(decrypted_buffer.begin(),
decrypted_buffer.begin() + sizeof(T));
decrypted_buffer.begin() + sizeof(T));
}
template <>
@ -181,7 +186,7 @@ inline void packet_out::create<PT_TURN>(plr_t s, plr_t d, turn_t u)
template <>
inline void packet_out::create<PT_JOIN_REQUEST>(plr_t s, plr_t d,
cookie_t c, buffer_t i)
cookie_t c, buffer_t i)
{
if (have_encrypted || have_decrypted)
ABORT();
@ -195,7 +200,7 @@ inline void packet_out::create<PT_JOIN_REQUEST>(plr_t s, plr_t d,
template <>
inline void packet_out::create<PT_JOIN_ACCEPT>(plr_t s, plr_t d, cookie_t c,
plr_t n, buffer_t i)
plr_t n, buffer_t i)
{
if (have_encrypted || have_decrypted)
ABORT();
@ -222,7 +227,7 @@ inline void packet_out::create<PT_CONNECT>(plr_t s, plr_t d, plr_t n)
template <>
inline void packet_out::create<PT_DISCONNECT>(plr_t s, plr_t d, plr_t n,
leaveinfo_t l)
leaveinfo_t l)
{
if (have_encrypted || have_decrypted)
ABORT();

12
SourceX/dvlnet/tcp_client.cpp

@ -17,7 +17,7 @@ int tcp_client::create(std::string addrstr, std::string passwd)
local_server.reset(new tcp_server(ioc, addrstr, port, passwd));
return join(local_server->localhost_self(), passwd);
} catch (std::system_error &e) {
eprintf("%s\n", e.what());
SDL_SetError(e.what());
return -1;
}
}
@ -34,7 +34,7 @@ int tcp_client::join(std::string addrstr, std::string passwd)
asio::ip::tcp::no_delay option(true);
sock.set_option(option);
} catch (std::exception &e) {
eprintf("%s\n", e.what());
SDL_SetError(e.what());
return -1;
}
start_recv();
@ -49,6 +49,7 @@ int tcp_client::join(std::string addrstr, std::string passwd)
try {
poll();
} catch (const std::runtime_error &e) {
SDL_SetError(e.what());
return -1;
}
if (plr_self != PLR_BROADCAST)
@ -56,7 +57,12 @@ int tcp_client::join(std::string addrstr, std::string passwd)
SDL_Delay(ms_sleep);
}
}
return (plr_self == PLR_BROADCAST ? -1 : plr_self);
if (plr_self == PLR_BROADCAST) {
SDL_SetError("Unable to connect");
return -1;
}
return plr_self;
}
void tcp_client::poll()

1
SourceX/dvlnet/tcp_server.cpp

@ -82,6 +82,7 @@ void tcp_server::handle_recv(scc con, const asio::error_code &ec,
handle_recv_packet(*pkt);
}
} catch (dvlnet_exception &e) {
SDL_Log("Network error: %s", e.what());
drop_connection(con);
return;
}

5
SourceX/dvlnet/tcp_server.h

@ -16,6 +16,11 @@ namespace dvl {
namespace net {
class server_exception : public dvlnet_exception {
public:
const char *what() const throw() override
{
return "Invalid player ID";
}
};
class tcp_server {

15
SourceX/dvlnet/udp_p2p.cpp

@ -32,6 +32,7 @@ int udp_p2p::create(std::string addrstr, std::string passwd)
try {
sock.bind(endpoint(ipaddr, port));
} catch (std::exception &e) {
SDL_SetError(e.what());
return -1;
}
plr_self = 0;
@ -53,10 +54,10 @@ int udp_p2p::join(std::string addrstr, std::string passwd)
master = themaster;
{ // hack: try to join for 5 seconds
randombytes_buf(reinterpret_cast<unsigned char *>(&cookie_self),
sizeof(cookie_t));
sizeof(cookie_t));
auto pkt = pktfty->make_packet<PT_JOIN_REQUEST>(PLR_BROADCAST,
PLR_MASTER, cookie_self,
game_init_info);
PLR_MASTER, cookie_self,
game_init_info);
send(*pkt);
for (auto i = 0; i < 5; ++i) {
recv();
@ -91,10 +92,12 @@ void udp_p2p::recv()
auto pkt = pktfty->make_packet(pkt_buf);
recv_decrypted(*pkt, sender);
} catch (packet_exception &e) {
SDL_Log("Incorrect package size");
// drop packet
}
}
} catch (std::exception &e) {
SDL_Log(e.what());
return;
}
}
@ -120,7 +123,7 @@ std::set<udp_p2p::endpoint> udp_p2p::dests_for_addr(plr_t dest, endpoint sender)
if (i != plr_self && connected_table[i])
ret.insert(nexthop_table[i]);
ret.insert(connection_requests_pending.begin(),
connection_requests_pending.end());
connection_requests_pending.end());
} else if (dest == PLR_MASTER) {
if (master != none)
ret.insert(master);
@ -139,8 +142,8 @@ void udp_p2p::handle_join_request(packet &pkt, endpoint sender)
}
}
auto reply = pktfty->make_packet<PT_JOIN_ACCEPT>(plr_self, PLR_BROADCAST,
pkt.cookie(), i,
game_init_info);
pkt.cookie(), i,
game_init_info);
send(*reply);
}

Loading…
Cancel
Save