Show explanation message for http related errors (like server connecting timeout, SSL error), make showing http error messages more consistent in launcher

This commit is contained in:
UnknownShadow200 2019-06-22 00:28:08 +10:00
parent d78b31a941
commit 3819e93dad
10 changed files with 182 additions and 145 deletions

View File

@ -401,9 +401,6 @@
<ClCompile Include="Widgets.c">
<Filter>Source Files\2D</Filter>
</ClCompile>
<ClCompile Include="Input.c">
<Filter>Source Files\Platform</Filter>
</ClCompile>
<ClCompile Include="Utils.c">
<Filter>Source Files\Utils</Filter>
</ClCompile>
@ -548,5 +545,8 @@
<ClCompile Include="Protocol.c">
<Filter>Source Files\Network</Filter>
</ClCompile>
<ClCompile Include="Input.c">
<Filter>Source Files\Game</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -15,6 +15,12 @@
#define _UNICODE
#endif
#ifdef UNICODE
#define Platform_DecodeString(dst, src, len) String_AppendUtf16(dst, (Codepoint*)(src), (len) * 2)
#else
#define Platform_DecodeString(dst, src, len) String_DecodeCP1252(dst, (uint8_t*)(src), len)
#endif
#include <windows.h>
#include <wininet.h>
#elif defined CC_BUILD_WEB
@ -252,6 +258,7 @@ static void Http_ParseHeader(struct HttpRequest* req, const String* line) {
static void Http_SysInit(void) { }
static void Http_SysFree(void) { }
static void Http_DownloadAsync(struct HttpRequest* req);
bool Http_DescribeError(ReturnCode res, String* dst) { return false; }
static void Http_DownloadNextAsync(void) {
struct HttpRequest req;
@ -400,6 +407,16 @@ static ReturnCode HttpCache_Lookup(struct HttpCacheEntry* e) {
return HttpCache_Insert(i, e);
}
bool Http_DescribeError(ReturnCode res, String* dst) {
TCHAR chars[600];
res = FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
GetModuleHandle(TEXT("wininet.dll")), res, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), chars, 600, NULL);
if (!res) return false;
Platform_DecodeString(dst, chars, res);
return true;
}
static void Http_SysInit(void) {
/* TODO: Should we use INTERNET_OPEN_TYPE_PRECONFIG instead? */
hInternet = InternetOpenA(GAME_APP_NAME, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
@ -548,6 +565,14 @@ static void Http_SysFree(void) {
#elif defined CC_BUILD_CURL
static CURL* curl;
bool Http_DescribeError(ReturnCode res, String* dst) {
const char* err = curl_easy_strerror(res);
if (!err) return false;
String_AppendConst(dst, err);
return true;
}
static void Http_SysInit(void) {
CURLcode res = curl_global_init(CURL_GLOBAL_DEFAULT);
if (res) Logger_Abort2(res, "Failed to init curl");

View File

@ -62,6 +62,8 @@ void Http_UrlEncodeUtf8(String* dst, const String* src);
/* Formats a date for inclusion in HTTP headers. */
/* NOTE: Time is always assumed as being UTC. */
void Http_FormatDate(TimeMS ms, String* str);
/* Outputs more detailed information about errors with http requests. */
bool Http_DescribeError(ReturnCode res, String* dst);
/* Attempts to retrieve a fully completed request. */
/* NOTE: You MUST also check Result/StatusCode, and check Size is > 0. */

View File

@ -692,17 +692,12 @@ CC_NOINLINE static void MainScreen_GetResume(struct ResumeInfo* info, bool full)
CC_NOINLINE static void MainScreen_Error(struct LWebTask* task, const char* action) {
String str; char strBuffer[STRING_SIZE];
struct MainScreen* s = &MainScreen_Instance;
String_InitArray(str, strBuffer);
s->SigningIn = false;
if (task->Status) {
String_Format1(&str, "&cclassicube.net returned: %i error", &task->Status);
} else {
String_Format1(&str, "&cError %i when connecting to classicube.net", &task->Res);
}
LWebTask_DisplayError(task, action, &str);
LLabel_SetText(&s->LblStatus, &str);
LWidget_Redraw(&s->LblStatus);
s->SigningIn = false;
}
static void MainScreen_Login(void* w, int x, int y) {
@ -886,7 +881,7 @@ static void MainScreen_TickGetToken(struct MainScreen* s) {
if (GetTokenTask.Base.Success) {
SignInTask_Run(&s->IptUsername.Text, &s->IptPassword.Text);
} else {
MainScreen_Error(&GetTokenTask.Base, "sign in");
MainScreen_Error(&GetTokenTask.Base, "signing in");
}
}
@ -910,7 +905,7 @@ static void MainScreen_TickSignIn(struct MainScreen* s) {
LLabel_SetText(&s->LblStatus, &fetchMsg);
LWidget_Redraw(&s->LblStatus);
} else {
MainScreen_Error(&SignInTask.Base, "sign in");
MainScreen_Error(&SignInTask.Base, "signing in");
}
}
@ -1164,7 +1159,7 @@ static void ServersScreen_Connect(void* w, int x, int y) {
String* hash = &ServersScreen_Instance.IptHash.Text;
if (!hash->length && table->RowsCount) {
hash = &LTable_Get(table->TopRow)->Hash;
hash = &LTable_Get(table->TopRow)->hash;
}
Launcher_ConnectToServer(hash);
}
@ -1217,7 +1212,7 @@ static void ServersScreen_ReloadServers(struct ServersScreen* s) {
LTable_Sort(&s->Table);
for (i = 0; i < FetchServersTask.NumServers; i++) {
FetchFlagsTask_Add(&FetchServersTask.Servers[i].Country);
FetchFlagsTask_Add(&FetchServersTask.Servers[i].country);
}
}
@ -1521,14 +1516,17 @@ static void UpdatesScreen_UpdateProgress(struct UpdatesScreen* s, struct LWebTas
}
static void UpdatesScreen_FetchTick(struct UpdatesScreen* s) {
static const String failedMsg = String_FromConst("&cFailed to fetch update");
String str; char strBuffer[STRING_SIZE];
if (!FetchUpdateTask.Base.Working) return;
LWebTask_Tick(&FetchUpdateTask.Base);
UpdatesScreen_UpdateProgress(s, &FetchUpdateTask.Base);
if (!FetchUpdateTask.Base.Completed) return;
if (!FetchUpdateTask.Base.Success) {
LLabel_SetText(&s->LblStatus, &failedMsg);
String_InitArray(str, strBuffer);
LWebTask_DisplayError(&FetchUpdateTask.Base, "fetching update", &str);
LLabel_SetText(&s->LblStatus, &str);
LWidget_Redraw(&s->LblStatus);
} else {
/* WebTask handles saving of ClassiCube.update for us */

View File

@ -14,7 +14,7 @@
#define TOKEN_FALSE 3
#define TOKEN_NULL 4
/* Consumes n characters from the JSON stream */
#define JsonContext_Consume(ctx, n) ctx->Cur += n; ctx->Left -= n;
#define JsonContext_Consume(ctx, n) ctx->cur += n; ctx->left -= n;
static const String strTrue = String_FromConst("true");
static const String strFalse = String_FromConst("false");
@ -30,10 +30,10 @@ static bool Json_IsNumber(char c) {
static bool Json_ConsumeConstant(struct JsonContext* ctx, const String* value) {
int i;
if (value->length > ctx->Left) return false;
if (value->length > ctx->left) return false;
for (i = 0; i < value->length; i++) {
if (ctx->Cur[i] != value->buffer[i]) return false;
if (ctx->cur[i] != value->buffer[i]) return false;
}
JsonContext_Consume(ctx, value->length);
@ -42,10 +42,10 @@ static bool Json_ConsumeConstant(struct JsonContext* ctx, const String* value) {
static int Json_ConsumeToken(struct JsonContext* ctx) {
char c;
for (; ctx->Left && Json_IsWhitespace(*ctx->Cur); ) { JsonContext_Consume(ctx, 1); }
if (!ctx->Left) return TOKEN_NONE;
for (; ctx->left && Json_IsWhitespace(*ctx->cur); ) { JsonContext_Consume(ctx, 1); }
if (!ctx->left) return TOKEN_NONE;
c = *ctx->Cur;
c = *ctx->cur;
if (c == '{' || c == '}' || c == '[' || c == ']' || c == ',' || c == '"' || c == ':') {
JsonContext_Consume(ctx, 1); return c;
}
@ -64,8 +64,8 @@ static int Json_ConsumeToken(struct JsonContext* ctx) {
static String Json_ConsumeNumber(struct JsonContext* ctx) {
int len = 0;
for (; ctx->Left && Json_IsNumber(*ctx->Cur); len++) { JsonContext_Consume(ctx, 1); }
return String_Init(ctx->Cur - len, len, len);
for (; ctx->left && Json_IsNumber(*ctx->cur); len++) { JsonContext_Consume(ctx, 1); }
return String_Init(ctx->cur - len, len, len);
}
static void Json_ConsumeString(struct JsonContext* ctx, String* str) {
@ -73,23 +73,23 @@ static void Json_ConsumeString(struct JsonContext* ctx, String* str) {
char c;
str->length = 0;
for (; ctx->Left;) {
c = *ctx->Cur; JsonContext_Consume(ctx, 1);
for (; ctx->left;) {
c = *ctx->cur; JsonContext_Consume(ctx, 1);
if (c == '"') return;
if (c != '\\') { String_Append(str, c); continue; }
/* form of \X */
if (!ctx->Left) break;
c = *ctx->Cur; JsonContext_Consume(ctx, 1);
if (!ctx->left) break;
c = *ctx->cur; JsonContext_Consume(ctx, 1);
if (c == '/' || c == '\\' || c == '"') { String_Append(str, c); continue; }
/* form of \uYYYY */
if (c != 'u' || ctx->Left < 4) break;
if (c != 'u' || ctx->left < 4) break;
if (!PackedCol_Unhex(ctx->Cur[0], &h[0])) break;
if (!PackedCol_Unhex(ctx->Cur[1], &h[1])) break;
if (!PackedCol_Unhex(ctx->Cur[2], &h[2])) break;
if (!PackedCol_Unhex(ctx->Cur[3], &h[3])) break;
if (!PackedCol_Unhex(ctx->cur[0], &h[0])) break;
if (!PackedCol_Unhex(ctx->cur[1], &h[1])) break;
if (!PackedCol_Unhex(ctx->cur[2], &h[2])) break;
if (!PackedCol_Unhex(ctx->cur[3], &h[3])) break;
codepoint = (h[0] << 12) | (h[1] << 8) | (h[2] << 4) | h[3];
/* don't want control characters in names/software */
@ -98,13 +98,13 @@ static void Json_ConsumeString(struct JsonContext* ctx, String* str) {
JsonContext_Consume(ctx, 4);
}
ctx->Failed = true; str->length = 0;
ctx->failed = true; str->length = 0;
}
static String Json_ConsumeValue(int token, struct JsonContext* ctx);
static void Json_ConsumeObject(struct JsonContext* ctx) {
char keyBuffer[STRING_SIZE];
String value, oldKey = ctx->CurKey;
String value, oldKey = ctx->curKey;
int token;
ctx->OnNewObject(ctx);
@ -113,19 +113,19 @@ static void Json_ConsumeObject(struct JsonContext* ctx) {
if (token == ',') continue;
if (token == '}') return;
if (token != '"') { ctx->Failed = true; return; }
String_InitArray(ctx->CurKey, keyBuffer);
Json_ConsumeString(ctx, &ctx->CurKey);
if (token != '"') { ctx->failed = true; return; }
String_InitArray(ctx->curKey, keyBuffer);
Json_ConsumeString(ctx, &ctx->curKey);
token = Json_ConsumeToken(ctx);
if (token != ':') { ctx->Failed = true; return; }
if (token != ':') { ctx->failed = true; return; }
token = Json_ConsumeToken(ctx);
if (token == TOKEN_NONE) { ctx->Failed = true; return; }
if (token == TOKEN_NONE) { ctx->failed = true; return; }
value = Json_ConsumeValue(token, ctx);
ctx->OnValue(ctx, &value);
ctx->CurKey = oldKey;
ctx->curKey = oldKey;
}
}
@ -139,7 +139,7 @@ static void Json_ConsumeArray(struct JsonContext* ctx) {
if (token == ',') continue;
if (token == ']') return;
if (token == TOKEN_NONE) { ctx->Failed = true; return; }
if (token == TOKEN_NONE) { ctx->failed = true; return; }
value = Json_ConsumeValue(token, ctx);
ctx->OnValue(ctx, &value);
}
@ -162,10 +162,10 @@ static String Json_ConsumeValue(int token, struct JsonContext* ctx) {
static void Json_NullOnNew(struct JsonContext* ctx) { }
static void Json_NullOnValue(struct JsonContext* ctx, const String* v) { }
void Json_Init(struct JsonContext* ctx, String* str) {
ctx->Cur = str->buffer;
ctx->Left = str->length;
ctx->Failed = false;
ctx->CurKey = String_Empty;
ctx->cur = str->buffer;
ctx->left = str->length;
ctx->failed = false;
ctx->curKey = String_Empty;
ctx->OnNewArray = Json_NullOnNew;
ctx->OnNewObject = Json_NullOnNew;
@ -226,6 +226,18 @@ void LWebTask_Tick(struct LWebTask* task) {
HttpRequest_Free(&req);
}
void LWebTask_DisplayError(struct LWebTask* task, const char* action, String* dst) {
if (task->Res) {
/* Non HTTP error - this is not good */
Logger_SysWarn(task->Res, action, Http_DescribeError);
String_Format2(dst, "&cError %i when %c", &task->Res, action);
} else if (task->Status != 200) {
String_Format2(dst, "&c%i error when %c", &task->Status, action);
} else {
String_Format1(dst, "&cEmpty response when %c", action);
}
}
/*########################################################################################################################*
*-------------------------------------------------------GetTokenTask------------------------------------------------------*
@ -234,7 +246,7 @@ struct GetTokenTaskData GetTokenTask;
char tokenBuffer[STRING_SIZE];
static void GetTokenTask_OnValue(struct JsonContext* ctx, const String* str) {
if (!String_CaselessEqualsConst(&ctx->CurKey, "token")) return;
if (!String_CaselessEqualsConst(&ctx->curKey, "token")) return;
String_Copy(&GetTokenTask.Token, str);
}
@ -277,9 +289,9 @@ static void SignInTask_LogError(const String* str) {
}
static void SignInTask_OnValue(struct JsonContext* ctx, const String* str) {
if (String_CaselessEqualsConst(&ctx->CurKey, "username")) {
if (String_CaselessEqualsConst(&ctx->curKey, "username")) {
String_Copy(&SignInTask.Username, str);
} else if (String_CaselessEqualsConst(&ctx->CurKey, "errors")) {
} else if (String_CaselessEqualsConst(&ctx->curKey, "errors")) {
SignInTask_LogError(str);
}
}
@ -321,46 +333,46 @@ struct FetchServerData FetchServerTask;
static struct ServerInfo* curServer;
static void ServerInfo_Init(struct ServerInfo* info) {
String_InitArray(info->Hash, info->_hashBuffer);
String_InitArray(info->Name, info->_nameBuffer);
String_InitArray(info->IP, info->_ipBuffer);
String_InitArray(info->hash, info->_hashBuffer);
String_InitArray(info->name, info->_nameBuffer);
String_InitArray(info->ip, info->_ipBuffer);
String_InitArray(info->Mppass, info->_mppassBuffer);
String_InitArray(info->Software, info->_softBuffer);
String_InitArray(info->Country, info->_countryBuffer);
String_InitArray(info->mppass, info->_mppassBuffer);
String_InitArray(info->software, info->_softBuffer);
String_InitArray(info->country, info->_countryBuffer);
info->Players = 0;
info->MaxPlayers = 0;
info->Uptime = 0;
info->Featured = false;
info->players = 0;
info->maxPlayers = 0;
info->uptime = 0;
info->featured = false;
info->_order = -100000;
}
static void ServerInfo_Parse(struct JsonContext* ctx, const String* val) {
struct ServerInfo* info = curServer;
if (String_CaselessEqualsConst(&ctx->CurKey, "hash")) {
String_Copy(&info->Hash, val);
} else if (String_CaselessEqualsConst(&ctx->CurKey, "name")) {
String_Copy(&info->Name, val);
} else if (String_CaselessEqualsConst(&ctx->CurKey, "players")) {
Convert_ParseInt(val, &info->Players);
} else if (String_CaselessEqualsConst(&ctx->CurKey, "maxplayers")) {
Convert_ParseInt(val, &info->MaxPlayers);
} else if (String_CaselessEqualsConst(&ctx->CurKey, "uptime")) {
Convert_ParseInt(val, &info->Uptime);
} else if (String_CaselessEqualsConst(&ctx->CurKey, "mppass")) {
String_Copy(&info->Mppass, val);
} else if (String_CaselessEqualsConst(&ctx->CurKey, "ip")) {
String_Copy(&info->IP, val);
} else if (String_CaselessEqualsConst(&ctx->CurKey, "port")) {
Convert_ParseInt(val, &info->Port);
} else if (String_CaselessEqualsConst(&ctx->CurKey, "software")) {
String_Copy(&info->Software, val);
} else if (String_CaselessEqualsConst(&ctx->CurKey, "featured")) {
Convert_ParseBool(val, &info->Featured);
} else if (String_CaselessEqualsConst(&ctx->CurKey, "country_abbr")) {
if (String_CaselessEqualsConst(&ctx->curKey, "hash")) {
String_Copy(&info->hash, val);
} else if (String_CaselessEqualsConst(&ctx->curKey, "name")) {
String_Copy(&info->name, val);
} else if (String_CaselessEqualsConst(&ctx->curKey, "players")) {
Convert_ParseInt(val, &info->players);
} else if (String_CaselessEqualsConst(&ctx->curKey, "maxplayers")) {
Convert_ParseInt(val, &info->maxPlayers);
} else if (String_CaselessEqualsConst(&ctx->curKey, "uptime")) {
Convert_ParseInt(val, &info->uptime);
} else if (String_CaselessEqualsConst(&ctx->curKey, "mppass")) {
String_Copy(&info->mppass, val);
} else if (String_CaselessEqualsConst(&ctx->curKey, "ip")) {
String_Copy(&info->ip, val);
} else if (String_CaselessEqualsConst(&ctx->curKey, "port")) {
Convert_ParseInt(val, &info->port);
} else if (String_CaselessEqualsConst(&ctx->curKey, "software")) {
String_Copy(&info->software, val);
} else if (String_CaselessEqualsConst(&ctx->curKey, "featured")) {
Convert_ParseBool(val, &info->featured);
} else if (String_CaselessEqualsConst(&ctx->curKey, "country_abbr")) {
/* Two letter country codes, see ISO 3166-1 alpha-2 */
String_Copy(&info->Country, val);
String_Copy(&info->country, val);
}
}
@ -460,11 +472,11 @@ CC_NOINLINE static TimeMS CheckUpdateTask_ParseTime(const String* str) {
}
static void CheckUpdateTask_OnValue(struct JsonContext* ctx, const String* str) {
if (String_CaselessEqualsConst(&ctx->CurKey, "release_version")) {
if (String_CaselessEqualsConst(&ctx->curKey, "release_version")) {
String_Copy(&CheckUpdateTask.LatestRelease, str);
} else if (String_CaselessEqualsConst(&ctx->CurKey, "latest_ts")) {
} else if (String_CaselessEqualsConst(&ctx->curKey, "latest_ts")) {
CheckUpdateTask.DevTimestamp = CheckUpdateTask_ParseTime(str);
} else if (String_CaselessEqualsConst(&ctx->CurKey, "release_ts")) {
} else if (String_CaselessEqualsConst(&ctx->curKey, "release_ts")) {
CheckUpdateTask.RelTimestamp = CheckUpdateTask_ParseTime(str);
}
}

View File

@ -12,10 +12,10 @@ typedef void (*JsonOnNew)(struct JsonContext* ctx);
/* State for parsing JSON text */
struct JsonContext {
char* Cur; /* Pointer to current character in JSON stream being inspected. */
int Left; /* Number of characters left to be inspected. */
bool Failed; /* Whether there was an error parsing the JSON. */
String CurKey; /* Key/Name of current member */
char* cur; /* Pointer to current character in JSON stream being inspected. */
int left; /* Number of characters left to be inspected. */
bool failed; /* Whether there was an error parsing the JSON. */
String curKey; /* Key/Name of current member */
JsonOnNew OnNewArray; /* Invoked when start of an array is read. */
JsonOnNew OnNewObject; /* Invoked when start of an object is read. */
@ -31,9 +31,9 @@ void Json_Parse(struct JsonContext* ctx);
/* Represents all known details about a server. */
struct ServerInfo {
String Hash, Name, IP, Mppass, Software, Country;
int Players, MaxPlayers, Port, Uptime;
bool Featured;
String hash, name, ip, mppass, software, country;
int players, maxPlayers, port, uptime;
bool featured;
int _order; /* (internal) order in servers table after filtering */
char _hashBuffer[32], _nameBuffer[STRING_SIZE];
char _ipBuffer[16], _mppassBuffer[STRING_SIZE];
@ -55,6 +55,7 @@ struct LWebTask {
void (*Handle)(uint8_t* data, uint32_t len);
};
void LWebTask_Tick(struct LWebTask* task);
void LWebTask_DisplayError(struct LWebTask* task, const char* action, String* dst);
extern struct GetTokenTaskData {

View File

@ -634,26 +634,26 @@ void LSlider_Init(struct LSlider* w, int width, int height) {
*------------------------------------------------------TableWidget--------------------------------------------------------*
*#########################################################################################################################*/
static void FlagColumn_Draw(struct ServerInfo* row, struct DrawTextArgs* args, int x, int y) {
Bitmap* bmp = Flags_Get(&row->Country);
Bitmap* bmp = Flags_Get(&row->country);
if (bmp) Drawer2D_BmpCopy(&Launcher_Framebuffer, x + 2, y + 6, bmp);
}
static void NameColumn_Draw(struct ServerInfo* row, struct DrawTextArgs* args, int x, int y) {
args->text = row->Name;
args->text = row->name;
}
static int NameColumn_Sort(const struct ServerInfo* a, const struct ServerInfo* b) {
return String_Compare(&b->Name, &a->Name);
return String_Compare(&b->name, &a->name);
}
static void PlayersColumn_Draw(struct ServerInfo* row, struct DrawTextArgs* args, int x, int y) {
String_Format2(&args->text, "%i/%i", &row->Players, &row->MaxPlayers);
String_Format2(&args->text, "%i/%i", &row->players, &row->maxPlayers);
}
static int PlayersColumn_Sort(const struct ServerInfo* a, const struct ServerInfo* b) {
return b->Players - a->Players;
return b->players - a->players;
}
static void UptimeColumn_Draw(struct ServerInfo* row, struct DrawTextArgs* args, int x, int y) {
int uptime = row->Uptime;
int uptime = row->uptime;
char unit = 's';
if (uptime >= SECS_PER_DAY * 7) {
@ -666,14 +666,14 @@ static void UptimeColumn_Draw(struct ServerInfo* row, struct DrawTextArgs* args,
String_Format2(&args->text, "%i%r", &uptime, &unit);
}
static int UptimeColumn_Sort(const struct ServerInfo* a, const struct ServerInfo* b) {
return b->Uptime - a->Uptime;
return b->uptime - a->uptime;
}
static void SoftwareColumn_Draw(struct ServerInfo* row, struct DrawTextArgs* args, int x, int y) {
args->text = row->Software;
args->text = row->software;
}
static int SoftwareColumn_Sort(const struct ServerInfo* a, const struct ServerInfo* b) {
return String_Compare(&b->Software, &a->Software);
return String_Compare(&b->software, &a->software);
}
static struct LTableColumn tableColumns[5] = {
@ -712,7 +712,7 @@ static int LTable_GetSelectedIndex(struct LTable* w) {
for (row = 0; row < w->RowsCount; row++) {
entry = LTable_Get(row);
if (String_CaselessEquals(w->SelectedHash, &entry->Hash)) return row;
if (String_CaselessEquals(w->SelectedHash, &entry->hash)) return row;
}
return -1;
}
@ -723,7 +723,7 @@ static void LTable_SetSelectedTo(struct LTable* w, int index) {
if (index >= w->RowsCount) index = w->RowsCount - 1;
if (index < 0) index = 0;
String_Copy(w->SelectedHash, &LTable_Get(index)->Hash);
String_Copy(w->SelectedHash, &LTable_Get(index)->hash);
LTable_ShowSelected(w);
w->OnSelectedChanged();
}
@ -759,8 +759,8 @@ static BitmapCol LTable_RowCol(struct LTable* w, struct ServerInfo* row) {
bool selected;
if (row) {
selected = String_Equals(&row->Hash, w->SelectedHash);
if (row->Featured) {
selected = String_Equals(&row->hash, w->SelectedHash);
if (row->featured) {
return selected ? featSelCol : featuredCol;
} else if (selected) {
return selectedCol;
@ -804,8 +804,8 @@ static void LTable_DrawGridlines(struct LTable* w) {
x, w->Y + w->HdrHeight, w->Width, GRIDLINE_SIZE);
for (i = 0; i < w->NumColumns; i++) {
x += w->Columns[i].Width;
if (!w->Columns[i].ColumnGridline) continue;
x += w->Columns[i].width;
if (!w->Columns[i].columnGridline) continue;
Drawer2D_Clear(&Launcher_Framebuffer, Launcher_BackgroundCol,
x, w->Y, GRIDLINE_SIZE, w->Height);
@ -829,13 +829,13 @@ static void LTable_DrawHeaders(struct LTable* w) {
x = w->X; y = w->Y;
for (i = 0; i < w->NumColumns; i++) {
args.text = String_FromReadonly(w->Columns[i].Name);
args.text = String_FromReadonly(w->Columns[i].name);
Drawer2D_DrawClippedText(&Launcher_Framebuffer, &args,
x + CELL_XOFFSET, y + HDR_YOFFSET,
w->Columns[i].Width - CELL_XPADDING);
w->Columns[i].width - CELL_XPADDING);
x += w->Columns[i].Width;
if (w->Columns[i].ColumnGridline) x += GRIDLINE_SIZE;
x += w->Columns[i].width;
if (w->Columns[i].columnGridline) x += GRIDLINE_SIZE;
}
}
@ -865,11 +865,11 @@ static void LTable_DrawRows(struct LTable* w) {
if (args.text.length) {
Drawer2D_DrawClippedText(&Launcher_Framebuffer, &args,
x + CELL_XOFFSET, y + ROW_YOFFSET,
w->Columns[i].Width - CELL_XPADDING);
w->Columns[i].width - CELL_XPADDING);
}
x += w->Columns[i].Width;
if (w->Columns[i].ColumnGridline) x += GRIDLINE_SIZE;
x += w->Columns[i].width;
if (w->Columns[i].columnGridline) x += GRIDLINE_SIZE;
}
}
}
@ -930,8 +930,8 @@ static void LTable_MouseMove(void* widget, int deltaX, int deltaY, bool wasOver)
if (!deltaX || x >= w->X + w->Width - 20) return;
col = w->DraggingColumn;
w->Columns[col].Width += deltaX;
Math_Clamp(w->Columns[col].Width, 20, w->Width - 20);
w->Columns[col].width += deltaX;
Math_Clamp(w->Columns[col].width, 20, w->Width - 20);
LWidget_Redraw(w);
}
}
@ -946,7 +946,7 @@ static void LTable_RowsClick(struct LTable* w) {
/* double click on row to join */
if (w->_lastClick + 1000 >= now && row == w->_lastRow) {
Launcher_ConnectToServer(&LTable_Get(row)->Hash);
Launcher_ConnectToServer(&LTable_Get(row)->hash);
}
w->_lastRow = LTable_GetSelectedIndex(w);
@ -959,25 +959,25 @@ static void LTable_HeadersClick(struct LTable* w) {
for (i = 0, x = w->X; i < w->NumColumns; i++) {
/* clicked on gridline, begin dragging */
if (mouseX >= (x - 8) && mouseX < (x + 8) && w->Columns[i].Interactable) {
if (mouseX >= (x - 8) && mouseX < (x + 8) && w->Columns[i].interactable) {
w->DraggingColumn = i - 1;
return;
}
x += w->Columns[i].Width;
if (w->Columns[i].ColumnGridline) x += GRIDLINE_SIZE;
x += w->Columns[i].width;
if (w->Columns[i].columnGridline) x += GRIDLINE_SIZE;
}
for (i = 0, x = w->X; i < w->NumColumns; i++) {
if (mouseX >= x && mouseX < (x + w->Columns[i].Width) && w->Columns[i].Interactable) {
if (mouseX >= x && mouseX < (x + w->Columns[i].width) && w->Columns[i].interactable) {
sortingCol = i;
w->Columns[i].InvertSort = !w->Columns[i].InvertSort;
w->Columns[i].invertSort = !w->Columns[i].invertSort;
LTable_Sort(w);
return;
}
x += w->Columns[i].Width;
if (w->Columns[i].ColumnGridline) x += GRIDLINE_SIZE;
x += w->Columns[i].width;
if (w->Columns[i].columnGridline) x += GRIDLINE_SIZE;
}
}
@ -1085,7 +1085,7 @@ void LTable_ApplyFilter(struct LTable* w) {
count = FetchServersTask.NumServers;
for (i = 0, j = 0; i < count; i++) {
if (String_CaselessContains(&Servers_Get(i)->Name, w->Filter)) {
if (String_CaselessContains(&Servers_Get(i)->name, w->Filter)) {
FetchServersTask.Servers[j++]._order = FetchServersTask.Orders[i];
}
}
@ -1103,12 +1103,12 @@ static int LTable_SortOrder(const struct ServerInfo* a, const struct ServerInfo*
int order;
if (sortingCol >= 0) {
order = tableColumns[sortingCol].SortOrder(a, b);
return tableColumns[sortingCol].InvertSort ? -order : order;
return tableColumns[sortingCol].invertSort ? -order : order;
}
/* Default sort order. (most active server, then by highest uptime) */
if (a->Players != b->Players) return a->Players - b->Players;
return a->Uptime - b->Uptime;
if (a->players != b->players) return a->players - b->players;
return a->uptime - b->uptime;
}
static void LTable_QuickSort(int left, int right) {

View File

@ -116,9 +116,9 @@ struct DrawTextArgs;
struct LTableColumn {
/* Name of this column. */
const char* Name;
const char* name;
/* Width of this column in pixels. */
int Width;
int width;
/* Draws the value of this column for the given row. */
/* If args.Text is changed to something, that text gets drawn afterwards. */
/* Most of the time that's all you need to do. */
@ -126,12 +126,12 @@ struct LTableColumn {
/* Returns sort order of two rows, based on value of this column in both rows. */
int (*SortOrder)(const struct ServerInfo* a, const struct ServerInfo* b);
/* Whether a vertical gridline (and padding) appears after this. */
bool ColumnGridline;
bool columnGridline;
/* Whether user can interact with this column. */
/* Non-interactable columns can't be sorted/resized. */
bool Interactable;
bool interactable;
/* Whether to invert the order of row sorting. */
bool InvertSort;
bool invertSort;
};
/* Represents a table of server entries. */

View File

@ -45,18 +45,19 @@ CC_NOINLINE static void Launcher_StartFromInfo(struct ServerInfo* info) {
String port; char portBuffer[STRING_INT_CHARS];
String_InitArray(port, portBuffer);
String_AppendInt(&port, info->Port);
Launcher_StartGame(&SignInTask.Username, &info->Mppass, &info->IP, &port, &info->Name);
String_AppendInt(&port, info->port);
Launcher_StartGame(&SignInTask.Username, &info->mppass, &info->ip, &port, &info->name);
}
bool Launcher_ConnectToServer(const String* hash) {
int i;
struct ServerInfo* info;
String logMsg;
int i;
if (!hash->length) return false;
for (i = 0; i < FetchServersTask.NumServers; i++) {
info = &FetchServersTask.Servers[i];
if (!String_Equals(hash, &info->Hash)) continue;
if (!String_Equals(hash, &info->hash)) continue;
Launcher_StartFromInfo(info);
return true;
@ -71,18 +72,16 @@ bool Launcher_ConnectToServer(const String* hash) {
Thread_Sleep(10);
}
if (FetchServerTask.Server.Hash.length) {
if (FetchServerTask.Server.hash.length) {
Launcher_StartFromInfo(&FetchServerTask.Server);
return true;
} else if (FetchServerTask.Base.Res) {
Logger_SimpleWarn(FetchServerTask.Base.Res, "fetching server info");
} else if (FetchServerTask.Base.Status != 200) {
/* TODO: Use a better dialog message.. */
Logger_SimpleWarn(FetchServerTask.Base.Status, "fetching server info");
} else {
} else if (FetchServerTask.Base.Success) {
Window_ShowDialog("Failed to connect", "No server has that hash");
} else {
logMsg = String_Init(NULL, 0, 0);
LWebTask_DisplayError(&FetchServerTask.Base, "fetching server info", &logMsg);
}
return true;
return false;
}

View File

@ -60,7 +60,7 @@ static void Server_CheckAsyncResources(void) {
TexturePack_Extract_Req(&item);
HttpRequest_Free(&item);
} else if (item.Result) {
Chat_Add1("&cError %i when trying to download texture pack", &item.Result);
Logger_SysWarn(item.Result, "trying to download texture pack", Http_DescribeError);
} else {
int status = item.StatusCode;
if (status == 200 || status == 304) return;