Merge branch 'save_ext' into enhanced_viewport_overlay-sx
This commit is contained in:
@@ -63,7 +63,6 @@ NetworkCompanyState *_network_company_states = NULL; ///< Statistics about some
|
||||
ClientID _network_own_client_id; ///< Our client identifier.
|
||||
ClientID _redirect_console_to_client; ///< If not invalid, redirect the console output to a client.
|
||||
bool _network_need_advertise; ///< Whether we need to advertise.
|
||||
uint32 _network_last_advertise_frame; ///< Last time we did advertise.
|
||||
uint8 _network_reconnect; ///< Reconnect timeout
|
||||
StringList _network_bind_list; ///< The addresses to bind on.
|
||||
StringList _network_host_list; ///< The servers we know.
|
||||
@@ -759,7 +758,6 @@ bool NetworkServerStart()
|
||||
if (_network_dedicated) IConsoleCmdExec("exec scripts/on_dedicated.scr 0");
|
||||
|
||||
/* Try to register us to the master server */
|
||||
_network_last_advertise_frame = 0;
|
||||
_network_need_advertise = true;
|
||||
NetworkUDPAdvertise();
|
||||
|
||||
@@ -1076,7 +1074,6 @@ void NetworkStartUp()
|
||||
/* Network is available */
|
||||
_network_available = NetworkCoreInitialize();
|
||||
_network_dedicated = false;
|
||||
_network_last_advertise_frame = 0;
|
||||
_network_need_advertise = true;
|
||||
_network_advertise_retries = 0;
|
||||
|
||||
|
@@ -282,10 +282,22 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/** Filter data for NetworkContentListWindow. */
|
||||
struct ContentListFilterData {
|
||||
StringFilter string_filter; ///< Text filter of content list
|
||||
ContentType type; ///< Content type displayed
|
||||
};
|
||||
|
||||
/** Filter criterias for NetworkContentListWindow. */
|
||||
enum ContentListFilterCriteria {
|
||||
CONTENT_FILTER_TEXT = 0, ///< Filter by query sting
|
||||
CONTENT_FILTER_TYPE_OR_SELECTED,///< Filter by being of displayed type or selected for download
|
||||
};
|
||||
|
||||
/** Window that lists the content that's at the content server */
|
||||
class NetworkContentListWindow : public Window, ContentCallback {
|
||||
/** List with content infos. */
|
||||
typedef GUIList<const ContentInfo *, StringFilter &> GUIContentList;
|
||||
typedef GUIList<const ContentInfo *, ContentListFilterData &> GUIContentList;
|
||||
|
||||
static const uint EDITBOX_MAX_SIZE = 50; ///< Maximum size of the editbox in characters.
|
||||
|
||||
@@ -295,7 +307,7 @@ class NetworkContentListWindow : public Window, ContentCallback {
|
||||
static GUIContentList::FilterFunction * const filter_funcs[]; ///< Filter functions.
|
||||
GUIContentList content; ///< List with content
|
||||
bool auto_select; ///< Automatically select all content when the meta-data becomes available
|
||||
StringFilter string_filter; ///< Filter for content list
|
||||
ContentListFilterData filter_data; ///< Filter for content list
|
||||
QueryString filter_editbox; ///< Filter editbox;
|
||||
Dimension checkbox_size; ///< Size of checkbox/"blot" sprite
|
||||
|
||||
@@ -431,20 +443,38 @@ class NetworkContentListWindow : public Window, ContentCallback {
|
||||
}
|
||||
|
||||
/** Filter content by tags/name */
|
||||
static bool CDECL TagNameFilter(const ContentInfo * const *a, StringFilter &filter)
|
||||
static bool CDECL TagNameFilter(const ContentInfo * const *a, ContentListFilterData &filter)
|
||||
{
|
||||
filter.ResetState();
|
||||
filter.string_filter.ResetState();
|
||||
for (int i = 0; i < (*a)->tag_count; i++) {
|
||||
filter.AddLine((*a)->tags[i]);
|
||||
filter.string_filter.AddLine((*a)->tags[i]);
|
||||
}
|
||||
filter.AddLine((*a)->name);
|
||||
return filter.GetState();
|
||||
filter.string_filter.AddLine((*a)->name);
|
||||
return filter.string_filter.GetState();
|
||||
}
|
||||
|
||||
/** Filter content by type, but still show content selected for download. */
|
||||
static bool CDECL TypeOrSelectedFilter(const ContentInfo * const *a, ContentListFilterData &filter)
|
||||
{
|
||||
if (filter.type == CONTENT_TYPE_END) return true;
|
||||
if ((*a)->type == filter.type) return true;
|
||||
return ((*a)->state == ContentInfo::SELECTED || (*a)->state == ContentInfo::AUTOSELECTED);
|
||||
}
|
||||
|
||||
/** Filter the content list */
|
||||
void FilterContentList()
|
||||
{
|
||||
if (!this->content.Filter(this->string_filter)) return;
|
||||
/* Apply filters. */
|
||||
bool changed = false;
|
||||
if (!this->filter_data.string_filter.IsEmpty()) {
|
||||
this->content.SetFilterType(CONTENT_FILTER_TEXT);
|
||||
changed |= this->content.Filter(this->filter_data);
|
||||
}
|
||||
if (this->filter_data.type != CONTENT_TYPE_END) {
|
||||
this->content.SetFilterType(CONTENT_FILTER_TYPE_OR_SELECTED);
|
||||
changed |= this->content.Filter(this->filter_data);
|
||||
}
|
||||
if (!changed) return;
|
||||
|
||||
/* update list position */
|
||||
for (ConstContentIterator iter = this->content.Begin(); iter != this->content.End(); iter++) {
|
||||
@@ -459,6 +489,20 @@ class NetworkContentListWindow : public Window, ContentCallback {
|
||||
this->list_pos = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update filter state based on current window state.
|
||||
* @return true if filter state was changed, otherwise false.
|
||||
*/
|
||||
bool UpdateFilterState()
|
||||
{
|
||||
Filtering old_params = this->content.GetFiltering();
|
||||
bool new_state = !this->filter_data.string_filter.IsEmpty() || this->filter_data.type != CONTENT_TYPE_END;
|
||||
if (new_state != old_params.state) {
|
||||
this->content.SetFilterState(new_state);
|
||||
}
|
||||
return new_state != old_params.state;
|
||||
}
|
||||
|
||||
/** Make sure that the currently selected content info is within the visible part of the matrix */
|
||||
void ScrollToSelected()
|
||||
{
|
||||
@@ -473,8 +517,12 @@ public:
|
||||
* Create the content list window.
|
||||
* @param desc the window description to pass to Window's constructor.
|
||||
* @param select_all Whether the select all button is allowed or not.
|
||||
* @param type the main type of content to display or #CONTENT_TYPE_END.
|
||||
* When a type other than #CONTENT_TYPE_END is given, dependencies of
|
||||
* other types are only shown when content that depend on them are
|
||||
* selected.
|
||||
*/
|
||||
NetworkContentListWindow(WindowDesc *desc, bool select_all) :
|
||||
NetworkContentListWindow(WindowDesc *desc, bool select_all, ContentType type) :
|
||||
Window(desc),
|
||||
auto_select(select_all),
|
||||
filter_editbox(EDITBOX_MAX_SIZE),
|
||||
@@ -493,12 +541,14 @@ public:
|
||||
this->filter_editbox.cancel_button = QueryString::ACTION_CLEAR;
|
||||
this->SetFocusedWidget(WID_NCL_FILTER);
|
||||
this->SetWidgetDisabledState(WID_NCL_SEARCH_EXTERNAL, this->auto_select);
|
||||
this->filter_data.type = type;
|
||||
|
||||
_network_content_client.AddCallback(this);
|
||||
this->content.SetListing(this->last_sorting);
|
||||
this->content.SetFiltering(this->last_filtering);
|
||||
this->content.SetSortFuncs(this->sorter_funcs);
|
||||
this->content.SetFilterFuncs(this->filter_funcs);
|
||||
this->UpdateFilterState();
|
||||
this->content.ForceRebuild();
|
||||
this->FilterContentList();
|
||||
this->SortContentList();
|
||||
@@ -751,6 +801,10 @@ public:
|
||||
this->content.ForceResort();
|
||||
}
|
||||
|
||||
if (this->filter_data.type != CONTENT_TYPE_END) {
|
||||
this->content.ForceRebuild();
|
||||
}
|
||||
|
||||
this->InvalidateData();
|
||||
break;
|
||||
}
|
||||
@@ -846,9 +900,13 @@ public:
|
||||
this->content.ForceResort();
|
||||
this->InvalidateData();
|
||||
}
|
||||
if (this->filter_data.type != CONTENT_TYPE_END) {
|
||||
this->content.ForceRebuild();
|
||||
this->InvalidateData();
|
||||
}
|
||||
return ES_HANDLED;
|
||||
}
|
||||
/* FALL THROUGH, space is pressed and filter isn't focused. */
|
||||
/* FALL THROUGH, space is pressed and filter is focused. */
|
||||
|
||||
default:
|
||||
return ES_NOT_HANDLED;
|
||||
@@ -856,13 +914,21 @@ public:
|
||||
|
||||
if (this->content.Length() == 0) {
|
||||
this->list_pos = 0; // above stuff may result in "-1".
|
||||
if (this->UpdateFilterState()) {
|
||||
this->content.ForceRebuild();
|
||||
this->InvalidateData();
|
||||
}
|
||||
return ES_HANDLED;
|
||||
}
|
||||
|
||||
this->selected = *this->content.Get(this->list_pos);
|
||||
|
||||
/* scroll to the new server if it is outside the current range */
|
||||
this->ScrollToSelected();
|
||||
if (this->UpdateFilterState()) {
|
||||
this->content.ForceRebuild();
|
||||
} else {
|
||||
/* Scroll to the new content if it is outside the current range. */
|
||||
this->ScrollToSelected();
|
||||
}
|
||||
|
||||
/* redraw window */
|
||||
this->InvalidateData();
|
||||
@@ -872,8 +938,8 @@ public:
|
||||
virtual void OnEditboxChanged(int wid)
|
||||
{
|
||||
if (wid == WID_NCL_FILTER) {
|
||||
this->string_filter.SetFilterTerm(this->filter_editbox.text.buf);
|
||||
this->content.SetFilterState(!this->string_filter.IsEmpty());
|
||||
this->filter_data.string_filter.SetFilterTerm(this->filter_editbox.text.buf);
|
||||
this->UpdateFilterState();
|
||||
this->content.ForceRebuild();
|
||||
this->InvalidateData();
|
||||
}
|
||||
@@ -965,6 +1031,7 @@ NetworkContentListWindow::GUIContentList::SortFunction * const NetworkContentLis
|
||||
|
||||
NetworkContentListWindow::GUIContentList::FilterFunction * const NetworkContentListWindow::filter_funcs[] = {
|
||||
&TagNameFilter,
|
||||
&TypeOrSelectedFilter,
|
||||
};
|
||||
|
||||
char NetworkContentListWindow::content_type_strs[CONTENT_TYPE_END][64];
|
||||
@@ -1080,7 +1147,7 @@ void ShowNetworkContentListWindow(ContentVector *cv, ContentType type)
|
||||
}
|
||||
|
||||
DeleteWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_CONTENT_LIST);
|
||||
new NetworkContentListWindow(&_network_content_list_desc, cv != NULL);
|
||||
new NetworkContentListWindow(&_network_content_list_desc, cv != NULL, type);
|
||||
#else
|
||||
ShowErrorMessage(STR_CONTENT_NO_ZLIB, STR_CONTENT_NO_ZLIB_SUB, WL_ERROR);
|
||||
/* Connection failed... clean up the mess */
|
||||
|
@@ -34,7 +34,6 @@ extern NetworkCompanyState *_network_company_states;
|
||||
extern ClientID _network_own_client_id;
|
||||
extern ClientID _redirect_console_to_client;
|
||||
extern bool _network_need_advertise;
|
||||
extern uint32 _network_last_advertise_frame;
|
||||
extern uint8 _network_reconnect;
|
||||
extern StringList _network_bind_list;
|
||||
extern StringList _network_host_list;
|
||||
|
@@ -1863,7 +1863,9 @@ struct NetworkClientListWindow : Window {
|
||||
int selected_item;
|
||||
|
||||
uint server_client_width;
|
||||
uint company_icon_width;
|
||||
uint line_height;
|
||||
|
||||
Dimension icon_size;
|
||||
|
||||
NetworkClientListWindow(WindowDesc *desc, WindowNumber window_number) :
|
||||
Window(desc),
|
||||
@@ -1885,7 +1887,7 @@ struct NetworkClientListWindow : Window {
|
||||
if (ci->client_playas != COMPANY_INACTIVE_CLIENT) num++;
|
||||
}
|
||||
|
||||
num *= FONT_HEIGHT_NORMAL;
|
||||
num *= this->line_height;
|
||||
|
||||
int diff = (num + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM) - (this->GetWidget<NWidgetBase>(WID_CL_PANEL)->current_y);
|
||||
/* If height is changed */
|
||||
@@ -1901,7 +1903,8 @@ struct NetworkClientListWindow : Window {
|
||||
if (widget != WID_CL_PANEL) return;
|
||||
|
||||
this->server_client_width = max(GetStringBoundingBox(STR_NETWORK_SERVER).width, GetStringBoundingBox(STR_NETWORK_CLIENT).width) + WD_FRAMERECT_RIGHT;
|
||||
this->company_icon_width = GetSpriteSize(SPR_COMPANY_ICON).width + WD_FRAMERECT_LEFT;
|
||||
this->icon_size = GetSpriteSize(SPR_COMPANY_ICON);
|
||||
this->line_height = max(this->icon_size.height + 2U, (uint)FONT_HEIGHT_NORMAL);
|
||||
|
||||
uint width = 100; // Default width
|
||||
const NetworkClientInfo *ci;
|
||||
@@ -1909,7 +1912,7 @@ struct NetworkClientListWindow : Window {
|
||||
width = max(width, GetStringBoundingBox(ci->client_name).width);
|
||||
}
|
||||
|
||||
size->width = WD_FRAMERECT_LEFT + this->server_client_width + this->company_icon_width + width + WD_FRAMERECT_RIGHT;
|
||||
size->width = WD_FRAMERECT_LEFT + this->server_client_width + this->icon_size.width + WD_FRAMERECT_LEFT + width + WD_FRAMERECT_RIGHT;
|
||||
}
|
||||
|
||||
virtual void OnPaint()
|
||||
@@ -1925,11 +1928,13 @@ struct NetworkClientListWindow : Window {
|
||||
if (widget != WID_CL_PANEL) return;
|
||||
|
||||
bool rtl = _current_text_dir == TD_RTL;
|
||||
int icon_y_offset = 1 + (FONT_HEIGHT_NORMAL - 10) / 2;
|
||||
int icon_offset = (this->line_height - icon_size.height) / 2;
|
||||
int text_offset = (this->line_height - FONT_HEIGHT_NORMAL) / 2;
|
||||
|
||||
uint y = r.top + WD_FRAMERECT_TOP;
|
||||
uint left = r.left + WD_FRAMERECT_LEFT;
|
||||
uint right = r.right - WD_FRAMERECT_RIGHT;
|
||||
uint type_icon_width = this->server_client_width + this->company_icon_width;
|
||||
uint type_icon_width = this->server_client_width + this->icon_size.width + WD_FRAMERECT_LEFT;
|
||||
|
||||
|
||||
uint type_left = rtl ? right - this->server_client_width : left;
|
||||
@@ -1943,24 +1948,24 @@ struct NetworkClientListWindow : Window {
|
||||
FOR_ALL_CLIENT_INFOS(ci) {
|
||||
TextColour colour;
|
||||
if (this->selected_item == i++) { // Selected item, highlight it
|
||||
GfxFillRect(r.left + 1, y, r.right - 1, y + FONT_HEIGHT_NORMAL - 1, PC_BLACK);
|
||||
GfxFillRect(r.left + 1, y, r.right - 1, y + this->line_height - 1, PC_BLACK);
|
||||
colour = TC_WHITE;
|
||||
} else {
|
||||
colour = TC_BLACK;
|
||||
}
|
||||
|
||||
if (ci->client_id == CLIENT_ID_SERVER) {
|
||||
DrawString(type_left, type_right, y, STR_NETWORK_SERVER, colour);
|
||||
DrawString(type_left, type_right, y + text_offset, STR_NETWORK_SERVER, colour);
|
||||
} else {
|
||||
DrawString(type_left, type_right, y, STR_NETWORK_CLIENT, colour);
|
||||
DrawString(type_left, type_right, y + text_offset, STR_NETWORK_CLIENT, colour);
|
||||
}
|
||||
|
||||
/* Filter out spectators */
|
||||
if (Company::IsValidID(ci->client_playas)) DrawCompanyIcon(ci->client_playas, icon_left, y + icon_y_offset);
|
||||
if (Company::IsValidID(ci->client_playas)) DrawCompanyIcon(ci->client_playas, icon_left, y + icon_offset);
|
||||
|
||||
DrawString(name_left, name_right, y, ci->client_name, colour);
|
||||
DrawString(name_left, name_right, y + text_offset, ci->client_name, colour);
|
||||
|
||||
y += FONT_HEIGHT_NORMAL;
|
||||
y += line_height;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1993,7 +1998,7 @@ struct NetworkClientListWindow : Window {
|
||||
pt.y -= this->GetWidget<NWidgetBase>(WID_CL_PANEL)->pos_y;
|
||||
int item = -1;
|
||||
if (IsInsideMM(pt.y, WD_FRAMERECT_TOP, this->GetWidget<NWidgetBase>(WID_CL_PANEL)->current_y - WD_FRAMERECT_BOTTOM)) {
|
||||
item = (pt.y - WD_FRAMERECT_TOP) / FONT_HEIGHT_NORMAL;
|
||||
item = (pt.y - WD_FRAMERECT_TOP) / this->line_height;
|
||||
}
|
||||
|
||||
/* It did not change.. no update! */
|
||||
|
@@ -42,9 +42,9 @@ static ThreadMutex *_network_udp_mutex = ThreadMutex::New();
|
||||
/** Session key to register ourselves to the master server */
|
||||
static uint64 _session_key = 0;
|
||||
|
||||
static const uint ADVERTISE_NORMAL_INTERVAL = 30000; ///< interval between advertising in ticks (15 minutes)
|
||||
static const uint ADVERTISE_RETRY_INTERVAL = 300; ///< re-advertise when no response after this many ticks (9 seconds)
|
||||
static const uint ADVERTISE_RETRY_TIMES = 3; ///< give up re-advertising after this much failed retries
|
||||
static const uint32 ADVERTISE_NORMAL_INTERVAL = 15 * 60 * 1000; ///< interval between advertising in ms (15 minutes)
|
||||
static const uint32 ADVERTISE_RETRY_INTERVAL = 10 * 1000; ///< re-advertise when no response after this many ms (10 seconds)
|
||||
static const uint32 ADVERTISE_RETRY_TIMES = 3; ///< give up re-advertising after this much failed retries
|
||||
|
||||
NetworkUDPSocketHandler *_udp_client_socket = NULL; ///< udp client socket
|
||||
NetworkUDPSocketHandler *_udp_server_socket = NULL; ///< udp server socket
|
||||
@@ -616,25 +616,37 @@ static void NetworkUDPAdvertiseThread(void *pntr)
|
||||
*/
|
||||
void NetworkUDPAdvertise()
|
||||
{
|
||||
static uint32 _last_advertisement = 0; ///< The time of the last advertisement (used to check for wrapping of time)
|
||||
static uint32 _next_advertisement = 0; ///< The next time we should perform a normal advertisement.
|
||||
static uint32 _next_retry = 0; ///< The next time we should perform a retry of an advertisement.
|
||||
|
||||
/* Check if we should send an advertise */
|
||||
if (!_networking || !_network_server || !_network_udp_server || !_settings_client.network.server_advertise) return;
|
||||
|
||||
if (_network_need_advertise) {
|
||||
if (_network_need_advertise || _realtime_tick < _last_advertisement) {
|
||||
/* Forced advertisement, or a wrapping of time in which case we determine the advertisement/retry times again. */
|
||||
_network_need_advertise = false;
|
||||
_network_advertise_retries = ADVERTISE_RETRY_TIMES;
|
||||
} else {
|
||||
/* Only send once every ADVERTISE_NORMAL_INTERVAL ticks */
|
||||
if (_network_advertise_retries == 0) {
|
||||
if ((_network_last_advertise_frame + ADVERTISE_NORMAL_INTERVAL) > _frame_counter) return;
|
||||
if (_realtime_tick <= _next_advertisement) return;
|
||||
|
||||
_network_advertise_retries = ADVERTISE_RETRY_TIMES;
|
||||
} else {
|
||||
/* An actual retry. */
|
||||
if (_realtime_tick <= _next_retry) return;
|
||||
}
|
||||
|
||||
if ((_network_last_advertise_frame + ADVERTISE_RETRY_INTERVAL) > _frame_counter) return;
|
||||
}
|
||||
|
||||
_network_advertise_retries--;
|
||||
_network_last_advertise_frame = _frame_counter;
|
||||
_last_advertisement = _realtime_tick;
|
||||
_next_advertisement = _realtime_tick + ADVERTISE_NORMAL_INTERVAL;
|
||||
_next_retry = _realtime_tick + ADVERTISE_RETRY_INTERVAL;
|
||||
|
||||
/* Make sure we do not have an overflow when checking these; when time wraps, we simply force an advertisement. */
|
||||
if (_next_advertisement < _last_advertisement) _next_advertisement = UINT32_MAX;
|
||||
if (_next_retry < _last_advertisement) _next_retry = UINT32_MAX;
|
||||
|
||||
if (!ThreadObject::New(NetworkUDPAdvertiseThread, NULL)) {
|
||||
NetworkUDPAdvertiseThread(NULL);
|
||||
|
Reference in New Issue
Block a user