diff --git a/src/base_media_func.h b/src/base_media_func.h index 8491f0e510..f5a5995f17 100644 --- a/src/base_media_func.h +++ b/src/base_media_func.h @@ -274,7 +274,7 @@ template return p; } -#include "network/network_content.h" +#include "network/core/tcp_content_type.h" template const char *TryGetBaseSetFile(const ContentInfo *ci, bool md5sum, const Tbase_set *s) { diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp index f45137aedd..904c6744f3 100644 --- a/src/console_cmds.cpp +++ b/src/console_cmds.cpp @@ -976,7 +976,7 @@ DEF_CONSOLE_CMD(ConNetworkReconnect) /* Don't resolve the address first, just print it directly as it comes from the config file. */ IConsolePrintF(CC_DEFAULT, "Reconnecting to %s:%d...", _settings_client.network.last_host, _settings_client.network.last_port); - NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port), playas); + NetworkClientConnectGame(_settings_client.network.last_host, _settings_client.network.last_port, playas); return true; } @@ -1018,7 +1018,7 @@ DEF_CONSOLE_CMD(ConNetworkConnect) IConsolePrintF(CC_DEFAULT, " port: %s", port); } - NetworkClientConnectGame(NetworkAddress(ip, rport), join_as); + NetworkClientConnectGame(ip, rport, join_as); return true; } diff --git a/src/fios.h b/src/fios.h index 39182e6087..54c7e477fc 100644 --- a/src/fios.h +++ b/src/fios.h @@ -13,7 +13,7 @@ #include "gfx_type.h" #include "company_base.h" #include "newgrf_config.h" -#include "network/core/tcp_content.h" +#include "network/core/tcp_content_type.h" /** Special values for save-load window for the data parameter of #InvalidateWindowData. */ diff --git a/src/lang/catalan.txt b/src/lang/catalan.txt index aecbc84f33..d797d312fd 100644 --- a/src/lang/catalan.txt +++ b/src/lang/catalan.txt @@ -955,7 +955,7 @@ STR_GAME_OPTIONS_CURRENCY_MYR :Ringgit (MYR) STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT :Conducció per l'esquerra STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_RIGHT :Conducció per la dreta -STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Estil dels noms de poblacions +STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Estil dels noms de les poblacions: STR_GAME_OPTIONS_TOWN_NAMES_DROPDOWN_TOOLTIP :{BLACK}Selecciona l'estil dels noms de poblacions ############ start of townname region @@ -995,6 +995,7 @@ STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS :Cada 12 mesos STR_GAME_OPTIONS_LANGUAGE :{BLACK}Idioma STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}Selecciona l'idioma de la interfície +STR_GAME_OPTIONS_LANGUAGE_PERCENTAGE :{STRING} ({NUM}{NBSP}% completed) STR_GAME_OPTIONS_FULLSCREEN :{BLACK}Pantalla completa STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}Marqueu la casella per mostrar l'OpenTTD a pantalla completa. @@ -1992,6 +1993,8 @@ STR_FACE_TIE :Corbata: STR_FACE_EARRING :Arracades: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Canvia la corbata o les arracades +STR_NETWORK_SERVER_VISIBILITY_PRIVATE :Privada +STR_NETWORK_SERVER_VISIBILITY_PUBLIC :Pública # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Multijugador @@ -2055,6 +2058,8 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}El nom d STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Posa una contrasenya STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Protegeix la teva partida amb una contrasenya si no vols que sigui accessible a desconeguts +STR_NETWORK_START_SERVER_VISIBILITY_LABEL :{BLACK}Visibilitat +STR_NETWORK_START_SERVER_VISIBILITY_TOOLTIP :{BLACK}Permet establir si altres persones poden veure el vostre servidor a la llista pública. STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} client{P "" s} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Màxim nombre de clients: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Tria el nombre màxim de clients. No és necessari omplir tots els llocs. @@ -2118,11 +2123,44 @@ STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Servidor STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Companyia protegida: escriviu-ne la contrasenya # Network company list added strings -STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Llista de clients +STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Jugadors en línia # Network client list - - +STR_NETWORK_CLIENT_LIST_CAPTION :{WHITE}Multijugador +STR_NETWORK_CLIENT_LIST_SERVER :{BLACK}Servidor +STR_NETWORK_CLIENT_LIST_SERVER_NAME :{BLACK}Nom +STR_NETWORK_CLIENT_LIST_SERVER_NAME_TOOLTIP :{BLACK}Nom del servidor on esteu jugant +STR_NETWORK_CLIENT_LIST_SERVER_NAME_EDIT_TOOLTIP :{BLACK}Editeu el nom del vostre servidor. +STR_NETWORK_CLIENT_LIST_SERVER_NAME_QUERY_CAPTION :Nom del servidor +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY :{BLACK}Visibilitat +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY_TOOLTIP :{BLACK}Permet establir si altres persones poden veure el vostre servidor a la llista pública. +STR_NETWORK_CLIENT_LIST_PLAYER :{BLACK}Jugador +STR_NETWORK_CLIENT_LIST_PLAYER_NAME :{BLACK}Nom +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_TOOLTIP :{BLACK}El vostre nom de jugador +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_EDIT_TOOLTIP :{BLACK}Editeu el vostre nom de jugador. +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_QUERY_CAPTION :El vostre nom de jugador +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_TOOLTIP :{BLACK}Accions d'administració que s'han de realitzar per a aquest client. +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_TOOLTIP :{BLACK}Accions d'administració que s'han de realitzar per a aquesta companyia. +STR_NETWORK_CLIENT_LIST_JOIN_TOOLTIP :{BLACK}Uniu-vos a aquesta companyia. +STR_NETWORK_CLIENT_LIST_CHAT_CLIENT_TOOLTIP :{BLACK}Envia un missatge a aquest jugador. +STR_NETWORK_CLIENT_LIST_CHAT_COMPANY_TOOLTIP :{BLACK}Envia un missatge a tots els jugadors de la companyia. +STR_NETWORK_CLIENT_LIST_CHAT_SPECTATOR_TOOLTIP :{BLACK}Envieu un missatge a tots els espectadors. +STR_NETWORK_CLIENT_LIST_SPECTATORS :Espectadors +STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Companyia nova) +STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Crea una companyia nova i uniu-vos. +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Aquest ets tu. +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Aquest és l'hoste de la partida. + +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_KICK :Treu +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_BAN :Expulsa +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_RESET :Esborra +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_UNLOCK :Desbloca la contrasenya + +STR_NETWORK_CLIENT_LIST_ASK_CAPTION :{WHITE}Acció de l'administrador +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_KICK :{YELLOW}Esteu segur que voleu treure el jugador «{STRING}»? +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_BAN :{YELLOW}Esteu segur que voleu expulsar el jugador «{STRING}»? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_RESET :{YELLOW}Esteu segur que voleu esborrar la companyia «{COMPANY}»? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_UNLOCK :{YELLOW}Esteu segur que voleu restablir la contrasenya de la companyia «{COMPANY}»? STR_NETWORK_SERVER :Servidor STR_NETWORK_CLIENT :Client @@ -2167,6 +2205,7 @@ STR_NETWORK_ERROR_SERVER_START :{WHITE}No s'ha STR_NETWORK_ERROR_CLIENT_START :{WHITE}No s'ha pogut connectar STR_NETWORK_ERROR_TIMEOUT :{WHITE}La connexió #{NUM} ha esgotat el temps d'espera STR_NETWORK_ERROR_SERVER_ERROR :{WHITE}S'ha obtingut un error de protocol i s'ha tancat la connexió +STR_NETWORK_ERROR_BAD_PLAYER_NAME :{WHITE}No s'ha escollit un nom per al vostre jugador. El nom es pot establir a la part superior de la finestra de mode multijugador. STR_NETWORK_ERROR_WRONG_REVISION :{WHITE}La revisió d'aquest client no concorda amb la revisió del servidor STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Contrasenya incorrecta STR_NETWORK_ERROR_SERVER_FULL :{WHITE}El servidor està ple @@ -2179,6 +2218,7 @@ STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE}Has tard STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}El teu ordinador és massa lent per mantenir-se connectat al servidor STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}El teu ordinador ha tardat massa a descarregar el mapa STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}El teu ordinador ha tardat massa a unir-se al servidor +STR_NETWORK_ERROR_INVALID_CLIENT_NAME :{WHITE}El vostre nom de jugador no és vàlid. ############ Leave those lines in this order!! STR_NETWORK_ERROR_CLIENT_GENERAL :error general @@ -2201,6 +2241,7 @@ STR_NETWORK_ERROR_CLIENT_TIMEOUT_PASSWORD :no s'ha rebut l STR_NETWORK_ERROR_CLIENT_TIMEOUT_COMPUTER :temps d'espera general esgotat STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP :la descàrrega del mapa ha tardat massa STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN :el processat del mapa ha tardat massa +STR_NETWORK_ERROR_CLIENT_INVALID_CLIENT_NAME :nom de client no vàlid ############ End of leave-in-this-order STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION :{WHITE}Possible pèrdua de connexió diff --git a/src/lang/japanese.txt b/src/lang/japanese.txt index 8e6a625e03..1c4fc75013 100644 --- a/src/lang/japanese.txt +++ b/src/lang/japanese.txt @@ -1116,6 +1116,7 @@ STR_TERRAIN_TYPE_HILLY :丘陵地 STR_TERRAIN_TYPE_MOUNTAINOUS :山岳地 STR_TERRAIN_TYPE_ALPINIST :山脈地帯 STR_TERRAIN_TYPE_CUSTOM :カスタム高度 +STR_TERRAIN_TYPE_CUSTOM_VALUE :カスタム高度 ({NUM}) STR_CITY_APPROVAL_PERMISSIVE :寛大 STR_CITY_APPROVAL_TOLERANT :寛容 @@ -1199,6 +1200,7 @@ STR_CONFIG_SETTING_CITY_APPROVAL :地域の再編 STR_CONFIG_SETTING_CITY_APPROVAL_HELPTEXT :会社が街域で引き起こした騒音(主に空港)や環境破壊がどの程度、街での評価や同じ地域での更なる建設行為に影響するかを設定します STR_CONFIG_SETTING_MAP_HEIGHT_LIMIT :マップ高さ限界: {STRING} +STR_CONFIG_SETTING_MAP_HEIGHT_LIMIT_AUTO :(自動) STR_CONFIG_SETTING_TOO_HIGH_MOUNTAIN :{WHITE}マップの最高高さをこの値には設定出来ません。少なくとも1箇所以上この値より高い山があります。 STR_CONFIG_SETTING_AUTOSLOPE :建物/路線の自動地形追従: {STRING} STR_CONFIG_SETTING_AUTOSLOPE_HELPTEXT :撤去を行わないで建物や路線がある土地の地形を変更することを可能にします。建物/路線は変更された地形に自動で追従します。 @@ -1342,6 +1344,7 @@ STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE :石油精製所 STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE_HELPTEXT :石油精製所はマップの外周付近にのみ建設されます。つまり、外周が海のマップでは海岸沿いに建設されるということです STR_CONFIG_SETTING_SNOWLINE_HEIGHT :雪線の位置: {STRING} STR_CONFIG_SETTING_SNOWLINE_HEIGHT_HELPTEXT :亜寒帯気候での雪線の高さを設定します。雪は産業と街の成長に影響があります +STR_CONFIG_SETTING_SNOW_COVERAGE_HELPTEXT :亜寒帯の風景のおおよその雪の量を制御します。雪はまた、産業の生成と町の成長要件にも影響を及ぼします。マップの生成中にのみ使用されます。海抜のすぐ上の土地は常に雪がありません STR_CONFIG_SETTING_SNOW_COVERAGE_VALUE :{NUM}% STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN :地形の起伏: {STRING} STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_HELPTEXT :(TerraGenesisのみ) 地形の起伏度を設定します。なだらかな地形では丘陵の数は減り、裾野が長くなります。起伏が多い地形では丘陵が多くなりますが、似たり寄ったりな地形の繰り返しに見えることがあります @@ -1452,6 +1455,7 @@ STR_CONFIG_SETTING_PERSISTENT_BUILDINGTOOLS :建設ツール STR_CONFIG_SETTING_PERSISTENT_BUILDINGTOOLS_HELPTEXT :橋やトンネルなどを建設した後もツールバーを開いたままにします STR_CONFIG_SETTING_EXPENSES_LAYOUT :財政ウィンドウのグループ分け: {STRING} STR_CONFIG_SETTING_EXPENSES_LAYOUT_HELPTEXT :財政ウィンドウのレイアウトを収入部門・支出部門でグループ分けするかどうかを設定します +STR_CONFIG_SETTING_FAST_FORWARD_SPEED_LIMIT_HELPTEXT :早送りが有効になっている場合のゲームの進行速度を制限します。0 =制限なし(コンピューターが許す限り高速)。100%未満の値は、ゲームの速度を低下させます。上限はコンピュータの仕様によって異なり、ゲームによって異なる場合があります。 STR_CONFIG_SETTING_FAST_FORWARD_SPEED_LIMIT_VAL :{NUM}%通常のゲーム速度 STR_CONFIG_SETTING_FAST_FORWARD_SPEED_LIMIT_ZERO :制限なし(コンピューターが許す限り高速) @@ -1502,6 +1506,7 @@ STR_CONFIG_SETTING_AI_IN_MULTIPLAYER :マルチプレ STR_CONFIG_SETTING_AI_IN_MULTIPLAYER_HELPTEXT :マルチプレイヤーゲームでもAIのライバル企業が登場するかを設定します STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES :命令コード処理上限: {STRING} STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES_HELPTEXT :AIやゲームスクリプトが一つの「詰め込み指令」を処理する際に、一度に演算できる命令コード数を設定します。一般に値を小さくした場合、ゲームへの負荷が軽減されます +STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY :スクリプトあたりの最大メモリ使用量:{STRING} STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY_VALUE :{COMMA} MiB STR_CONFIG_SETTING_SERVINT_ISPERCENT :最大信頼度を点検要件化: {STRING} @@ -1633,6 +1638,7 @@ STR_CONFIG_SETTING_ZOOM_MIN :最大ズーム STR_CONFIG_SETTING_ZOOM_MIN_HELPTEXT :ズームインの最大倍率を設定します。倍率を高くすればするほどメモリー使用量が増えます STR_CONFIG_SETTING_ZOOM_MAX :最大ズームアウトレベル:{STRING} STR_CONFIG_SETTING_ZOOM_MAX_HELPTEXT :ズームアウトの最大倍率を設定します。ズームアウトの倍率が大きいと、処理遅延が発生する可能性があります +STR_CONFIG_SETTING_SPRITE_ZOOM_MIN :使用する最高解像度のスプライト:{STRING} STR_CONFIG_SETTING_SPRITE_ZOOM_MIN_HELPTEXT :スプライトに使用する最大解像度を制限します。 スプライトの解像度を制限すると、使用可能な場合でも高解像度のグラフィックを使用できなくなります。 これにより、高解像度のグラフィックを使用する場合と使用しない場合のGRFファイルを組み合わせて使用する場合に、ゲームの外観を統一することができます。 STR_CONFIG_SETTING_ZOOM_LVL_MIN :4倍 STR_CONFIG_SETTING_ZOOM_LVL_IN_2X :2倍 @@ -2008,6 +2014,7 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}ゲー STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}パスワードを設定 STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}ゲームをパスワードで保護することができます。一般から公然とアクセスされたくない場合等に設定します +STR_NETWORK_START_SERVER_VISIBILITY_LABEL :{BLACK}可視性 STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}接続者数: {NUM} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}最大接続数: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}接続できるクライアントの最大数を指定します。必ずしも全スロットを埋める必要はありません @@ -2074,8 +2081,13 @@ STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}この STR_NETWORK_COMPANY_LIST_CLIENT_LIST :クライアントリスト # Network client list +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY_TOOLTIP :{BLACK}他の人があなたのサーバーを公開リストで見ることができるかどうか +STR_NETWORK_CLIENT_LIST_CHAT_SPECTATOR_TOOLTIP :{BLACK}すべての観客にメッセージを送る +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}ゲームのホストです +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_BAN :{YELLOW}プレーヤー「{STRING}」を追放してもよろしいですか? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_UNLOCK :{YELLOW}会社 '{COMPANY}'のパスワードをリセットしてもよろしいですか? STR_NETWORK_SERVER :サーバー STR_NETWORK_CLIENT :クライアント @@ -2125,6 +2137,7 @@ STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}不正 STR_NETWORK_ERROR_SERVER_FULL :{WHITE}サーバが満員です STR_NETWORK_ERROR_SERVER_BANNED :{WHITE}サーバー側であなたの参加が禁止されています STR_NETWORK_ERROR_KICKED :{WHITE}ゲームから追放されました +STR_NETWORK_ERROR_KICK_MESSAGE :{WHITE}理由:{STRING} STR_NETWORK_ERROR_CHEATER :{WHITE}このサーバーではチート行為は許可されていません STR_NETWORK_ERROR_TOO_MANY_COMMANDS :{WHITE}サーバーに送ったコマンド数が過剰です STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE}パスワード入力時間切れです @@ -2262,6 +2275,7 @@ STR_MISSING_GRAPHICS_NO_QUIT :{BLACK}いい STR_MISSING_GRAPHICS_ERROR_TITLE :{WHITE}ダウンロードに失敗しました STR_MISSING_GRAPHICS_ERROR :{BLACK}グラフィックのダウンロードに失敗しました。{}手動でダウンロードしてください。 +STR_MISSING_GRAPHICS_ERROR_QUIT :{BLACK}OpenTTDをやめる # Transparency settings window STR_TRANSPARENCY_CAPTION :{WHITE}透過表示設定 @@ -2410,6 +2424,7 @@ STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD :{BLACK}道路 STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS :{BLACK}軌道の建設/撤去を切り替えます STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_ROAD :{BLACK}道路の種類を変更/アップグレードします.Shiftは、コスト見積もりの作成/表示を切り替えます +STR_ROAD_NAME_ROAD :道路 STR_ROAD_NAME_TRAM :トラムウェイ # Road depot construction window @@ -2498,6 +2513,7 @@ STR_TREES_RANDOM_TYPE :{BLACK}ラン STR_TREES_RANDOM_TYPE_TOOLTIP :{BLACK}ランダムな樹類で植林します。Shift+クリックで費用を見積もります STR_TREES_RANDOM_TREES_BUTTON :{BLACK}ランダムに広域植林 STR_TREES_RANDOM_TREES_TOOLTIP :{BLACK}地表全体にランダムに植林します +STR_TREES_MODE_NORMAL_TOOLTIP :{BLACK}風景の上をドラッグして、単一の木を植えます。 STR_TREES_MODE_FOREST_SM_BUTTON :{BLACK}グローブ STR_TREES_MODE_FOREST_SM_TOOLTIP :{BLACK}風景をドラッグして小さな森を植えます STR_TREES_MODE_FOREST_LG_TOOLTIP :{BLACK}風景の上をドラッグして、大きな森を植えます。 @@ -2716,6 +2732,7 @@ STR_FRAMERATE_FPS_GOOD :{LTBLUE}{DECIMA STR_FRAMERATE_FPS_WARN :{YELLOW} {DECIMAL}フレーム/秒 STR_FRAMERATE_FPS_BAD :{RED} {DECIMAL}FPS STR_FRAMERATE_BYTES_GOOD :{LTBLUE}{BYTES} +STR_FRAMERATE_BYTES_WARN :{YELLOW} {BYTES} ############ Leave those lines in this order!! STR_FRAMERATE_GAMELOOP :{BLACK}ゲームループの合計: STR_FRAMERATE_GL_ECONOMY :{BLACK}貨物の取り扱い: @@ -2730,6 +2747,8 @@ STR_FRAMERATE_SOUND :{BLACK}サウ STR_FRAMETIME_CAPTION_GAMELOOP :ゲームループ STR_FRAMETIME_CAPTION_GL_ECONOMY :貨物の取り扱い STR_FRAMETIME_CAPTION_GL_TRAINS :切符 +STR_FRAMETIME_CAPTION_GL_SHIPS :船のティック +STR_FRAMETIME_CAPTION_GL_AIRCRAFT :航空機ティック STR_FRAMETIME_CAPTION_GL_LANDSCAPE :ワールドティック STR_FRAMETIME_CAPTION_GL_LINKGRAPH :リンクグラフの遅延 STR_FRAMETIME_CAPTION_DRAWING :グラフィックレンダリング @@ -2813,6 +2832,7 @@ STR_MAPGEN_HEIGHTMAP_NAME :{BLACK}ハイ STR_MAPGEN_HEIGHTMAP_SIZE_LABEL :{BLACK}サイズ: STR_MAPGEN_HEIGHTMAP_SIZE :{ORANGE}{NUM} × {NUM} +STR_MAPGEN_TERRAIN_TYPE_QUERY_CAPT :{WHITE}ターゲットの最高の高さ STR_MAPGEN_SNOW_COVERAGE_QUERY_CAPT :{WHITE}積雪量(%) STR_MAPGEN_DESERT_COVERAGE_QUERY_CAPT :{WHITE}砂漠領域(%) STR_MAPGEN_SNOW_LINE_QUERY_CAPT :{WHITE}雪線の位置を変更 @@ -2890,6 +2910,7 @@ STR_NEWGRF_SETTINGS_MD5SUM :{BLACK}MD5sum: STR_NEWGRF_SETTINGS_PALETTE :{BLACK}パレット: {SILVER}{STRING} STR_NEWGRF_SETTINGS_PALETTE_DEFAULT :デフォルト(D) STR_NEWGRF_SETTINGS_PALETTE_DEFAULT_32BPP :デフォルト(D)/ 32 bpp +STR_NEWGRF_SETTINGS_PALETTE_LEGACY :レガシー(W) STR_NEWGRF_SETTINGS_PALETTE_LEGACY_32BPP :レガシー(W)/ 32 bpp STR_NEWGRF_SETTINGS_PARAMETER :{BLACK}設定: {SILVER}{STRING} STR_NEWGRF_SETTINGS_PARAMETER_NONE :なし @@ -3423,6 +3444,7 @@ STR_INDUSTRY_DIRECTORY_ITEM_INFO :{BLACK}{CARGO_L STR_INDUSTRY_DIRECTORY_ITEM_NOPROD :{ORANGE}{INDUSTRY} STR_INDUSTRY_DIRECTORY_LIST_CAPTION :{BLACK}産業の名前です - 名前をクリックするとこの産業拠点の場所にメイン画面を移動します。Ctrl+クリックでこの産業拠点の場所を新たなビューポートに表示します STR_INDUSTRY_DIRECTORY_ACCEPTED_CARGO_FILTER :{BLACK}受け取った貨物: {SILVER}{STRING} +STR_INDUSTRY_DIRECTORY_PRODUCED_CARGO_FILTER :{BLACK}生産された貨物:{SILVER} {STRING} STR_INDUSTRY_DIRECTORY_FILTER_ALL_TYPES :すべての貨物タイプ STR_INDUSTRY_DIRECTORY_FILTER_NONE :なし @@ -3742,6 +3764,7 @@ STR_REPLACE_REMOVE_WAGON_HELP :{BLACK}機関 STR_VEHICLE_VIEW_CAPTION :{WHITE}{VEHICLE} STR_VEHICLE_VIEW_TRAIN_CENTER_TOOLTIP :{BLACK}メイン画面を列車に中心します。ダブルクリックで列車をメイン画面で追従します。Ctrl+クリックで列車の場所で新しいビューポートでを開きます。 +STR_VEHICLE_VIEW_AIRCRAFT_CENTER_TOOLTIP :{BLACK}航空機の位置に関する中央のメインビュー。ダブルクリックすると、メインビューで航空機が表示されます。Ctrl +クリックすると、航空機の位置に新しいビューポートが開きます STR_VEHICLE_VIEW_TRAIN_SEND_TO_DEPOT_TOOLTIP :{BLACK}列車を列車庫へ回送します。Ctrl+クリックすると点検後、再出庫します STR_VEHICLE_VIEW_ROAD_VEHICLE_SEND_TO_DEPOT_TOOLTIP :{BLACK}車両を車庫へ回送します。Ctrl+クリックすると点検後、再出庫します @@ -4183,9 +4206,11 @@ STR_AI_LIST_ACCEPT_TOOLTIP :{BLACK}選択 STR_AI_LIST_CANCEL :{BLACK}キャンセル STR_AI_LIST_CANCEL_TOOLTIP :{BLACK}スクリプトを変更しません +STR_SCREENSHOT_CAPTION :{WHITE}スクリーンショットを撮る STR_SCREENSHOT_ZOOMIN_SCREENSHOT :{BLACK}スクリーンショットを完全に拡大 STR_SCREENSHOT_WORLD_SCREENSHOT :{BLACK}地図全体のスクリーンショット STR_SCREENSHOT_HEIGHTMAP_SCREENSHOT :{BLACK}ハイトマップスクリーンショット +STR_SCREENSHOT_MINIMAP_SCREENSHOT :{BLACK}ミニマップのスクリーンショット # AI Parameters STR_AI_SETTINGS_CAPTION :{WHITE}{STRING} パラメータ @@ -4347,6 +4372,7 @@ STR_ERROR_LOAN_ALREADY_REPAYED :{WHITE}全額 STR_ERROR_CURRENCY_REQUIRED :{WHITE}{CURRENCY_LONG}が必要です STR_ERROR_CAN_T_REPAY_LOAN :{WHITE}借入金を返済できません STR_ERROR_INSUFFICIENT_FUNDS :{WHITE}借入金を送金することはできません +STR_ERROR_CAN_T_GIVE_MONEY :{WHITE}この会社にお金を渡すことはできません... STR_ERROR_CAN_T_BUY_COMPANY :{WHITE}会社を買収できません STR_ERROR_CAN_T_BUILD_COMPANY_HEADQUARTERS :{WHITE}会社の本社ビルを建設できません STR_ERROR_CAN_T_BUY_25_SHARE_IN_THIS :{WHITE}この会社の株を25%購入できません diff --git a/src/network/core/CMakeLists.txt b/src/network/core/CMakeLists.txt index 777d15d841..c9368a5b46 100644 --- a/src/network/core/CMakeLists.txt +++ b/src/network/core/CMakeLists.txt @@ -17,6 +17,7 @@ add_files( tcp_connect.cpp tcp_content.cpp tcp_content.h + tcp_content_type.h tcp_game.cpp tcp_game.h tcp_http.cpp diff --git a/src/network/core/address.cpp b/src/network/core/address.cpp index 81765ad87c..673619c2eb 100644 --- a/src/network/core/address.cpp +++ b/src/network/core/address.cpp @@ -14,6 +14,8 @@ #include "../../safeguards.h" +static const int DEFAULT_CONNECT_TIMEOUT_SECONDS = 3; ///< Allow connect() three seconds to connect. + /** * Get the hostname; in case it wasn't given the * IPv4 dotted representation is given. @@ -314,29 +316,53 @@ static SOCKET ConnectLoopProc(addrinfo *runp) SOCKET sock = socket(runp->ai_family, runp->ai_socktype, runp->ai_protocol); if (sock == INVALID_SOCKET) { - DEBUG(net, 1, "[%s] could not create %s socket: %s", type, family, strerror(errno)); + DEBUG(net, 1, "[%s] could not create %s socket: %s", type, family, NetworkGetLastErrorString()); return INVALID_SOCKET; } if (!SetNoDelay(sock)) DEBUG(net, 1, "[%s] setting TCP_NODELAY failed", type); + if (!SetNonBlocking(sock)) DEBUG(net, 0, "[%s] setting non-blocking mode failed", type); + int err = connect(sock, runp->ai_addr, (int)runp->ai_addrlen); -#ifdef __EMSCRIPTEN__ - /* Emscripten is asynchronous, and as such a connect() is still in - * progress by the time the call returns. */ - if (err != 0 && errno != EINPROGRESS) -#else - if (err != 0) -#endif - { - DEBUG(net, 1, "[%s] could not connect %s socket: %s", type, family, strerror(errno)); + if (err != 0 && NetworkGetLastError() != EINPROGRESS) { + DEBUG(net, 1, "[%s] could not connect to %s over %s: %s", type, address, family, NetworkGetLastErrorString()); closesocket(sock); return INVALID_SOCKET; } - /* Connection succeeded */ - if (!SetNonBlocking(sock)) DEBUG(net, 0, "[%s] setting non-blocking mode failed", type); + fd_set write_fd; + struct timeval tv; + + FD_ZERO(&write_fd); + FD_SET(sock, &write_fd); + + /* Wait for connect() to either connect, timeout or fail. */ + tv.tv_usec = 0; + tv.tv_sec = DEFAULT_CONNECT_TIMEOUT_SECONDS; + int n = select(FD_SETSIZE, NULL, &write_fd, NULL, &tv); + if (n < 0) { + DEBUG(net, 1, "[%s] could not connect to %s: %s", type, address, NetworkGetLastErrorString()); + closesocket(sock); + return INVALID_SOCKET; + } + + /* If no fd is selected, the timeout has been reached. */ + if (n == 0) { + DEBUG(net, 1, "[%s] timed out while connecting to %s", type, address); + closesocket(sock); + return INVALID_SOCKET; + } + + /* Retrieve last error, if any, on the socket. */ + err = GetSocketError(sock); + if (err != 0) { + DEBUG(net, 1, "[%s] could not connect to %s: %s", type, address, NetworkGetErrorString(err)); + closesocket(sock); + return INVALID_SOCKET; + } + /* Connection succeeded. */ DEBUG(net, 1, "[%s] connected to %s", type, address); return sock; @@ -367,7 +393,7 @@ static SOCKET ListenLoopProc(addrinfo *runp) SOCKET sock = socket(runp->ai_family, runp->ai_socktype, runp->ai_protocol); if (sock == INVALID_SOCKET) { - DEBUG(net, 0, "[%s] could not create %s socket on port %s: %s", type, family, address, strerror(errno)); + DEBUG(net, 0, "[%s] could not create %s socket on port %s: %s", type, family, address, NetworkGetLastErrorString()); return INVALID_SOCKET; } @@ -378,24 +404,24 @@ static SOCKET ListenLoopProc(addrinfo *runp) int on = 1; /* The (const char*) cast is needed for windows!! */ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)) == -1) { - DEBUG(net, 3, "[%s] could not set reusable %s sockets for port %s: %s", type, family, address, strerror(errno)); + DEBUG(net, 3, "[%s] could not set reusable %s sockets for port %s: %s", type, family, address, NetworkGetLastErrorString()); } #ifndef __OS2__ if (runp->ai_family == AF_INET6 && setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&on, sizeof(on)) == -1) { - DEBUG(net, 3, "[%s] could not disable IPv4 over IPv6 on port %s: %s", type, address, strerror(errno)); + DEBUG(net, 3, "[%s] could not disable IPv4 over IPv6 on port %s: %s", type, address, NetworkGetLastErrorString()); } #endif if (bind(sock, runp->ai_addr, (int)runp->ai_addrlen) != 0) { - DEBUG(net, 1, "[%s] could not bind on %s port %s: %s", type, family, address, strerror(errno)); + DEBUG(net, 1, "[%s] could not bind on %s port %s: %s", type, family, address, NetworkGetLastErrorString()); closesocket(sock); return INVALID_SOCKET; } if (runp->ai_socktype != SOCK_DGRAM && listen(sock, 1) != 0) { - DEBUG(net, 1, "[%s] could not listen at %s port %s: %s", type, family, address, strerror(errno)); + DEBUG(net, 1, "[%s] could not listen at %s port %s: %s", type, family, address, NetworkGetLastErrorString()); closesocket(sock); return INVALID_SOCKET; } diff --git a/src/network/core/core.cpp b/src/network/core/core.cpp index 0aeb9c65ce..8c5c5c2292 100644 --- a/src/network/core/core.cpp +++ b/src/network/core/core.cpp @@ -13,6 +13,7 @@ #include "../../debug.h" #include "os_abstraction.h" #include "packet.h" +#include "../../string_func.h" #include "../../safeguards.h" @@ -48,6 +49,22 @@ void NetworkCoreShutdown() #endif } +#if defined(_WIN32) +/** + * Return the string representation of the given error from the OS's network functions. + * @param error The error number (from \c NetworkGetLastError()). + * @return The error message, potentially an empty string but never \c nullptr. + */ +const char *NetworkGetErrorString(int error) +{ + static char buffer[512]; + if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buffer, sizeof(buffer), NULL) == 0) { + seprintf(buffer, lastof(buffer), "Unknown error %d", error); + } + return buffer; +} +#endif /* defined(_WIN32) */ /** * Serializes the GRFIdentifier (GRF ID and MD5 checksum) to the packet diff --git a/src/network/core/os_abstraction.h b/src/network/core/os_abstraction.h index ce6b91747f..658088497d 100644 --- a/src/network/core/os_abstraction.h +++ b/src/network/core/os_abstraction.h @@ -23,9 +23,21 @@ #include #include -#define GET_LAST_ERROR() WSAGetLastError() +/** + * Get the last error code from any of the OS's network functions. + * What it returns and when it is reset, is implementation defined. + * @return The last error code. + */ +#define NetworkGetLastError() WSAGetLastError() #undef EWOULDBLOCK #define EWOULDBLOCK WSAEWOULDBLOCK +#undef ECONNRESET +#define ECONNRESET WSAECONNRESET +#undef EINPROGRESS +#define EINPROGRESS WSAEWOULDBLOCK + +const char *NetworkGetErrorString(int error); + /* Windows has some different names for some types */ typedef unsigned long in_addr_t; @@ -64,7 +76,8 @@ typedef unsigned long in_addr_t; # define INVALID_SOCKET -1 # define ioctlsocket ioctl # define closesocket close -# define GET_LAST_ERROR() (errno) +# define NetworkGetLastError() (errno) +# define NetworkGetErrorString(error) (strerror(error)) # define SD_RECEIVE SHUT_RD # define SD_SEND SHUT_WR # define SD_BOTH SHUT_RDWR @@ -117,7 +130,8 @@ typedef unsigned long in_addr_t; # define INVALID_SOCKET -1 # define ioctlsocket ioctl # define closesocket close -# define GET_LAST_ERROR() (sock_errno()) +# define NetworkGetLastError() (sock_errno()) +# define NetworkGetErrorString(error) (strerror(error)) # define SD_RECEIVE SHUT_RD # define SD_SEND SHUT_WR # define SD_BOTH SHUT_RDWR @@ -192,6 +206,15 @@ static inline socklen_t FixAddrLenForEmscripten(struct sockaddr_storage &address } #endif +/** + * Return the string representation of the last error from the OS's network functions. + * @return The error message, potentially an empty string but never \c nullptr. + */ +static inline const char *NetworkGetLastErrorString() +{ + return NetworkGetErrorString(NetworkGetLastError()); +} + /** * Try to set the socket into non-blocking mode. * @param d The socket to set the non-blocking more for. @@ -269,6 +292,20 @@ static inline bool ShutdownSocket(SOCKET d, bool read, bool write, uint linger_t return shutdown(d, how) == 0; } +/** + * Get the error from a socket, if any. + * @param d The socket to get the error from. + * @return The errno on the socket. + */ +static inline int GetSocketError(SOCKET d) +{ + int err; + socklen_t len = sizeof(err); + getsockopt(d, SOL_SOCKET, SO_ERROR, (char *)&err, &len); + + return err; +} + /* Make sure these structures have the size we expect them to be */ static_assert(sizeof(in_addr) == 4); ///< IPv4 addresses should be 4 bytes. static_assert(sizeof(in6_addr) == 16); ///< IPv6 addresses should be 16 bytes. diff --git a/src/network/core/tcp.cpp b/src/network/core/tcp.cpp index 0d6a5fa020..ceb4e283b6 100644 --- a/src/network/core/tcp.cpp +++ b/src/network/core/tcp.cpp @@ -98,11 +98,11 @@ SendPacketsState NetworkTCPSocketHandler::SendPackets(bool closing_down) Packet *p = this->packet_queue.front().get(); res = p->TransferOut(send, this->sock, 0); if (res == -1) { - int err = GET_LAST_ERROR(); + int err = NetworkGetLastError(); if (err != EWOULDBLOCK) { /* Something went wrong.. close client! */ if (!closing_down) { - DEBUG(net, 0, "send failed with error %d", err); + DEBUG(net, 0, "send failed with error %s", NetworkGetErrorString(err)); this->CloseConnection(); } return SPS_CLOSED; @@ -148,10 +148,10 @@ std::unique_ptr NetworkTCPSocketHandler::ReceivePacket() while (p->RemainingBytesToTransfer() != 0) { res = p->TransferIn(recv, this->sock, 0); if (res == -1) { - int err = GET_LAST_ERROR(); + int err = NetworkGetLastError(); if (err != EWOULDBLOCK) { - /* Something went wrong... (104 is connection reset by peer) */ - if (err != 104) DEBUG(net, 0, "recv failed with error %d", err); + /* Something went wrong... (ECONNRESET is connection reset by peer) */ + if (err != ECONNRESET) DEBUG(net, 0, "recv failed with error %s", NetworkGetErrorString(err)); this->CloseConnection(); return nullptr; } @@ -176,10 +176,10 @@ std::unique_ptr NetworkTCPSocketHandler::ReceivePacket() while (p->RemainingBytesToTransfer() != 0) { res = p->TransferIn(recv, this->sock, 0); if (res == -1) { - int err = GET_LAST_ERROR(); + int err = NetworkGetLastError(); if (err != EWOULDBLOCK) { - /* Something went wrong... (104 is connection reset by peer) */ - if (err != 104) DEBUG(net, 0, "recv failed with error %d", err); + /* Something went wrong... (ECONNRESET is connection reset by peer) */ + if (err != ECONNRESET) DEBUG(net, 0, "recv failed with error %s", NetworkGetErrorString(err)); this->CloseConnection(); return nullptr; } diff --git a/src/network/core/tcp_content.cpp b/src/network/core/tcp_content.cpp index 551e0e1db5..319df8c644 100644 --- a/src/network/core/tcp_content.cpp +++ b/src/network/core/tcp_content.cpp @@ -10,14 +10,12 @@ */ #include "../../stdafx.h" -#ifndef OPENTTD_MSU #include "../../textfile_gui.h" #include "../../newgrf_config.h" #include "../../base_media_base.h" #include "../../ai/ai.hpp" #include "../../game/game.hpp" #include "../../fios.h" -#endif /* OPENTTD_MSU */ #include "tcp_content.h" #include "../../safeguards.h" @@ -92,7 +90,6 @@ bool ContentInfo::IsValid() const return this->state < ContentInfo::INVALID && this->type >= CONTENT_TYPE_BEGIN && this->type < CONTENT_TYPE_END; } -#ifndef OPENTTD_MSU /** * Search a textfile file next to this file in the content list. * @param type The type of the textfile to search for. @@ -139,7 +136,6 @@ const char *ContentInfo::GetTextfile(TextfileType type) const if (tmp == nullptr) return nullptr; return ::GetTextfile(type, GetContentInfoSubDir(this->type), tmp); } -#endif /* OPENTTD_MSU */ void NetworkContentSocketHandler::Close() { @@ -235,7 +231,6 @@ bool NetworkContentSocketHandler::Receive_SERVER_INFO(Packet *p) { return this-> bool NetworkContentSocketHandler::Receive_CLIENT_CONTENT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CONTENT_CLIENT_CONTENT); } bool NetworkContentSocketHandler::Receive_SERVER_CONTENT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CONTENT_SERVER_CONTENT); } -#ifndef OPENTTD_MSU /** * Helper to get the subdirectory a #ContentInfo is located in. * @param type The type of content. @@ -260,4 +255,3 @@ Subdirectory GetContentInfoSubDir(ContentType type) case CONTENT_TYPE_HEIGHTMAP: return HEIGHTMAP_DIR; } } -#endif /* OPENTTD_MSU */ diff --git a/src/network/core/tcp_content.h b/src/network/core/tcp_content.h index f421211230..52cae1e0ed 100644 --- a/src/network/core/tcp_content.h +++ b/src/network/core/tcp_content.h @@ -16,81 +16,7 @@ #include "tcp.h" #include "packet.h" #include "../../debug.h" - -/** The values in the enum are important; they are used as database 'keys' */ -enum ContentType { - CONTENT_TYPE_BEGIN = 1, ///< Helper to mark the begin of the types - CONTENT_TYPE_BASE_GRAPHICS = 1, ///< The content consists of base graphics - CONTENT_TYPE_NEWGRF = 2, ///< The content consists of a NewGRF - CONTENT_TYPE_AI = 3, ///< The content consists of an AI - CONTENT_TYPE_AI_LIBRARY = 4, ///< The content consists of an AI library - CONTENT_TYPE_SCENARIO = 5, ///< The content consists of a scenario - CONTENT_TYPE_HEIGHTMAP = 6, ///< The content consists of a heightmap - CONTENT_TYPE_BASE_SOUNDS = 7, ///< The content consists of base sounds - CONTENT_TYPE_BASE_MUSIC = 8, ///< The content consists of base music - CONTENT_TYPE_GAME = 9, ///< The content consists of a game script - CONTENT_TYPE_GAME_LIBRARY = 10, ///< The content consists of a GS library - CONTENT_TYPE_END, ///< Helper to mark the end of the types -}; - -/** Enum with all types of TCP content packets. The order MUST not be changed **/ -enum PacketContentType { - PACKET_CONTENT_CLIENT_INFO_LIST, ///< Queries the content server for a list of info of a given content type - PACKET_CONTENT_CLIENT_INFO_ID, ///< Queries the content server for information about a list of internal IDs - PACKET_CONTENT_CLIENT_INFO_EXTID, ///< Queries the content server for information about a list of external IDs - PACKET_CONTENT_CLIENT_INFO_EXTID_MD5, ///< Queries the content server for information about a list of external IDs and MD5 - PACKET_CONTENT_SERVER_INFO, ///< Reply of content server with information about content - PACKET_CONTENT_CLIENT_CONTENT, ///< Request a content file given an internal ID - PACKET_CONTENT_SERVER_CONTENT, ///< Reply with the content of the given ID - PACKET_CONTENT_END, ///< Must ALWAYS be on the end of this list!! (period) -}; - -/** Unique identifier for the content. */ -enum ContentID { - INVALID_CONTENT_ID = UINT32_MAX, ///< Sentinel for invalid content. -}; - -/** Container for all important information about a piece of content. */ -struct ContentInfo { - /** The state the content can be in. */ - enum State { - UNSELECTED, ///< The content has not been selected - SELECTED, ///< The content has been manually selected - AUTOSELECTED, ///< The content has been selected as dependency - ALREADY_HERE, ///< The content is already at the client side - DOES_NOT_EXIST, ///< The content does not exist in the content system - INVALID, ///< The content's invalid - }; - - ContentType type; ///< Type of content - ContentID id; ///< Unique (server side) ID for the content - uint32 filesize; ///< Size of the file - char filename[48]; ///< Filename (for the .tar.gz; only valid on download) - char name[64]; ///< Name of the content - char version[16]; ///< Version of the content - char url[96]; ///< URL related to the content - char description[512]; ///< Description of the content - uint32 unique_id; ///< Unique ID; either GRF ID or shortname - byte md5sum[16]; ///< The MD5 checksum - uint8 dependency_count; ///< Number of dependencies - ContentID *dependencies; ///< Malloced array of dependencies (unique server side ids) - uint8 tag_count; ///< Number of tags - char (*tags)[32]; ///< Malloced array of tags (strings) - State state; ///< Whether the content info is selected (for download) - bool upgrade; ///< This item is an upgrade - - ContentInfo(); - ~ContentInfo(); - - void TransferFrom(ContentInfo *other); - - size_t Size() const; - bool IsSelected() const; - bool IsValid() const; -#ifndef OPENTTD_MSU - const char *GetTextfile(TextfileType type) const; -#endif /* OPENTTD_MSU */ -}; +#include "tcp_content_type.h" /** Base socket handler for all Content TCP sockets */ class NetworkContentSocketHandler : public NetworkTCPSocketHandler { @@ -203,8 +129,6 @@ public: bool ReceivePackets(); }; -#ifndef OPENTTD_MSU Subdirectory GetContentInfoSubDir(ContentType type); -#endif /* OPENTTD_MSU */ #endif /* NETWORK_CORE_TCP_CONTENT_H */ diff --git a/src/network/core/tcp_content_type.h b/src/network/core/tcp_content_type.h new file mode 100644 index 0000000000..c3a9d61108 --- /dev/null +++ b/src/network/core/tcp_content_type.h @@ -0,0 +1,88 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** + * @file tcp_content_type.h Basic types related to the content on the content server. + */ + +#ifndef NETWORK_CORE_TCP_CONTENT_TYPE_H +#define NETWORK_CORE_TCP_CONTENT_TYPE_H + +/** The values in the enum are important; they are used as database 'keys' */ +enum ContentType { + CONTENT_TYPE_BEGIN = 1, ///< Helper to mark the begin of the types + CONTENT_TYPE_BASE_GRAPHICS = 1, ///< The content consists of base graphics + CONTENT_TYPE_NEWGRF = 2, ///< The content consists of a NewGRF + CONTENT_TYPE_AI = 3, ///< The content consists of an AI + CONTENT_TYPE_AI_LIBRARY = 4, ///< The content consists of an AI library + CONTENT_TYPE_SCENARIO = 5, ///< The content consists of a scenario + CONTENT_TYPE_HEIGHTMAP = 6, ///< The content consists of a heightmap + CONTENT_TYPE_BASE_SOUNDS = 7, ///< The content consists of base sounds + CONTENT_TYPE_BASE_MUSIC = 8, ///< The content consists of base music + CONTENT_TYPE_GAME = 9, ///< The content consists of a game script + CONTENT_TYPE_GAME_LIBRARY = 10, ///< The content consists of a GS library + CONTENT_TYPE_END, ///< Helper to mark the end of the types +}; + +/** Enum with all types of TCP content packets. The order MUST not be changed **/ +enum PacketContentType { + PACKET_CONTENT_CLIENT_INFO_LIST, ///< Queries the content server for a list of info of a given content type + PACKET_CONTENT_CLIENT_INFO_ID, ///< Queries the content server for information about a list of internal IDs + PACKET_CONTENT_CLIENT_INFO_EXTID, ///< Queries the content server for information about a list of external IDs + PACKET_CONTENT_CLIENT_INFO_EXTID_MD5, ///< Queries the content server for information about a list of external IDs and MD5 + PACKET_CONTENT_SERVER_INFO, ///< Reply of content server with information about content + PACKET_CONTENT_CLIENT_CONTENT, ///< Request a content file given an internal ID + PACKET_CONTENT_SERVER_CONTENT, ///< Reply with the content of the given ID + PACKET_CONTENT_END, ///< Must ALWAYS be on the end of this list!! (period) +}; + +/** Unique identifier for the content. */ +enum ContentID { + INVALID_CONTENT_ID = UINT32_MAX, ///< Sentinel for invalid content. +}; + +/** Container for all important information about a piece of content. */ +struct ContentInfo { + /** The state the content can be in. */ + enum State { + UNSELECTED, ///< The content has not been selected + SELECTED, ///< The content has been manually selected + AUTOSELECTED, ///< The content has been selected as dependency + ALREADY_HERE, ///< The content is already at the client side + DOES_NOT_EXIST, ///< The content does not exist in the content system + INVALID, ///< The content's invalid + }; + + ContentType type; ///< Type of content + ContentID id; ///< Unique (server side) ID for the content + uint32 filesize; ///< Size of the file + char filename[48]; ///< Filename (for the .tar.gz; only valid on download) + char name[64]; ///< Name of the content + char version[16]; ///< Version of the content + char url[96]; ///< URL related to the content + char description[512]; ///< Description of the content + uint32 unique_id; ///< Unique ID; either GRF ID or shortname + byte md5sum[16]; ///< The MD5 checksum + uint8 dependency_count; ///< Number of dependencies + ContentID *dependencies; ///< Malloced array of dependencies (unique server side ids) + uint8 tag_count; ///< Number of tags + char (*tags)[32]; ///< Malloced array of tags (strings) + State state; ///< Whether the content info is selected (for download) + bool upgrade; ///< This item is an upgrade + + ContentInfo(); + ~ContentInfo(); + + void TransferFrom(ContentInfo *other); + + size_t Size() const; + bool IsSelected() const; + bool IsValid() const; + const char *GetTextfile(TextfileType type) const; +}; + +#endif /* NETWORK_CORE_TCP_CONTENT_TYPE_H */ diff --git a/src/network/core/tcp_http.cpp b/src/network/core/tcp_http.cpp index 36826c81a4..17eb3a720b 100644 --- a/src/network/core/tcp_http.cpp +++ b/src/network/core/tcp_http.cpp @@ -228,10 +228,10 @@ int NetworkHTTPSocketHandler::Receive() for (;;) { ssize_t res = recv(this->sock, (char *)this->recv_buffer + this->recv_pos, lengthof(this->recv_buffer) - this->recv_pos, 0); if (res == -1) { - int err = GET_LAST_ERROR(); + int err = NetworkGetLastError(); if (err != EWOULDBLOCK) { - /* Something went wrong... (104 is connection reset by peer) */ - if (err != 104) DEBUG(net, 0, "recv failed with error %d", err); + /* Something went wrong... (ECONNRESET is connection reset by peer) */ + if (err != ECONNRESET) DEBUG(net, 0, "recv failed with error %s", NetworkGetErrorString(err)); return -1; } /* Connection would block, so stop for now */ diff --git a/src/network/core/tcp_listen.h b/src/network/core/tcp_listen.h index 53a3d57cc9..168f49f947 100644 --- a/src/network/core/tcp_listen.h +++ b/src/network/core/tcp_listen.h @@ -64,7 +64,7 @@ public: DEBUG(net, 1, "[%s] Banned ip tried to join (%s), refused", Tsocket::GetName(), entry.c_str()); if (p.TransferOut(send, s, 0) < 0) { - DEBUG(net, 0, "send failed with error %d", GET_LAST_ERROR()); + DEBUG(net, 0, "send failed with error %s", NetworkGetLastErrorString()); } closesocket(s); break; @@ -81,7 +81,7 @@ public: p.PrepareToSend(); if (p.TransferOut(send, s, 0) < 0) { - DEBUG(net, 0, "send failed with error %d", GET_LAST_ERROR()); + DEBUG(net, 0, "send failed with error %s", NetworkGetLastErrorString()); } closesocket(s); diff --git a/src/network/core/udp.cpp b/src/network/core/udp.cpp index 1cd7ff273d..69631a3ada 100644 --- a/src/network/core/udp.cpp +++ b/src/network/core/udp.cpp @@ -130,7 +130,7 @@ void NetworkUDPSocketHandler::SendPacket(Packet *p, NetworkAddress *recv, bool a /* Enable broadcast */ unsigned long val = 1; if (setsockopt(s.second, SOL_SOCKET, SO_BROADCAST, (char *) &val, sizeof(val)) < 0) { - DEBUG(net, 1, "[udp] setting broadcast failed with: %i", GET_LAST_ERROR()); + DEBUG(net, 1, "[udp] setting broadcast failed with: %s", NetworkGetLastErrorString()); } } @@ -139,7 +139,7 @@ void NetworkUDPSocketHandler::SendPacket(Packet *p, NetworkAddress *recv, bool a DEBUG(net, 7, "[udp] sendto(%s)", NetworkAddressDumper().GetAddressAsString(&send)); /* Check for any errors, but ignore it otherwise */ - if (res == -1) DEBUG(net, 1, "[udp] sendto(%s) failed with: %i", NetworkAddressDumper().GetAddressAsString(&send), GET_LAST_ERROR()); + if (res == -1) DEBUG(net, 1, "[udp] sendto(%s) failed with: %s", NetworkAddressDumper().GetAddressAsString(&send), NetworkGetLastErrorString()); if (!all) break; } diff --git a/src/network/network.cpp b/src/network/network.cpp index 7890058835..e066d00d6e 100644 --- a/src/network/network.cpp +++ b/src/network/network.cpp @@ -718,16 +718,16 @@ public: /* Used by clients, to connect to a server */ -void NetworkClientConnectGame(NetworkAddress address, CompanyID join_as, const char *join_server_password, const char *join_company_password) +void NetworkClientConnectGame(const char *hostname, uint16 port, CompanyID join_as, const char *join_server_password, const char *join_company_password) { if (!_network_available) return; - if (address.GetPort() == 0) return; + if (port == 0) return; if (!NetworkValidateClientName()) return; - strecpy(_settings_client.network.last_host, address.GetHostname(), lastof(_settings_client.network.last_host)); - _settings_client.network.last_port = address.GetPort(); + strecpy(_settings_client.network.last_host, hostname, lastof(_settings_client.network.last_host)); + _settings_client.network.last_port = port; _network_join_as = join_as; _network_join_server_password = join_server_password; _network_join_company_password = join_company_password; @@ -738,7 +738,7 @@ void NetworkClientConnectGame(NetworkAddress address, CompanyID join_as, const c _network_join_status = NETWORK_JOIN_STATUS_CONNECTING; ShowJoinStatusWindow(); - new TCPClientConnecter(address); + new TCPClientConnecter(NetworkAddress(hostname, port)); } static void NetworkInitGameInfo() @@ -1099,12 +1099,13 @@ static void NetworkGenerateServerId() seprintf(_settings_client.network.network_id, lastof(_settings_client.network.network_id), "%s", hex_output); } -void NetworkStartDebugLog(NetworkAddress address) +void NetworkStartDebugLog(const char *hostname, uint16 port) { extern SOCKET _debug_socket; // Comes from debug.c - DEBUG(net, 0, "Redirecting DEBUG() to %s:%d", address.GetHostname(), address.GetPort()); + DEBUG(net, 0, "Redirecting DEBUG() to %s:%d", hostname, port); + NetworkAddress address(hostname, port); SOCKET s = address.Connect(); if (s == INVALID_SOCKET) { DEBUG(net, 0, "Failed to open socket for redirection DEBUG()"); diff --git a/src/network/network_func.h b/src/network/network_func.h index 448b434fde..90bf12b2c0 100644 --- a/src/network/network_func.h +++ b/src/network/network_func.h @@ -17,7 +17,6 @@ // #define DEBUG_DUMP_COMMANDS // #define DEBUG_FAILED_DUMP_COMMANDS -#include "core/address.h" #include "network_type.h" #include "../console_type.h" #include "../gfx_type.h" @@ -48,12 +47,12 @@ void NetworkGameLoop(); void NetworkBackgroundLoop(); void ParseConnectionString(const char **port, char *connection_string); void ParseGameConnectionString(const char **company, const char **port, char *connection_string); -void NetworkStartDebugLog(NetworkAddress address); +void NetworkStartDebugLog(const char *hostname, uint16 port); void NetworkPopulateCompanyStats(NetworkCompanyStats *stats); void NetworkUpdateClientInfo(ClientID client_id); void NetworkClientsToSpectators(CompanyID cid); -void NetworkClientConnectGame(NetworkAddress address, CompanyID join_as, const char *join_server_password = nullptr, const char *join_company_password = nullptr); +void NetworkClientConnectGame(const char *hostname, uint16 port, CompanyID join_as, const char *join_server_password = nullptr, const char *join_company_password = nullptr); void NetworkClientRequestMove(CompanyID company, const char *pass = ""); void NetworkClientSendRcon(const char *password, const char *command); void NetworkClientSendSettingsPassword(const char *password); diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index e71cec0f81..8162f1e474 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -1485,15 +1485,15 @@ struct NetworkLobbyWindow : public Window { case WID_NL_JOIN: // Join company /* Button can be clicked only when it is enabled. */ - NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port), this->company); + NetworkClientConnectGame(_settings_client.network.last_host, _settings_client.network.last_port, this->company); break; case WID_NL_NEW: // New company - NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port), COMPANY_NEW_COMPANY); + NetworkClientConnectGame(_settings_client.network.last_host, _settings_client.network.last_port, COMPANY_NEW_COMPANY); break; case WID_NL_SPECTATE: // Spectate game - NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port), COMPANY_SPECTATOR); + NetworkClientConnectGame(_settings_client.network.last_host, _settings_client.network.last_port, COMPANY_SPECTATOR); break; case WID_NL_REFRESH: // Refresh diff --git a/src/newgrf_config.cpp b/src/newgrf_config.cpp index 6df31ff3ae..c0da077398 100644 --- a/src/newgrf_config.cpp +++ b/src/newgrf_config.cpp @@ -17,6 +17,7 @@ #include "window_func.h" #include "progress.h" #include "video/video_driver.hpp" +#include "string_func.h" #include "strings_func.h" #include "textfile_gui.h" #include "thread.h" diff --git a/src/openttd.cpp b/src/openttd.cpp index efcf764c8a..c63db32d48 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -638,7 +638,7 @@ struct AfterNewGRFScan : NewGRFScanCallback { LoadIntroGame(); _switch_mode = SM_NONE; - NetworkClientConnectGame(NetworkAddress(network_conn, rport), join_as, join_server_password, join_company_password); + NetworkClientConnectGame(network_conn, rport, join_as, join_server_password, join_company_password); } /* After the scan we're not used anymore. */ @@ -940,7 +940,7 @@ int openttd_main(int argc, char *argv[]) ParseConnectionString(&port, debuglog_conn); if (port != nullptr) rport = atoi(port); - NetworkStartDebugLog(NetworkAddress(debuglog_conn, rport)); + NetworkStartDebugLog(debuglog_conn, rport); } if (!HandleBootstrap()) { @@ -1959,7 +1959,7 @@ void GameLoop() if (_network_reconnect > 0 && --_network_reconnect == 0) { /* This means that we want to reconnect to the last host * We do this here, because it means that the network is really closed */ - NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port), COMPANY_SPECTATOR); + NetworkClientConnectGame(_settings_client.network.last_host, _settings_client.network.last_port, COMPANY_SPECTATOR); } /* Singleplayer */ StateGameLoop(); diff --git a/src/safeguards.h b/src/safeguards.h index 5351116ecb..e3d6c4a3e4 100644 --- a/src/safeguards.h +++ b/src/safeguards.h @@ -69,4 +69,17 @@ #undef abs #endif +#if defined(NETWORK_CORE_OS_ABSTRACTION_H) && defined(_WIN32) +/* Use NetworkGetLastError() instead of errno, or do not (indirectly) include network/core/os_abstraction.h. + * Winsock does not set errno, but one should rather call WSAGetLastError. NetworkGetLastError abstracts that away. */ +#ifdef errno +#undef errno +#endif +#define errno SAFEGUARD_DO_NOT_USE_THIS_METHOD + +/* Use NetworkGetLastErrorString() instead of strerror, or do not (indirectly) include network/core/os_abstraction.h. + * Winsock errors are not handled by strerror, but one should rather call FormatMessage. NetworkGetLastErrorString abstracts that away. */ +#define strerror SAFEGUARD_DO_NOT_USE_THIS_METHOD +#endif /* defined(NETWORK_CORE_OS_ABSTRACTION_H) && defined(_WIN32) */ + #endif /* SAFEGUARDS_H */ diff --git a/src/saveload/gamelog_sl.cpp b/src/saveload/gamelog_sl.cpp index 4d0ee02272..10a71e9b72 100644 --- a/src/saveload/gamelog_sl.cpp +++ b/src/saveload/gamelog_sl.cpp @@ -10,6 +10,7 @@ #include "../stdafx.h" #include "../gamelog_internal.h" #include "../fios.h" +#include "../string_func.h" #include "saveload.h" diff --git a/src/saveload/newgrf_sl.cpp b/src/saveload/newgrf_sl.cpp index 64aafe29f6..abc76813d3 100644 --- a/src/saveload/newgrf_sl.cpp +++ b/src/saveload/newgrf_sl.cpp @@ -9,6 +9,7 @@ #include "../stdafx.h" #include "../fios.h" +#include "../string_func.h" #include "saveload.h" #include "newgrf_sl.h" diff --git a/src/settings.cpp b/src/settings.cpp index 7330acf754..c01f5697b7 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -523,6 +523,59 @@ static void Write_ValidateSetting(void *ptr, const SettingDesc *sd, int32 val) WriteValue(ptr, sd->save.conv, (int64)val); } +/** + * Set the string value of a setting. + * @param ptr Pointer to the storage location (might be a pointer to a pointer). + * @param sld Pointer to the information for the conversions and limitations to apply. + * @param p The string to save. + */ +static void Write_ValidateString(void *ptr, const SaveLoad *sld, const char *p) +{ + switch (GetVarMemType(sld->conv)) { + case SLE_VAR_STRB: + case SLE_VAR_STRBQ: + if (p != nullptr) { + char *begin = (char*)ptr; + char *end = begin + sld->length - 1; + strecpy(begin, p, end); + str_validate(begin, end, SVS_NONE); + } + break; + + case SLE_VAR_STR: + case SLE_VAR_STRQ: + free(*(char**)ptr); + *(char**)ptr = p == nullptr ? nullptr : stredup(p); + break; + + default: NOT_REACHED(); + } +} + +/** + * Set the string value of a setting. + * @param ptr Pointer to the std::string. + * @param sld Pointer to the information for the conversions and limitations to apply. + * @param p The string to save. + */ +static void Write_ValidateStdString(void *ptr, const SaveLoad *sld, const char *p) +{ + std::string *dst = reinterpret_cast(ptr); + + switch (GetVarMemType(sld->conv)) { + case SLE_VAR_STR: + case SLE_VAR_STRQ: + if (p != nullptr) { + dst->assign(p); + } else { + dst->clear(); + } + break; + + default: NOT_REACHED(); + } +} + /** * Load values from a group of an IniFile structure into the internal representation * @param ini pointer to IniFile structure that holds administrative information @@ -583,38 +636,11 @@ static void IniLoadSettings(IniFile *ini, const SettingDesc *sd, const char *grp break; case SDT_STRING: - switch (GetVarMemType(sld->conv)) { - case SLE_VAR_STRB: - case SLE_VAR_STRBQ: - if (p != nullptr) strecpy((char*)ptr, (const char*)p, (char*)ptr + sld->length - 1); - break; - - case SLE_VAR_STR: - case SLE_VAR_STRQ: - free(*(char**)ptr); - *(char**)ptr = p == nullptr ? nullptr : stredup((const char*)p); - break; - - case SLE_VAR_CHAR: if (p != nullptr) *(char *)ptr = *(const char *)p; break; - - default: NOT_REACHED(); - } + Write_ValidateString(ptr, sld, (const char *)p); break; case SDT_STDSTRING: - switch (GetVarMemType(sld->conv)) { - case SLE_VAR_STR: - case SLE_VAR_STRQ: - if (p != nullptr) { - reinterpret_cast(ptr)->assign((const char *)p); - } else { - reinterpret_cast(ptr)->clear(); - } - break; - - default: NOT_REACHED(); - } - + Write_ValidateStdString(ptr, sld, (const char *)p); break; case SDT_INTLIST: { @@ -749,7 +775,6 @@ static void IniSaveSettings(IniFile *ini, const SettingDesc *sd, const char *grp } break; - case SLE_VAR_CHAR: buf[0] = *(char*)ptr; buf[1] = '\0'; break; default: NOT_REACHED(); } break; @@ -2494,13 +2519,13 @@ bool SetSettingValue(uint index, const char *value, bool force_newgame) const SettingDesc *sd = &_settings[index]; assert(sd->save.conv & SLF_NO_NETWORK_SYNC); - if (GetVarMemType(sd->save.conv) == SLE_VAR_STRQ) { - char **var = (char**)GetVariableAddress((_game_mode == GM_MENU || force_newgame) ? &_settings_newgame : &_settings_game, &sd->save); - free(*var); - *var = strcmp(value, "(null)") == 0 ? nullptr : stredup(value); - } else { - char *var = (char*)GetVariableAddress(nullptr, &sd->save); - strecpy(var, value, &var[sd->save.length - 1]); + if (GetVarMemType(sd->save.conv) == SLE_VAR_STRQ && strcmp(value, "(null)") == 0) { + value = nullptr; + } + + void *ptr = GetVariableAddress((_game_mode == GM_MENU || force_newgame) ? &_settings_newgame : &_settings_game, &sd->save); + if (sd->desc.cmd == SDT_STRING) { + Write_ValidateString(ptr, &sd->save, value); } if (sd->desc.proc != nullptr) sd->desc.proc(0); diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index 59ccadf43a..efcecd824e 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -3009,7 +3009,7 @@ struct CustomCurrencyWindow : Window { case WID_CC_SEPARATOR: SetDParamStr(0, _custom_currency.separator); str = STR_JUST_RAW_STRING; - len = 1; + len = sizeof(_custom_currency.separator) - 1; // Number of characters excluding '\0' termination line = WID_CC_SEPARATOR; break; @@ -3017,7 +3017,7 @@ struct CustomCurrencyWindow : Window { case WID_CC_PREFIX: SetDParamStr(0, _custom_currency.prefix); str = STR_JUST_RAW_STRING; - len = 12; + len = sizeof(_custom_currency.prefix) - 1; // Number of characters excluding '\0' termination line = WID_CC_PREFIX; break; @@ -3025,7 +3025,7 @@ struct CustomCurrencyWindow : Window { case WID_CC_SUFFIX: SetDParamStr(0, _custom_currency.suffix); str = STR_JUST_RAW_STRING; - len = 12; + len = sizeof(_custom_currency.suffix) - 1; // Number of characters excluding '\0' termination line = WID_CC_SUFFIX; break; diff --git a/src/table/currency_settings.ini b/src/table/currency_settings.ini index e09dd7ba7f..9dd65b7eb3 100644 --- a/src/table/currency_settings.ini +++ b/src/table/currency_settings.ini @@ -10,7 +10,6 @@ static const SettingDesc _currency_settings[] = { }; [templates] SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat, $startup, $extver, nullptr, $orderproc), -SDT_CHR = SDT_CHR($base, $var, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $startup, $extver, nullptr), SDT_STR = SDT_STR($base, $var, $type, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $startup, $extver, nullptr), SDT_END = SDT_END() @@ -43,9 +42,10 @@ def = 1 min = 0 max = UINT16_MAX -[SDT_CHR] +[SDT_STR] base = CurrencySpec var = separator +type = SLE_STRBQ def = ""."" cat = SC_BASIC diff --git a/src/table/settings.h.preamble b/src/table/settings.h.preamble index cba64b7110..5bc12b7e9b 100644 --- a/src/table/settings.h.preamble +++ b/src/table/settings.h.preamble @@ -119,9 +119,6 @@ static size_t ConvertLandscape(const char *value); #define SDT_STR(base, var, type, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat, startup, extver, patxname)\ SDT_GENERAL(#var, SDT_STRING, SL_STR, type, flags, guiflags, base, var, sizeof(((base*)8)->var), def, 0, 0, 0, nullptr, str, strhelp, strval, proc, nullptr, from, to, cat, startup, extver, patxname) -#define SDT_CHR(base, var, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat, startup, extver, patxname)\ - SDT_GENERAL(#var, SDT_STRING, SL_VAR, SLE_CHAR, flags, guiflags, base, var, 1, def, 0, 0, 0, nullptr, str, strhelp, strval, proc, nullptr, from, to, cat, startup, extver, patxname) - #define SDT_OMANY(base, var, type, flags, guiflags, def, max, full, str, strhelp, strval, proc, from, to, load, cat, startup, extver, patxname)\ SDT_GENERAL(#var, SDT_ONEOFMANY, SL_VAR, type, flags, guiflags, base, var, 1, def, 0, max, 0, full, str, strhelp, strval, proc, load, from, to, cat, startup, extver, patxname)