diff --git a/.github/workflows/release-linux.yml b/.github/workflows/release-linux.yml index c398e6c0e3..201452daca 100644 --- a/.github/workflows/release-linux.yml +++ b/.github/workflows/release-linux.yml @@ -50,7 +50,7 @@ jobs: uses: dtolnay/rust-toolchain@stable - name: Enable Rust cache - uses: Swatinem/rust-cache@v2 + uses: Swatinem/rust-cache@v2.7.0 - name: Setup vcpkg caching uses: actions/github-script@v6 diff --git a/CMakeLists.txt b/CMakeLists.txt index 02af1334f9..2ebec96b2d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -388,6 +388,7 @@ link_package(ZSTD TARGET ZSTD::ZSTD RECOMMENDED) if(NOT WIN32 AND NOT EMSCRIPTEN) link_package(CURL ENCOURAGED) + target_link_libraries(openttd_lib ${CMAKE_DL_LIBS}) endif() if(NOT OPTION_DEDICATED) diff --git a/cmake/scripts/Regression.cmake b/cmake/scripts/Regression.cmake index 19fece83f5..c719b90406 100644 --- a/cmake/scripts/Regression.cmake +++ b/cmake/scripts/Regression.cmake @@ -54,6 +54,9 @@ string(REPLACE "0x(nil)" "0x00000000" REGRESSION_RESULT "${REGRESSION_RESULT}") string(REPLACE "0x0000000000000000" "0x00000000" REGRESSION_RESULT "${REGRESSION_RESULT}") string(REPLACE "0x0x0" "0x00000000" REGRESSION_RESULT "${REGRESSION_RESULT}") +# Convert path separators +string(REPLACE "\\" "/" REGRESSION_RESULT "${REGRESSION_RESULT}") + # Remove timestamps if any string(REGEX REPLACE "\[[0-9-]+ [0-9:]+\] " "" REGRESSION_RESULT "${REGRESSION_RESULT}") @@ -62,6 +65,7 @@ string(REPLACE "\ndbg: [script]" "\n" REGRESSION_RESULT "${REGRESSION_RESULT}") string(REPLACE "\n " "\nERROR: " REGRESSION_RESULT "${REGRESSION_RESULT}") string(REPLACE "\nERROR: [1] " "\n" REGRESSION_RESULT "${REGRESSION_RESULT}") string(REPLACE "\n[P] " "\n" REGRESSION_RESULT "${REGRESSION_RESULT}") +string(REPLACE "\n[S] " "\n" REGRESSION_RESULT "${REGRESSION_RESULT}") string(REGEX REPLACE "dbg: ([^\n]*)\n?" "" REGRESSION_RESULT "${REGRESSION_RESULT}") # Read the expected result diff --git a/regression/regression/main.nut b/regression/regression/main.nut index c829fc33f4..ed859a1011 100644 --- a/regression/regression/main.nut +++ b/regression/regression/main.nut @@ -2024,5 +2024,12 @@ function Regression::Start() print(" IsEventWaiting: false"); this.Math(); + + /* Check Valuate() is actually limited, MUST BE THE LAST TEST. */ + print("--Valuate() with excessive CPU usage--") + local list = AIList(); + list.AddItem(0, 0); + local Infinite = function(id) { while(true); } + list.Valuate(Infinite); } diff --git a/regression/regression/result.txt b/regression/regression/result.txt index 0aaf488bbb..780460af17 100644 --- a/regression/regression/result.txt +++ b/regression/regression/result.txt @@ -9585,4 +9585,23 @@ ERROR: IsEnd() is invalid as Begin() is never called -1 > 2147483647: false -2147483648 > 2147483647: false 13725 > -2147483648: true +--Valuate() with excessive CPU usage-- +Your script made an error: excessive CPU usage in valuator function + +*FUNCTION [unknown()] regression/main.nut line [2032] +*FUNCTION [Valuate()] NATIVE line [-1] +*FUNCTION [Start()] regression/main.nut line [2033] + +[id] 0 +[this] TABLE +[Infinite] CLOSURE +[list] INSTANCE +[this] INSTANCE +Your script made an error: excessive CPU usage in valuator function + +*FUNCTION [Start()] regression/main.nut line [2033] + +[Infinite] CLOSURE +[list] INSTANCE +[this] INSTANCE ERROR: The script died unexpectedly. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 548a43a088..d075514a05 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -242,6 +242,7 @@ add_files( league_gui.h league_gui.cpp league_type.h + library_loader.h livery.h load_check.h main_gui.cpp diff --git a/src/gfx_layout_fallback.cpp b/src/gfx_layout_fallback.cpp index 2343c8aa86..39c6efab76 100644 --- a/src/gfx_layout_fallback.cpp +++ b/src/gfx_layout_fallback.cpp @@ -256,6 +256,11 @@ std::unique_ptr FallbackParagraphLayout::NextLine next_run = this->buffer_begin + iter->first; begin = this->buffer; + /* Since a next run is started, there is already some text that + * will be shown for this line. However, we do not want to break + * this line at the previous space, so pretend we passed a space + * just before this next run. */ + last_space = begin - 1; } if (IsWhitespace(c)) last_space = this->buffer; diff --git a/src/lang/arabic_egypt.txt b/src/lang/arabic_egypt.txt index 3563bca280..bb95b67a74 100644 --- a/src/lang/arabic_egypt.txt +++ b/src/lang/arabic_egypt.txt @@ -202,6 +202,7 @@ STR_UNITS_POWER_IMPERIAL :{DECIMAL}{NBSP} STR_UNITS_POWER_METRIC :{DECIMAL}{NBSP}حصان STR_UNITS_POWER_SI :{DECIMAL}{NBSP}ك واط +STR_UNITS_POWER_METRIC_TO_WEIGHT_IMPERIAL :{DECIMAL}{NBSP}hp/t STR_UNITS_POWER_METRIC_TO_WEIGHT_SI :{DECIMAL}{NBSP}hp/Mg STR_UNITS_WEIGHT_SHORT_IMPERIAL :{DECIMAL}{NBSP} طن @@ -390,6 +391,7 @@ STR_SCENEDIT_FILE_MENU_QUIT :انهاء ###length 15 STR_SETTINGS_MENU_GAME_OPTIONS :إعدادات اللعبه STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :الإعدادات +STR_SETTINGS_MENU_AI_SETTINGS :اعدادات االذكاء الاصطناعي STR_SETTINGS_MENU_NEWGRF_SETTINGS :إعدادات اﻹضافات STR_SETTINGS_MENU_TRANSPARENCY_OPTIONS :خيارات الشفافية STR_SETTINGS_MENU_TOWN_NAMES_DISPLAYED :عرض اسماء المدن @@ -752,6 +754,7 @@ STR_SMALLMAP_TOOLTIP_SHOW_HEIGHT :{BLACK}بدل STR_SMALLMAP_TOOLTIP_DISABLE_ALL_COMPANIES :{BLACK}عدم عرض ممتلكات اي شركة على الخارطة STR_SMALLMAP_TOOLTIP_ENABLE_ALL_COMPANIES :{BLACK}عرض جميع املاك الشركة على الخريطة STR_SMALLMAP_TOOLTIP_DISABLE_ALL_CARGOS :{BLACK}عدم عرض أي بضائع على الخريطة +STR_SMALLMAP_TOOLTIP_ENABLE_ALL_CARGOS :{BLACK}عرض جميع البضائع على الخريطة # Status bar messages STR_STATUSBAR_TOOLTIP_SHOW_LAST_NEWS :{BLACK}اظهر اخر رسالة / تقرير @@ -948,6 +951,7 @@ STR_GAME_OPTIONS_VIDEO_VSYNC :{BLACK}VSync STR_GAME_OPTIONS_VIDEO_VSYNC_TOOLTIP :{BLACK}حدد هذا المربع لمزامنة الشاشة (v-sync). سيتم تطبيق الإعداد الذي تم تغييره فقط عند إعادة تشغيل اللعبة. يعمل فقط مع تمكين تسريع الأجهزة (hardware acceleration) +STR_GAME_OPTIONS_GUI_SCALE_TOOLTIP :{BLACK}اسحب شريط التمرير لتعيين حجم الواجهة. اضغط مع الاستمرار على Ctrl للتعديل المستمر STR_GAME_OPTIONS_GUI_SCALE_AUTO :{BLACK}الكشف التلقائي عن الحجم STR_GAME_OPTIONS_GUI_SCALE_AUTO_TOOLTIP :{BLACK}اختر هذا المربع لكشف حجم الواجهة تلقائيا @@ -1252,6 +1256,7 @@ STR_CONFIG_SETTING_ORDER_REVIEW_EXDEPOT :نعم, بست STR_CONFIG_SETTING_ORDER_REVIEW_ON :لكل العربات STR_CONFIG_SETTING_WARN_INCOME_LESS :حذر عندما يكون الدخل سالبا :{STRING} +STR_CONFIG_SETTING_WARN_INCOME_LESS_HELPTEXT :عند التمكين ، يتم إرسال رسالة إخبارية عندما لا تحقق السيارة أي ربح خلال سنة تقويمية واحدة STR_CONFIG_SETTING_NEVER_EXPIRE_VEHICLES :المركبات لا تنتهي صلاحيتها ابدا : {STRING} @@ -1406,6 +1411,7 @@ STR_CONFIG_SETTING_ADVANCED_VEHICLE_LISTS :استخدام STR_CONFIG_SETTING_LOADING_INDICATORS :تفعيل مؤشر التحميل: {STRING} STR_CONFIG_SETTING_LOADING_INDICATORS_HELPTEXT :حدد ما إذا كانت مؤشرات التحميل معروضة فوق تحميل المركبات أو تفريغها +STR_CONFIG_SETTING_TIMETABLE_MODE_HELPTEXT :حدد الوحدات الزمنية المستخدمة في جداول مواعيد المركبات ###length 3 STR_CONFIG_SETTING_TIMETABLE_SHOW_ARRIVAL_DEPARTURE :عرض الوصول و المغادرة في جدولة الاعمال: {STRING} @@ -1469,6 +1475,7 @@ STR_CONFIG_SETTING_AI_BUILDS_AIRCRAFT :حظر الطا STR_CONFIG_SETTING_AI_BUILDS_SHIPS :حظر السفن على الحاسوب: {STRING} +STR_CONFIG_SETTING_AI_PROFILE :الملف الشخصي للإعدادات الافتراضية: {STRING} ###length 3 STR_CONFIG_SETTING_AI_PROFILE_EASY :سهل @@ -1480,8 +1487,10 @@ STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY_VALUE :{COMMA} MiB STR_CONFIG_SETTING_SERVINT_ISPERCENT :فترات الصيانة بالنسبة المئوية : {STRING} -STR_CONFIG_SETTING_SERVINT_AIRCRAFT ::مدة فحص الطائرة الإفتراضي{STRING} +STR_CONFIG_SETTING_SERVINT_AIRCRAFT :مدة فحص الإفتراضي للطائرة: {STRING} +STR_CONFIG_SETTING_SERVINT_SHIPS :مدة فحص الإفتراضي للسفن: {STRING} ###setting-zero-is-special +STR_CONFIG_SETTING_SERVINT_DISABLED :غير مفعل STR_CONFIG_SETTING_NOSERVICE :الغاء الصيانة عندما يكون التعطيل للمركبات غير مفعل: {STRING} @@ -1624,6 +1633,7 @@ STR_CONFIG_SETTING_LARGER_TOWNS_VALUE :1 في {COMMA} STR_CONFIG_SETTING_CITY_SIZE_MULTIPLIER :مضاعف المدن المبدئي: {STRING} +STR_CONFIG_SETTING_DISTRIBUTION_PAX :وضع التوزيع للركاب: {STRING} ###length 3 STR_CONFIG_SETTING_LINKGRAPH_ACCURACY_HELPTEXT :كلما قمت بتعليت هذا بشكل اكثر، كلما ازداد وقت الCPU في حساب الرسم البياني الرابط. إذا استغرق الأمر وقتًا طويلاً فقد تلاحظ تأخير في الاستجبة. إذا قمت بتغيره إلى قيمة منخفضة، فسيكون التوزيع غير دقيق، وقد تلاحظ عدم إرسال البضائع إلى الأماكن التي تتوقع أن تذهب إليها. @@ -1648,6 +1658,7 @@ STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_METRIC :متري (طن) STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE ::وحدات جهد الجر {STRING} ###length 3 +STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_IMPERIAL :إمبراطوري (lbf) STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_METRIC :متري (كغ - قوة) ###length 3 @@ -1979,6 +1990,7 @@ STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_BAN :منع STR_NETWORK_CLIENT_LIST_ASK_CLIENT_KICK :{YELLOW}هل أنت متأكد أنك تريد طرد اللاعب '{STRING}'؟ STR_NETWORK_CLIENT_LIST_ASK_CLIENT_BAN :{YELLOW}هل أنت متأكد أنك تريد حظر اللاعب '{STRING}'؟ STR_NETWORK_CLIENT_LIST_ASK_COMPANY_RESET :{YELLOW}هل أنت متأكد أنك تريد حذف شركة '{COMPANY}'؟ +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_UNLOCK :{YELLOW}هل أنت متأكد أنك تريد محو كلمة السر الخاصة بالشركة '{COMPANY}'? STR_NETWORK_ASK_RELAY_NO :{BLACK}لا @@ -2600,6 +2612,7 @@ STR_ABOUT_VERSION :{BLACK}النس STR_ABOUT_COPYRIGHT_OPENTTD :{BLACK}النسخة المفتوحة {COPYRIGHT}2002-{STRING} فريق النسخة المفتوحة # Framerate display window +STR_FRAMERATE_CURRENT :{WHITE}الحالي STR_FRAMERATE_MS_GOOD :{LTBLUE}{DECIMAL} ms STR_FRAMERATE_MS_BAD :{RED}{DECIMAL} ms STR_FRAMERATE_FPS_GOOD :{LTBLUE}{DECIMAL} صورة في الثانية @@ -2845,6 +2858,7 @@ STR_NEWGRF_ERROR_MSG_INFO :{SILVER}{STRING STR_NEWGRF_ERROR_MSG_WARNING :{RED} تحذير: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_ERROR :{RED} خطأ: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_FATAL :{RED} خطأ قاتل: {SILVER}{STRING} +STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}ال NewGRF "{STRING}" قام باعادة خطء فادح:{}{STRING} STR_NEWGRF_ERROR_VERSION_NUMBER :{1:STRING} لن يعمل مع اصدار الباتش المسجل في النسخة المفتوحة STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:STRING} يعمل مع {STRING} اصدار من TTD. STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING} مصمم ليستخدم مع {STRING} @@ -3114,6 +3128,7 @@ STR_FINANCES_NEGATIVE_INCOME :-{CURRENCY_LONG STR_FINANCES_POSITIVE_INCOME :+{CURRENCY_LONG} STR_FINANCES_BANK_BALANCE_TITLE :{WHITE}السيولة المتاحة STR_FINANCES_LOAN_TITLE :{WHITE}القرض +STR_FINANCES_INTEREST_RATE :{WHITE}فائدة القرض: {BLACK}{NUM}% STR_FINANCES_MAX_LOAN :{WHITE}اقصى حد للقرض: {BLACK}{CURRENCY_LONG} STR_FINANCES_TOTAL_CURRENCY :{BLACK}{CURRENCY_LONG} STR_FINANCES_BORROW_BUTTON :{BLACK}اقتراض{CURRENCY_LONG} @@ -3333,6 +3348,7 @@ STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_BUTTON :{BLACK}شراء STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_BUTTON :{BLACK}شراء طائرة ###length VEHICLE_TYPES +STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_BUTTON :{BLACK}شراء العربة وتجديد بضائعها STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_REFIT_VEHICLE_BUTTON :{BLACK}شراء العربة وتجديد بضائعها STR_BUY_VEHICLE_SHIP_BUY_REFIT_VEHICLE_BUTTON :{BLACK}شراء وإعادة تجهيز السفينة @@ -3496,6 +3512,7 @@ STR_REPLACE_HELP_LEFT_ARRAY :{BLACK} اخت STR_REPLACE_HELP_RIGHT_ARRAY :{BLACK} اختر نوع المحرك المراد إحلاله محل المحرك المختار في القائمة اليسرى STR_REPLACE_VEHICLES_START :{BLACK} بدأ تبديل العربات +STR_REPLACE_VEHICLES_NOW :استبدل جميع المركبات الآن STR_REPLACE_HELP_START_BUTTON :{BLACK}اضغط لبدأ عملية تبديل المحركات المختارة في القائمة اليسرى بالمحركات المختارة في القائمة اليمنى STR_REPLACE_NOT_REPLACING :{BLACK}لم يتم التبديل STR_REPLACE_NOT_REPLACING_VEHICLE_SELECTED :{BLACK}لم يتم اختيار اي عربة @@ -3865,13 +3882,13 @@ STR_TIMETABLE_STAY_FOR_ESTIMATED :(البقاء STR_TIMETABLE_STAY_FOR :ويبقى لـ {STRING} STR_TIMETABLE_AND_TRAVEL_FOR :ويسافر لـ {STRING} -STR_TIMETABLE_TOTAL_TIME :{BLACK}جدولة الاوامر هذه ستأخذ {STRING} لنهاية -STR_TIMETABLE_TOTAL_TIME_INCOMPLETE :{BLACK}جدولة الاوامر هذه ستأخذ على الاقل {STRING} لتكتمل (لايشمل كل الجدولة) +STR_TIMETABLE_TOTAL_TIME :{BLACK}جدول الاوامر هذه ستأخذ {STRING} للانتهاء +STR_TIMETABLE_TOTAL_TIME_INCOMPLETE :{BLACK}جدول الاوامر هذا سيأخذ على الاقل {STRING} للانتهاء (ليست جميعها مجدولة) STR_TIMETABLE_STATUS_ON_TIME :{BLACK}هذه العربة تعمل حسب الجدولة في الوقت المُحَدَد STR_TIMETABLE_STATUS_LATE :{BLACK}هذه العربه {STRING} مُتاخِرة حاليا عن الجدوله STR_TIMETABLE_STATUS_EARLY :{BLACK}هذه العربه {STRING} مُتَقَدِمه عن الجدوله -STR_TIMETABLE_STATUS_NOT_STARTED :{BLACK}جدولة الاعمال لم تبدأ بعد +STR_TIMETABLE_STATUS_NOT_STARTED :{BLACK}جدول الاعمال لم تبدأ بعد @@ -4070,6 +4087,7 @@ STR_ERROR_OWNED_BY :{WHITE}مملو STR_ERROR_AREA_IS_OWNED_BY_ANOTHER :{WHITE}... المنطقة مملوكة لشركة منافسة STR_ERROR_TERRAFORM_LIMIT_REACHED :{WHITE}... تم الوصول لاقصى حدود للتضاريس STR_ERROR_CLEARING_LIMIT_REACHED :{WHITE}... تم الوصول لاقصى عدد ازالة +STR_ERROR_TREE_PLANT_LIMIT_REACHED :{WHITE}... تم الوصول للحد الاقصى لزرع الاشجار STR_ERROR_NAME_MUST_BE_UNIQUE :{WHITE}السم يجب ان يكون فريدا - غير مستخدم STR_ERROR_GENERIC_OBJECT_IN_THE_WAY :{WHITE}{1:STRING} على الطريق STR_ERROR_NOT_ALLOWED_WHILE_PAUSED :{WHITE}غير مسموح في حين توقفت @@ -4405,6 +4423,7 @@ STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE :{WHITE}... ال STR_ERROR_CAN_T_TIMETABLE_VEHICLE :{WHITE}لا يمكن جدولة العربة ... STR_ERROR_TIMETABLE_ONLY_WAIT_AT_STATIONS :{WHITE}يمكن للعربات الانتظار في المحطات فقط. STR_ERROR_TIMETABLE_NOT_STOPPING_HERE :{WHITE}هذه العربة لا تتوقف في هذه المحطة. +STR_ERROR_TIMETABLE_NOT_STARTED :{WHITE}... جدول الاعمال لم تبدأ بعد # Sign related errors STR_ERROR_TOO_MANY_SIGNS :{WHITE}... العلامات كثيرة جدا diff --git a/src/lang/brazilian_portuguese.txt b/src/lang/brazilian_portuguese.txt index 2e5d23a496..ece32ddb64 100644 --- a/src/lang/brazilian_portuguese.txt +++ b/src/lang/brazilian_portuguese.txt @@ -772,7 +772,7 @@ STR_SMALLMAP_LEGENDA_AIRCRAFT :{TINY_FONT}{BLA STR_SMALLMAP_LEGENDA_TRANSPORT_ROUTES :{TINY_FONT}{BLACK}Rotas de Transporte STR_SMALLMAP_LEGENDA_FOREST :{TINY_FONT}{BLACK}Floresta STR_SMALLMAP_LEGENDA_RAILROAD_STATION :{TINY_FONT}{BLACK}Estação Ferroviária -STR_SMALLMAP_LEGENDA_TRUCK_LOADING_BAY :{TINY_FONT}{BLACK}Compartimento de Carga de Caminhões +STR_SMALLMAP_LEGENDA_TRUCK_LOADING_BAY :{TINY_FONT}{BLACK}Estação de caminhões STR_SMALLMAP_LEGENDA_BUS_STATION :{TINY_FONT}{BLACK}Estação de Ônibus STR_SMALLMAP_LEGENDA_AIRPORT_HELIPORT :{TINY_FONT}{BLACK}Aeroporto/Heliporto STR_SMALLMAP_LEGENDA_DOCK :{TINY_FONT}{BLACK}Doca @@ -1003,6 +1003,7 @@ STR_GAME_OPTIONS_CURRENCY_HKD :Dólar de Hong STR_GAME_OPTIONS_CURRENCY_INR :Rúpia Indiana STR_GAME_OPTIONS_CURRENCY_IDR :Rupia Indonésia STR_GAME_OPTIONS_CURRENCY_MYR :Ringgit Malaio +STR_GAME_OPTIONS_CURRENCY_LVL :Lats da Letônia STR_GAME_OPTIONS_AUTOSAVE_FRAME :{BLACK}Salvar automaticamente STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_TOOLTIP :{BLACK}Selecionar o intervalo entre jogos salvos automaticos @@ -2056,14 +2057,17 @@ STR_CONFIG_SETTING_ACCOUNTING :Contabilidade STR_CONFIG_SETTING_VEHICLES :Veículos STR_CONFIG_SETTING_VEHICLES_PHYSICS :Física STR_CONFIG_SETTING_VEHICLES_ROUTING :Rota +STR_CONFIG_SETTING_VEHICLES_ORDERS :Ordens STR_CONFIG_SETTING_LIMITATIONS :Limitações STR_CONFIG_SETTING_ACCIDENTS :Desastres / Acidentes STR_CONFIG_SETTING_GENWORLD :Geração de Mundo STR_CONFIG_SETTING_ENVIRONMENT :Meio-Ambiente +STR_CONFIG_SETTING_ENVIRONMENT_TIME :Tempo STR_CONFIG_SETTING_ENVIRONMENT_AUTHORITIES :Autoridades STR_CONFIG_SETTING_ENVIRONMENT_TOWNS : Cidades STR_CONFIG_SETTING_ENVIRONMENT_INDUSTRIES :Indústrias STR_CONFIG_SETTING_ENVIRONMENT_CARGODIST :Distribuição de Carga +STR_CONFIG_SETTING_ENVIRONMENT_TREES :Árvores STR_CONFIG_SETTING_AI :Oponentes STR_CONFIG_SETTING_AI_NPC :Computadores STR_CONFIG_SETTING_NETWORK :Rede @@ -2721,9 +2725,9 @@ STR_RAIL_TOOLBAR_MAGLEV_CONSTRUCTION_CAPTION :Construir ferro STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK :{BLACK}Construir ferrovias. Ctrl alterna entre construção/remoção de trilhos. Shift altera construção/preço estimado STR_RAIL_TOOLBAR_TOOLTIP_BUILD_AUTORAIL :{BLACK}Construir ferrovias usando o modo Autotrilho. Ctrl alterna entre construção/remoçao de trilhos. Shift altera construção/preço estimado STR_RAIL_TOOLBAR_TOOLTIP_BUILD_TRAIN_DEPOT_FOR_BUILDING :{BLACK}Construir depósito (para compra e manutenção de trens). Shift altera construção/preço estimado -STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL_TO_WAYPOINT :{BLACK}Converter linha em ponto de controle. Ctrl permite a união de pontos de controle. Shift altera construção/preço estimado +STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL_TO_WAYPOINT :{BLACK}Construir ponto de controle na rodovia. Ctrl permite unir pontos de controle. Shift alterna construir/mostrar custo estimado STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_STATION :{BLACK}Construir estação ferroviária. Ctrl permite a união de estações. Shift altera construção/preço estimado -STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_SIGNALS :{BLACK}Construir sinais ferroviários. Ctrl alterna a construção de semáforos/sinais{}Clicar e arrastar constroi sinais até a próxima junção ou sinal{}Ctrl+Clique alterna a janela de seleção de sinais. Shift alterna construção/preço estimado +STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_SIGNALS :{BLACK}Construir sinais na ferrovia. Ctrl alterna entre a construção de semáforos/sinais{}Clicar e arrastar constrói sinais ao longo de uma linha de trilhos. Ctrl constrói sinais até a próxima junção ou sinal{}Ctrl+Clique abre a janela de seleção de sinais. Shift alterna construir/mostrar custo estimado STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_BRIDGE :{BLACK}Construir ponte ferroviária. Shift altera construção/preço estimado STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TUNNEL :{BLACK}Construir túnel ferroviário. Shift altera construção/preço estimado STR_RAIL_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR :{BLACK}Alternar construir/remover ferrovias, sinais, pontos de controle e estações. Segure ctrl para remover os trilhos de estações e pontos de controle. @@ -2811,7 +2815,7 @@ STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_VEHICLE_DEPOT :{BLACK}Construi STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAM_VEHICLE_DEPOT :{BLACK}Construir depósito de bonde (para compra e manutenção de bondes). Shift altera construção/preço estimado STR_ROAD_TOOLBAR_TOOLTIP_BUILD_BUS_STATION :{BLACK}Construir estação de ônibus. Ctrl permite a união de estações. Shift altera construção/preço estimado STR_ROAD_TOOLBAR_TOOLTIP_BUILD_PASSENGER_TRAM_STATION :{BLACK}Constuir estação de bonde para passageiros. Ctrl permite a união de estações. Shift altera construção/preço estimado -STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRUCK_LOADING_BAY :{BLACK}Construir área de carga. Ctrl permite a união de estações. Shift altera construção/preço estimado +STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRUCK_LOADING_BAY :{BLACK}Construir estação de caminhões. Ctrl permite unir estações. Shift alterna construir/mostrar custo estimado STR_ROAD_TOOLBAR_TOOLTIP_BUILD_CARGO_TRAM_STATION :{BLACK}Constuir estação de bonde para carga. Ctrl permite a união de estações. Shift altera construção/preço estimado STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_ONE_WAY_ROAD :{BLACK}Ativar/Desativar vias de mão única STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_BRIDGE :{BLACK}Construir ponte rodoviária. Shift altera construção/preço estimado @@ -2836,7 +2840,7 @@ STR_BUILD_DEPOT_TRAM_ORIENTATION_SELECT_TOOLTIP :{BLACK}Selecion STR_STATION_BUILD_BUS_ORIENTATION :{WHITE}Orientação do estação de ônibus STR_STATION_BUILD_BUS_ORIENTATION_TOOLTIP :{BLACK}Selecionar orientação do estação de ônibus STR_STATION_BUILD_TRUCK_ORIENTATION :{WHITE}Orientação da área de carga -STR_STATION_BUILD_TRUCK_ORIENTATION_TOOLTIP :{BLACK}Selecionar orientação da área de carga +STR_STATION_BUILD_TRUCK_ORIENTATION_TOOLTIP :{BLACK}Selecionar a orientação da estação de caminhões STR_STATION_BUILD_PASSENGER_TRAM_ORIENTATION :{WHITE}Orientação da Estação de Bonde Passageiros STR_STATION_BUILD_PASSENGER_TRAM_ORIENTATION_TOOLTIP :{BLACK}Selecionar orientação da estação de bonde STR_STATION_BUILD_CARGO_TRAM_ORIENTATION :{WHITE}Orientação da Estação de Bonde de Carga @@ -3080,7 +3084,7 @@ STR_LAI_TREE_NAME_CACTUS_PLANTS :Cactos STR_LAI_STATION_DESCRIPTION_RAILROAD_STATION :Estação ferroviária STR_LAI_STATION_DESCRIPTION_AIRCRAFT_HANGAR :Hangar STR_LAI_STATION_DESCRIPTION_AIRPORT :Aeroporto -STR_LAI_STATION_DESCRIPTION_TRUCK_LOADING_AREA :Área de carga +STR_LAI_STATION_DESCRIPTION_TRUCK_LOADING_AREA :Estação de caminhões STR_LAI_STATION_DESCRIPTION_BUS_STATION :Estação de ônibus STR_LAI_STATION_DESCRIPTION_SHIP_DOCK :Doca STR_LAI_STATION_DESCRIPTION_BUOY :Bóia diff --git a/src/lang/korean.txt b/src/lang/korean.txt index af15fa09ca..30d3166d21 100644 --- a/src/lang/korean.txt +++ b/src/lang/korean.txt @@ -1003,6 +1003,7 @@ STR_GAME_OPTIONS_CURRENCY_HKD :홍콩 달러 STR_GAME_OPTIONS_CURRENCY_INR :인도 루피 STR_GAME_OPTIONS_CURRENCY_IDR :인도네시아 루피아 STR_GAME_OPTIONS_CURRENCY_MYR :말레이시아 링깃 +STR_GAME_OPTIONS_CURRENCY_LVL :라트비아 라츠 STR_GAME_OPTIONS_AUTOSAVE_FRAME :{BLACK}자동 저장 STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_TOOLTIP :{BLACK}게임 자동 저장 간격을 선택 diff --git a/src/lang/polish.txt b/src/lang/polish.txt index 7308ec4b87..e118cc27ba 100644 --- a/src/lang/polish.txt +++ b/src/lang/polish.txt @@ -1884,7 +1884,7 @@ STR_CONFIG_SETTING_SNOWLINE_HEIGHT :Wysokość gran STR_CONFIG_SETTING_SNOWLINE_HEIGHT_HELPTEXT :Wybierz, na jakiej wysokości zaczyna zalegać śnieg w krajobrazie arktycznym. Poziom pokrywy śnieżnej wpływa na rozmieszczenie przedsiębiorstw i na warunki rozwoju miast. Może być zmodyfikowana poprzez Edytor Scenariuszy, w innym przypadku jest obliczana za pomocą ustawienia „pokrycie śniegiem” STR_CONFIG_SETTING_SNOW_COVERAGE :Pokrycie śniegiem: {STRING} -STR_CONFIG_SETTING_SNOW_COVERAGE_HELPTEXT :Wybierz przybliżoną ilość śniegu w krajobrazie arktycznym. Śnieg wpływa również wpływa na rozmieszczenie przedsiębiorstw i na warunki rozwoju miast. Używane tylko podczas generowania mapy. Teren tuż ponad poziomem wody jest zawsze bez śniegu +STR_CONFIG_SETTING_SNOW_COVERAGE_HELPTEXT :Wybierz przybliżoną ilość śniegu w krajobrazie arktycznym. Śnieg wpływa również wpływa na rozmieszczenie przedsiębiorstw i na warunki rozwoju miast. Używane tylko podczas generowania mapy. Teren tuż ponad poziomem morza jest zawsze bez śniegu STR_CONFIG_SETTING_SNOW_COVERAGE_VALUE :{NUM}% STR_CONFIG_SETTING_DESERT_COVERAGE :Pokrycie pustynią: {STRING} @@ -3612,7 +3612,7 @@ STR_MAPGEN_DATE_TOOLTIP :{BLACK}Wybierz STR_MAPGEN_NUMBER_OF_INDUSTRIES :{BLACK}Liczba przedsiębiorstw: STR_MAPGEN_NUMBER_OF_INDUSTRIES_TOOLTIP :{BLACK}Wybierz gęstość rozmieszczenia przedsiębiorstw lub podaj ich określoną liczbę STR_MAPGEN_HEIGHTMAP_HEIGHT :{BLACK}Najwyższy szczyt: -STR_MAPGEN_HEIGHTMAP_HEIGHT_TOOLTIP :{BLACK}Wybierz najwyższy szczyt, który gra spróbuje utworzyć, mierzony wysokością nad poziomem wody +STR_MAPGEN_HEIGHTMAP_HEIGHT_TOOLTIP :{BLACK}Wybierz najwyższy szczyt, który gra spróbuje utworzyć, mierzony wysokością nad poziomem morza STR_MAPGEN_HEIGHTMAP_HEIGHT_UP :{BLACK}Zwiększ wysokość najwyższego szczytu na mapie o jeden poziom STR_MAPGEN_HEIGHTMAP_HEIGHT_DOWN :{BLACK}Zmniejsz wysokość najwyższego szczytu na mapie o jeden poziom STR_MAPGEN_SNOW_COVERAGE :{BLACK}Pokrycie śniegiem: @@ -3624,8 +3624,8 @@ STR_MAPGEN_DESERT_COVERAGE_UP :{BLACK}Zwiększ STR_MAPGEN_DESERT_COVERAGE_DOWN :{BLACK}Zmniejsz pokrycie pustynią o 10% STR_MAPGEN_DESERT_COVERAGE_TEXT :{BLACK}{NUM}% STR_MAPGEN_TERRAIN_TYPE :{BLACK}Typ terenu: -STR_MAPGEN_SEA_LEVEL :{BLACK}Poziom wody: -STR_MAPGEN_SEA_LEVEL_TOOLTIP :{BLACK}Określ wysokość poziomu wody +STR_MAPGEN_SEA_LEVEL :{BLACK}Poziom morza: +STR_MAPGEN_SEA_LEVEL_TOOLTIP :{BLACK}Określ wysokość poziomu morza STR_MAPGEN_QUANTITY_OF_RIVERS :{BLACK}Liczba rzek: STR_MAPGEN_SMOOTHNESS :{BLACK}Gładkość: STR_MAPGEN_VARIETY :{BLACK}Różnorodność: diff --git a/src/lang/simplified_chinese.txt b/src/lang/simplified_chinese.txt index de399c5706..80d99e0d3d 100644 --- a/src/lang/simplified_chinese.txt +++ b/src/lang/simplified_chinese.txt @@ -1356,12 +1356,12 @@ STR_CONFIG_SETTING_INDUSTRY_PLATFORM_HELPTEXT :设置工厂周 STR_CONFIG_SETTING_MULTIPINDTOWN :允许在一个城镇中建设多个同类工业设施:{STRING} STR_CONFIG_SETTING_MULTIPINDTOWN_HELPTEXT :通常,城市不希望有多个相同类型工业,本设置“打开”时允许多个同类型工厂在同一个城市 -STR_CONFIG_SETTING_SIGNALSIDE :显示信号灯:{STRING} -STR_CONFIG_SETTING_SIGNALSIDE_HELPTEXT :选择在铁路哪一边放置信号灯 +STR_CONFIG_SETTING_SIGNALSIDE :铁路信号位置:{STRING} +STR_CONFIG_SETTING_SIGNALSIDE_HELPTEXT :选择在铁路的哪一侧放置信号。 ###length 3 -STR_CONFIG_SETTING_SIGNALSIDE_LEFT :在左边 +STR_CONFIG_SETTING_SIGNALSIDE_LEFT :左侧 STR_CONFIG_SETTING_SIGNALSIDE_DRIVING_SIDE :道路通行方向 -STR_CONFIG_SETTING_SIGNALSIDE_RIGHT :在右侧 +STR_CONFIG_SETTING_SIGNALSIDE_RIGHT :右侧 STR_CONFIG_SETTING_SHOWFINANCES :在年终显示财务报表:{STRING} STR_CONFIG_SETTING_SHOWFINANCES_HELPTEXT :“打开”时,在年底显示财务报表窗口,方便查看公司财务状况 @@ -1369,7 +1369,7 @@ STR_CONFIG_SETTING_SHOWFINANCES_HELPTEXT :“打开”时 STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT :新的调度命令默认为“不停车”: {STRING} STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT_HELPTEXT :通常,车辆在它经过的每一个车站都会停车。“打开”本选项时,车辆会不停车的通过所有中间车站前往最终目的地。注意:这只是为每一条新调度命令设置一个默认信息,仍然可以为每条调度命令设置明确的信息 -STR_CONFIG_SETTING_STOP_LOCATION :新列车调度计划中默认命令为停靠在站台{STRING} 位置 +STR_CONFIG_SETTING_STOP_LOCATION :新列车调度计划中默认命令为停靠在站台 {STRING} 位置 STR_CONFIG_SETTING_STOP_LOCATION_HELPTEXT :设置车辆在站台的默认停靠位置,“近端”是靠近车辆进入的那一端,“中间”是站台中间位置,“远端”是远离车辆进入的那一端。注意:本设定只改变新指令的默认设定。玩家仍可通过点击指令文字改变列车在某车站的停车位置。 ###length 3 STR_CONFIG_SETTING_STOP_LOCATION_NEAR_END :近端 @@ -1675,11 +1675,11 @@ STR_CONFIG_SETTING_QUICKGOTO :快速创建车 STR_CONFIG_SETTING_QUICKGOTO_HELPTEXT :启用时,打开调度计划窗口时预先选定“前往”命令 STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE :默认铁路类型 (新建/读取游戏后): {STRING} -STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_HELPTEXT :设置开启或者载入游戏时的默认铁路类型,“第一可用的”是最老的铁路类型,“最后一个可用”的是最新的铁路类型,“最常用的”是当前用的最多的铁路类型 +STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_HELPTEXT :设置开启或者载入游戏时的默认铁路类型,“最先可用的类型”是最老的铁路类型,“最新可用的类型”的是最新的铁路类型,“最常用的类型”是当前用的最多的铁路类型 ###length 3 -STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_FIRST :第一个可用的 -STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_LAST :第后一个可用的 -STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_MOST_USED :最常用的 +STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_FIRST :最先可用的类型 +STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_LAST :最新可用的类型 +STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_MOST_USED :最常用的类型 STR_CONFIG_SETTING_SHOW_TRACK_RESERVATION :显示预留的轨道: {STRING} STR_CONFIG_SETTING_SHOW_TRACK_RESERVATION_HELPTEXT :让预留的铁路轨道显示不同的颜色,以帮助查找列车拒绝进入路径轨道的原因 @@ -1754,10 +1754,10 @@ STR_CONFIG_SETTING_AI_PROFILE_HARD :困难 STR_CONFIG_SETTING_AI_IN_MULTIPLAYER :联机游戏时允许电脑玩家(AI): {STRING} STR_CONFIG_SETTING_AI_IN_MULTIPLAYER_HELPTEXT :“打开”时联机游戏允许电脑玩家 -STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES :可允许的最大的代码量(如超过则会令脚本被禁用):{STRING} -STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES_HELPTEXT :脚本在一个回合中可进行计算步数的最大值 +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_HELPTEXT :单个脚本强制终止前可占用的最大内存量。对于大地图可能需要增加。 +STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY_HELPTEXT :单个脚本(AI与游戏脚本)可使用的最大内存量,在游玩大型地图时可能需要增加。 STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY_VALUE :{COMMA} MiB STR_CONFIG_SETTING_SERVINT_ISPERCENT :维护间隔以百分比(%)计算: {STRING} @@ -1914,7 +1914,7 @@ STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT :树木自动生 STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_HELPTEXT :控制游戏中数目的随机生长,这将影响依赖树木的工业,比如木材厂 ###length 4 STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_NO_SPREAD :生长但不扩散 {RED}(损坏伐木场) -STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_SPREAD_RAINFOREST :只生长在雨林 +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_SPREAD_RAINFOREST :仅在雨林扩散 STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_SPREAD_ALL :生长并四处扩散 STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_NO_GROWTH_NO_SPREAD :不生长,不扩散 {RED}(损坏伐木场) @@ -3239,7 +3239,7 @@ STR_MAPGEN_SNOW_COVERAGE :{BLACK}雪地 STR_MAPGEN_SNOW_COVERAGE_UP :{BLACK}将雪地比率增加10% STR_MAPGEN_SNOW_COVERAGE_DOWN :{BLACK}将雪地比率减少10% STR_MAPGEN_SNOW_COVERAGE_TEXT :{BLACK}{NUM}% -STR_MAPGEN_DESERT_COVERAGE :{BLACK}沙漠覆盖率: +STR_MAPGEN_DESERT_COVERAGE :{BLACK}沙漠比率: STR_MAPGEN_DESERT_COVERAGE_UP :{BLACK}将沙漠比率增加10% STR_MAPGEN_DESERT_COVERAGE_DOWN :{BLACK}将沙漠比率减少10% STR_MAPGEN_DESERT_COVERAGE_TEXT :{BLACK}{NUM}% @@ -3304,7 +3304,7 @@ STR_MAPGEN_HEIGHTMAP_SIZE :{ORANGE}{NUM} STR_MAPGEN_TERRAIN_TYPE_QUERY_CAPT :{WHITE}最高峰目标高度 STR_MAPGEN_HEIGHTMAP_HEIGHT_QUERY_CAPT :{WHITE}最高峰 STR_MAPGEN_SNOW_COVERAGE_QUERY_CAPT :{WHITE}积雪覆盖率 (百分比) -STR_MAPGEN_DESERT_COVERAGE_QUERY_CAPT :{WHITE}沙漠覆盖率 (百分比) +STR_MAPGEN_DESERT_COVERAGE_QUERY_CAPT :{WHITE}沙漠比率 (百分比) STR_MAPGEN_START_DATE_QUERY_CAPT :{WHITE}改变游戏开始的日期 # SE Map generation @@ -3375,7 +3375,7 @@ STR_NEWGRF_SETTINGS_FILENAME :{BLACK}文件 STR_NEWGRF_SETTINGS_GRF_ID :{BLACK}GRF ID:{SILVER}{STRING} STR_NEWGRF_SETTINGS_VERSION :{BLACK}版本: {SILVER}{NUM} STR_NEWGRF_SETTINGS_MIN_VERSION :{BLACK}最低兼容版本: {SILVER}{NUM} -STR_NEWGRF_SETTINGS_MD5SUM :{BLACK}MD5 码:{SILVER}{STRING} +STR_NEWGRF_SETTINGS_MD5SUM :{BLACK}MD5码:{SILVER}{STRING} STR_NEWGRF_SETTINGS_PALETTE :{BLACK}调色板: {SILVER}{STRING} STR_NEWGRF_SETTINGS_PALETTE_DEFAULT :默认 (DOS) STR_NEWGRF_SETTINGS_PALETTE_DEFAULT_32BPP :默认 (DOS) / 32 bpp diff --git a/src/library_loader.h b/src/library_loader.h new file mode 100644 index 0000000000..1a5e09483c --- /dev/null +++ b/src/library_loader.h @@ -0,0 +1,116 @@ +/* + * 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 library_loader.h Functions/types related to loading libraries dynamically. */ + +#ifndef LIBRARY_LOADER_H +#define LIBRARY_LOADER_H + +#include +#include +#include + +class LibraryLoader { +public: + /** + * A function loaded from a library. + * + * Will automatically cast to the correct function pointer type on retrieval. + */ + class Function { + public: + explicit Function(void *p) : p(p) {} + + template >> + operator T *() const + { + return reinterpret_cast(this->p); + } + + private: + void *p; + }; + + /** + * Load a library with the given filename. + */ + explicit LibraryLoader(const std::string &filename) + { + this->handle = this->OpenLibrary(filename); + } + + /** + * Close the library. + */ + ~LibraryLoader() + { + if (this->handle != nullptr) { + this->CloseLibrary(); + } + } + + /** + * Check whether an error occurred while loading the library or a function. + * + * @return Whether an error occurred. + */ + bool HasError() + { + return this->error.has_value(); + } + + /** + * Get the last error that occurred while loading the library or a function. + * + * @return The error message. + */ + std::string GetLastError() + { + return this->error.value_or("No error"); + } + + /** + * Get a function from a loaded library. + * + * @param symbol_name The name of the function to get. + * @return The function. Check HasError() before using. + */ + Function GetFunction(const std::string &symbol_name) + { + if (this->error.has_value()) return Function(nullptr); + return Function(this->GetSymbol(symbol_name)); + } + +private: + /** + * Open the library with the given filename. + * + * Should set error if any error occurred. + * + * @param filename The filename of the library to open. + */ + void *OpenLibrary(const std::string &filename); + + /** + * Close the library. + */ + void CloseLibrary(); + + /** + * Get a symbol from the library. + * + * Should set error if any error occurred. + * + * @param symbol_name The name of the symbol to get. + */ + void *GetSymbol(const std::string &symbol_name); + + std::optional error = {}; ///< The last error that occurred, if set. + void *handle = nullptr; ///< Handle to the library. +}; + +#endif /* LIBRARY_LOADER_H */ diff --git a/src/os/unix/CMakeLists.txt b/src/os/unix/CMakeLists.txt index 1e8bb5d63d..f6c40d015f 100644 --- a/src/os/unix/CMakeLists.txt +++ b/src/os/unix/CMakeLists.txt @@ -5,6 +5,7 @@ add_files( ) add_files( + library_loader_unix.cpp unix.cpp CONDITION UNIX ) diff --git a/src/os/unix/library_loader_unix.cpp b/src/os/unix/library_loader_unix.cpp new file mode 100644 index 0000000000..471f1faa2a --- /dev/null +++ b/src/os/unix/library_loader_unix.cpp @@ -0,0 +1,64 @@ +/* + * 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 library_loader_unix.cpp Implementation of the LibraryLoader for Linux / MacOS */ + +#include "../../stdafx.h" + +#include + +#include "../../library_loader.h" + +#include "../../safeguards.h" + +/* Emscripten cannot dynamically load other files. */ +#if defined(__EMSCRIPTEN__) + +void *LibraryLoader::OpenLibrary(const std::string &) +{ + this->error = "Dynamic loading is not supported on this platform."; + return nullptr; +} + +void LibraryLoader::CloseLibrary() +{ +} + +void *LibraryLoader::GetSymbol(const std::string &) +{ + this->error = "Dynamic loading is not supported on this platform."; + return nullptr; +} + +#else + +void *LibraryLoader::OpenLibrary(const std::string &filename) +{ + void *h = dlopen(filename.c_str(), RTLD_NOW | RTLD_LOCAL); + if (h == nullptr) { + this->error = dlerror(); + } + + return h; +} + +void LibraryLoader::CloseLibrary() +{ + dlclose(this->handle); +} + +void *LibraryLoader::GetSymbol(const std::string &symbol_name) +{ + void *p = dlsym(this->handle, symbol_name.c_str()); + if (p == nullptr) { + this->error = dlerror(); + } + + return p; +} + +#endif /* __EMSCRIPTEN__ */ diff --git a/src/os/windows/CMakeLists.txt b/src/os/windows/CMakeLists.txt index 9215514fa2..dd446f7ac6 100644 --- a/src/os/windows/CMakeLists.txt +++ b/src/os/windows/CMakeLists.txt @@ -2,6 +2,7 @@ add_files( crashlog_win.cpp font_win32.cpp font_win32.h + library_loader_win.cpp string_uniscribe.cpp string_uniscribe.h survey_win.cpp diff --git a/src/os/windows/crashlog_win.cpp b/src/os/windows/crashlog_win.cpp index 53520044c5..234974a629 100644 --- a/src/os/windows/crashlog_win.cpp +++ b/src/os/windows/crashlog_win.cpp @@ -19,6 +19,7 @@ #include "../../gamelog.h" #include "../../sl/saveload.h" #include "../../video/video_driver.hpp" +#include "../../library_loader.h" #include "../../screenshot.h" #include "../../debug.h" #include "../../settings_type.h" @@ -334,22 +335,7 @@ static const uint MAX_FRAMES = 64; /* virtual */ char *CrashLogWindows::LogStacktrace(char *buffer, const char *last) const { -#define M(x) x "\0" - static const char dbg_import[] = - M("dbghelp.dll") - M("SymInitialize") - M("SymSetOptions") - M("SymCleanup") - M("StackWalk64") - M("SymFunctionTableAccess64") - M("SymGetModuleBase64") - M("SymGetModuleInfo64") - M("SymGetSymFromAddr64") - M("SymGetLineFromAddr64") - M("") - ; -#undef M - + LibraryLoader dbghelp("dbghelp.dll"); struct ProcPtrs { BOOL (WINAPI * pSymInitialize)(HANDLE, PCSTR, BOOL); BOOL (WINAPI * pSymSetOptions)(DWORD); @@ -360,12 +346,22 @@ static const uint MAX_FRAMES = 64; BOOL (WINAPI * pSymGetModuleInfo64)(HANDLE, DWORD64, PIMAGEHLP_MODULE64); BOOL (WINAPI * pSymGetSymFromAddr64)(HANDLE, DWORD64, PDWORD64, PIMAGEHLP_SYMBOL64); BOOL (WINAPI * pSymGetLineFromAddr64)(HANDLE, DWORD64, PDWORD, PIMAGEHLP_LINE64); - } proc; + } proc = { + dbghelp.GetFunction("SymInitialize"), + dbghelp.GetFunction("SymSetOptions"), + dbghelp.GetFunction("SymCleanup"), + dbghelp.GetFunction("StackWalk64"), + dbghelp.GetFunction("SymFunctionTableAccess64"), + dbghelp.GetFunction("SymGetModuleBase64"), + dbghelp.GetFunction("SymGetModuleInfo64"), + dbghelp.GetFunction("SymGetSymFromAddr64"), + dbghelp.GetFunction("SymGetLineFromAddr64"), + }; buffer += seprintf(buffer, last, "Decoded stack trace:\n"); /* Try to load the functions from the DLL, if that fails because of a too old dbghelp.dll, just skip it. */ - if (LoadLibraryList((Function*)&proc, dbg_import)) { + if (!dbghelp.HasError()) { /* Initialize symbol handler. */ HANDLE hCur = GetCurrentProcess(); proc.pSymInitialize(hCur, nullptr, TRUE); @@ -522,12 +518,12 @@ static const uint MAX_FRAMES = 64; int ret = 0; HMODULE dbghelp = LoadLibrary(L"dbghelp.dll"); if (dbghelp != nullptr) { - typedef BOOL (WINAPI *MiniDumpWriteDump_t)(HANDLE, DWORD, HANDLE, + typedef BOOL (WINAPI *MiniDumpWriteDumpT)(HANDLE, DWORD, HANDLE, MINIDUMP_TYPE, CONST PMINIDUMP_EXCEPTION_INFORMATION, CONST PMINIDUMP_USER_STREAM_INFORMATION, CONST PMINIDUMP_CALLBACK_INFORMATION); - MiniDumpWriteDump_t funcMiniDumpWriteDump = GetProcAddressT(dbghelp, "MiniDumpWriteDump"); + MiniDumpWriteDumpT funcMiniDumpWriteDump = (MiniDumpWriteDumpT) GetProcAddress(dbghelp, "MiniDumpWriteDump"); if (funcMiniDumpWriteDump != nullptr) { seprintf(filename, filename_last, "%scrash.dmp", _personal_dir.c_str()); HANDLE file = CreateFile(OTTD2FS(filename).c_str(), GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, 0, 0); @@ -751,7 +747,9 @@ static void CDECL CustomAbort(int) using VEX_HANDLER_TYPE = LONG WINAPI (EXCEPTION_POINTERS *); void* (WINAPI *AddVectoredExceptionHandler)(ULONG, VEX_HANDLER_TYPE*); - if (LoadLibraryList((Function*)&AddVectoredExceptionHandler, "kernel32.dll\0AddVectoredExceptionHandler\0\0")) { + static LibraryLoader _kernel32("Kernel32.dll"); + AddVectoredExceptionHandler = _kernel32.GetFunction("AddVectoredExceptionHandler"); + if (AddVectoredExceptionHandler != nullptr) { AddVectoredExceptionHandler(1, VectoredExceptionHandler); } } diff --git a/src/os/windows/font_win32.cpp b/src/os/windows/font_win32.cpp index 48ef580762..132d51059b 100644 --- a/src/os/windows/font_win32.cpp +++ b/src/os/windows/font_win32.cpp @@ -14,9 +14,10 @@ #include "../../core/math_func.hpp" #include "../../core/mem_func.hpp" #include "../../fileio_func.h" -#include "../../fontdetection.h" #include "../../fontcache.h" #include "../../fontcache/truetypefontcache.h" +#include "../../fontdetection.h" +#include "../../library_loader.h" #include "../../string_func.h" #include "../../strings_func.h" #include "../../zoom_func.h" @@ -358,8 +359,9 @@ void LoadWin32Font(FontSize fs) if (AddFontResourceEx(fontPath, FR_PRIVATE, 0) != 0) { /* Try a nice little undocumented function first for getting the internal font name. * Some documentation is found at: http://www.undocprint.org/winspool/getfontresourceinfo */ + static LibraryLoader _gdi32("gdi32.dll"); typedef BOOL(WINAPI *PFNGETFONTRESOURCEINFO)(LPCTSTR, LPDWORD, LPVOID, DWORD); - static PFNGETFONTRESOURCEINFO GetFontResourceInfo = GetProcAddressT(GetModuleHandle(L"Gdi32"), "GetFontResourceInfoW"); + static PFNGETFONTRESOURCEINFO GetFontResourceInfo = _gdi32.GetFunction("GetFontResourceInfoW"); if (GetFontResourceInfo != nullptr) { /* Try to query an array of LOGFONTs that describe the file. */ diff --git a/src/os/windows/font_win32.h b/src/os/windows/font_win32.h index 7ef5568601..02a84b63fc 100644 --- a/src/os/windows/font_win32.h +++ b/src/os/windows/font_win32.h @@ -13,6 +13,8 @@ #include "../../fontcache/truetypefontcache.h" #include "win32.h" +#include + /** Font cache for fonts that are based on a Win32 font. */ class Win32FontCache : public TrueTypeFontCache { private: diff --git a/src/os/windows/library_loader_win.cpp b/src/os/windows/library_loader_win.cpp new file mode 100644 index 0000000000..838a2117f4 --- /dev/null +++ b/src/os/windows/library_loader_win.cpp @@ -0,0 +1,59 @@ +/* + * 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 library_loader_win.cpp Implementation of the LibraryLoader for Windows */ + +#include "../../stdafx.h" + +#include + +#include "../../library_loader.h" +#include "../../core/format.hpp" + +#include "../../safeguards.h" + +static std::string GetLoadError() +{ + auto error_code = GetLastError(); + + char buffer[512]; + if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, error_code, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buffer, sizeof(buffer), nullptr) == 0) { + return fmt::format("Unknown error {}", error_code); + } + + return buffer; +} + +void *LibraryLoader::OpenLibrary(const std::string &filename) +{ + void *h = ::LoadLibraryW(OTTD2FS(filename).c_str()); + if (h == nullptr) { + this->error = GetLoadError(); + } + + return h; +} + +void LibraryLoader::CloseLibrary() +{ + HMODULE handle = static_cast(this->handle); + + ::FreeLibrary(handle); +} + +void *LibraryLoader::GetSymbol(const std::string &symbol_name) +{ + HMODULE handle = static_cast(this->handle); + + void *p = reinterpret_cast(::GetProcAddress(handle, symbol_name.c_str())); + if (p == nullptr) { + this->error = GetLoadError(); + } + + return p; +} diff --git a/src/os/windows/string_uniscribe.cpp b/src/os/windows/string_uniscribe.cpp index 1af78b811b..b41fa75415 100644 --- a/src/os/windows/string_uniscribe.cpp +++ b/src/os/windows/string_uniscribe.cpp @@ -418,7 +418,7 @@ static std::vector UniscribeItemizeString(UniscribeParagraphLayoutF UniscribeRun run = *i_run; /* Partial run after line break (either start or end)? Reshape run to get the first/last glyphs right. */ - if (i_run == last_run - 1 && remaining_offset < (last_run - 1)->len) { + if (i_run == last_run - 1 && remaining_offset <= (last_run - 1)->len) { run.len = remaining_offset - 1; if (!UniscribeShapeRun(this->text_buffer, run)) return nullptr; diff --git a/src/os/windows/win32.cpp b/src/os/windows/win32.cpp index b0c07d2b03..d20f4c267f 100644 --- a/src/os/windows/win32.cpp +++ b/src/os/windows/win32.cpp @@ -31,12 +31,17 @@ #include #include "../../language.h" #include "../../thread.h" +#include "../../library_loader.h" #include #include #include #include "../../safeguards.h" +#if defined(__MINGW32__) && !defined(__MINGW64__) && !(_WIN32_IE >= 0x0500) +#define SHGFP_TYPE_CURRENT 0 +#endif /* __MINGW32__ */ + static bool _has_console; static bool _cursor_disable = true; static bool _cursor_visible = true; @@ -53,30 +58,6 @@ bool MyShowCursor(bool show, bool toggle) return !show; } -/** - * Helper function needed by dynamically loading libraries - */ -bool LoadLibraryList(Function proc[], const char *dll) -{ - while (*dll != '\0') { - HMODULE lib; - lib = LoadLibrary(OTTD2FS(dll).c_str()); - - if (lib == nullptr) return false; - for (;;) { - Function p; - - while (*dll++ != '\0') { /* Nothing */ } - if (*dll == '\0') break; - p = GetProcAddressT(lib, dll); - if (p == nullptr) return false; - *proc++ = p; - } - dll++; - } - return true; -} - void ShowOSErrorBox(const char *buf, bool system) { MyShowCursor(true); @@ -614,7 +595,8 @@ int OTTDStringCompare(std::string_view s1, std::string_view s2) #endif if (first_time) { - _CompareStringEx = GetProcAddressT(GetModuleHandle(L"Kernel32"), "CompareStringEx"); + static LibraryLoader _kernel32("Kernel32.dll"); + _CompareStringEx = _kernel32.GetFunction("CompareStringEx"); first_time = false; } @@ -657,7 +639,8 @@ int Win32StringContains(const std::string_view str, const std::string_view value static bool first_time = true; if (first_time) { - _FindNLSStringEx = GetProcAddressT(GetModuleHandle(L"Kernel32"), "FindNLSStringEx"); + static LibraryLoader _kernel32("Kernel32.dll"); + _FindNLSStringEx = _kernel32.GetFunction("FindNLSStringEx"); first_time = false; } @@ -704,7 +687,8 @@ void PerThreadSetup() void PerThreadSetupInit() { - LoadLibraryList((Function*)&_SetThreadStackGuarantee, "kernel32.dll\0SetThreadStackGuarantee\0\0"); + static LibraryLoader _kernel32("Kernel32.dll"); + _SetThreadStackGuarantee = _kernel32.GetFunction("SetThreadStackGuarantee"); } bool IsMainThread() diff --git a/src/os/windows/win32.h b/src/os/windows/win32.h index 9a354bf168..6163085c1d 100644 --- a/src/os/windows/win32.h +++ b/src/os/windows/win32.h @@ -10,19 +10,11 @@ #ifndef WIN32_H #define WIN32_H -#include bool MyShowCursor(bool show, bool toggle = false); -typedef void (*Function)(int); -bool LoadLibraryList(Function proc[], const char *dll); - char *convert_from_fs(const wchar_t *name, char *utf8_buf, size_t buflen); wchar_t *convert_to_fs(const std::string_view name, wchar_t *utf16_buf, size_t buflen); -#if defined(__MINGW32__) && !defined(__MINGW64__) && !(_WIN32_IE >= 0x0500) -#define SHGFP_TYPE_CURRENT 0 -#endif /* __MINGW32__ */ - void Win32SetCurrentLocaleName(const char *iso_code); int OTTDStringCompare(std::string_view s1, std::string_view s2); int Win32StringContains(const std::string_view str, const std::string_view value, bool case_insensitive); @@ -33,12 +25,6 @@ int Win32StringContains(const std::string_view str, const std::string_view value #pragma GCC diagnostic ignored "-Wcast-function-type" #endif /* __MINGW32__ */ -template -T GetProcAddressT(HMODULE hModule, LPCSTR lpProcName) -{ - return reinterpret_cast(GetProcAddress(hModule, lpProcName)); -} - #ifdef __MINGW32__ #pragma GCC diagnostic pop #endif diff --git a/src/script/api/script_list.cpp b/src/script/api/script_list.cpp index 07e73b7d78..7558159081 100644 --- a/src/script/api/script_list.cpp +++ b/src/script/api/script_list.cpp @@ -9,7 +9,6 @@ #include "../../stdafx.h" #include "script_list.hpp" -#include "script_controller.hpp" #include "../../debug.h" #include "../../script/squirrel.hpp" @@ -1074,16 +1073,6 @@ SQInteger ScriptList::Valuate(HSQUIRRELVM vm) } } - /* Kill the script when the valuator call takes way too long. - * Triggered by nesting valuators, which then take billions of iterations. */ - if (ScriptController::GetOpsTillSuspend() < -1000000) { - /* See below for explanation. The extra pop is the return value. */ - sq_pop(vm, nparam + 4); - - ScriptObject::SetAllowDoCommand(backup_allow); - return sq_throwerror(vm, "excessive CPU usage in valuator function"); - } - /* Was something changed? */ if (previous_modification_count != this->modifications) { /* See below for explanation. The extra pop is the return value. */ diff --git a/src/sound/xaudio2_s.cpp b/src/sound/xaudio2_s.cpp index 0984e4f016..e84d8f9c32 100644 --- a/src/sound/xaudio2_s.cpp +++ b/src/sound/xaudio2_s.cpp @@ -158,7 +158,7 @@ const char *SoundDriver_XAudio2::Start(const StringList &parm) return "Failed to load XAudio2 DLL"; } - API_XAudio2Create xAudio2Create = GetProcAddressT(_xaudio_dll_handle, "XAudio2Create"); + API_XAudio2Create xAudio2Create = (API_XAudio2Create) GetProcAddress(_xaudio_dll_handle, "XAudio2Create"); if (xAudio2Create == nullptr) { diff --git a/src/video/win32_v.cpp b/src/video/win32_v.cpp index 58585860b8..1e5afce11f 100644 --- a/src/video/win32_v.cpp +++ b/src/video/win32_v.cpp @@ -21,6 +21,7 @@ #include "../window_gui.h" #include "../window_func.h" #include "../framerate_type.h" +#include "../library_loader.h" #include "win32_v.h" #include #include @@ -987,10 +988,11 @@ float VideoDriver_Win32Base::GetDPIScale() static bool init_done = false; if (!init_done) { init_done = true; - - _GetDpiForWindow = GetProcAddressT(GetModuleHandle(L"User32"), "GetDpiForWindow"); - _GetDpiForSystem = GetProcAddressT(GetModuleHandle(L"User32"), "GetDpiForSystem"); - _GetDpiForMonitor = GetProcAddressT(LoadLibrary(L"Shcore.dll"), "GetDpiForMonitor"); + static LibraryLoader _user32("user32.dll"); + static LibraryLoader _shcore("shcore.dll"); + _GetDpiForWindow = _user32.GetFunction("GetDpiForWindow"); + _GetDpiForSystem = _user32.GetFunction("GetDpiForSystem"); + _GetDpiForMonitor = _shcore.GetFunction("GetDpiForMonitor"); } UINT cur_dpi = 0; diff --git a/src/video/win32_v.h b/src/video/win32_v.h index d0a70cfd4d..516d8a84d8 100644 --- a/src/video/win32_v.h +++ b/src/video/win32_v.h @@ -14,6 +14,7 @@ #include #include #include +#include /** Base class for Windows video drivers. */ class VideoDriver_Win32Base : public VideoDriver {