Add handling of mods manifests
Also add Polish translations for mod manager related strings.pyro-refactor
parent
eac74c23ec
commit
f57da76ae8
|
@ -189,7 +189,7 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
|||
set(NORMAL_CXX_FLAGS "/wd\"4244\" /wd\"4309\" /wd\"4800\" /wd\"4996\" /wd\"4351\" /EHsc") # disable some useless warnings
|
||||
if(MSVC_STATIC)
|
||||
set(RELEASE_CXX_FLAGS "/MT /Ox")
|
||||
set(DEBUG_CXX_FLAGS "/MTd /ZI")
|
||||
set(DEBUG_CXX_FLAGS "/MTd /Od /ZI")
|
||||
else(MSVC_STATIC)
|
||||
set(RELEASE_CXX_FLAGS "/MD /Ox")
|
||||
set(DEBUG_CXX_FLAGS "/MDd /Od /ZI")
|
||||
|
|
|
@ -123,21 +123,6 @@ msgstr ""
|
|||
msgid "2) Then press the key you want to use instead."
|
||||
msgstr ""
|
||||
|
||||
msgid "Mods:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Information:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Description:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Enable\\Enable the selected mod"
|
||||
msgstr ""
|
||||
|
||||
msgid "Disable\\Disable the selected mod"
|
||||
msgstr ""
|
||||
|
||||
msgid "Face type:"
|
||||
msgstr ""
|
||||
|
||||
|
@ -315,6 +300,36 @@ msgstr ""
|
|||
msgid "%s: %d pts"
|
||||
msgstr ""
|
||||
|
||||
msgid "Mods:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Information:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Description:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Enable\\Enable the selected mod"
|
||||
msgstr ""
|
||||
|
||||
msgid "Disable\\Disable the selected mod"
|
||||
msgstr ""
|
||||
|
||||
msgid "Unknown author"
|
||||
msgstr ""
|
||||
|
||||
msgid "by"
|
||||
msgstr ""
|
||||
|
||||
msgid "Version"
|
||||
msgstr ""
|
||||
|
||||
msgid "Website"
|
||||
msgstr ""
|
||||
|
||||
msgid "No description."
|
||||
msgstr ""
|
||||
|
||||
msgid "Code battle"
|
||||
msgstr ""
|
||||
|
||||
|
|
17
po/cs.po
17
po/cs.po
|
@ -988,6 +988,10 @@ msgstr "Další objekt\\Vybere následující objekt"
|
|||
msgid "No"
|
||||
msgstr "Ne"
|
||||
|
||||
#, fuzzy
|
||||
msgid "No description."
|
||||
msgstr "Rozlišení:"
|
||||
|
||||
msgid "No energy in the subsoil"
|
||||
msgstr "Pod povrchem není zdroj energie"
|
||||
|
||||
|
@ -1735,6 +1739,10 @@ msgstr "Jednotka"
|
|||
msgid "Unknown Object"
|
||||
msgstr "Neznámý objekt"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Unknown author"
|
||||
msgstr "Neznámá funkce"
|
||||
|
||||
msgid "Unknown command"
|
||||
msgstr "Neznámý příkaz"
|
||||
|
||||
|
@ -1771,6 +1779,9 @@ msgstr "Proměnná nebyla nastavena"
|
|||
msgid "Vault"
|
||||
msgstr "Trezor"
|
||||
|
||||
msgid "Version"
|
||||
msgstr ""
|
||||
|
||||
msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1789,6 +1800,9 @@ msgstr "Vosa byla smrtelně raněna"
|
|||
msgid "Waste"
|
||||
msgstr "Odpad"
|
||||
|
||||
msgid "Website"
|
||||
msgstr ""
|
||||
|
||||
msgid "Wheeled builder"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1975,6 +1989,9 @@ msgstr "\\Fialové vlajky"
|
|||
msgid "\\Yellow flags"
|
||||
msgstr "\\Žluté vlajky"
|
||||
|
||||
msgid "by"
|
||||
msgstr ""
|
||||
|
||||
msgid "colobot.info"
|
||||
msgstr "colobot.info"
|
||||
|
||||
|
|
17
po/de.po
17
po/de.po
|
@ -1004,6 +1004,10 @@ msgstr "Nächstes auswählen\\Nächstes Objekt auswählen"
|
|||
msgid "No"
|
||||
msgstr "Nein"
|
||||
|
||||
#, fuzzy
|
||||
msgid "No description."
|
||||
msgstr "Auflösung:"
|
||||
|
||||
msgid "No energy in the subsoil"
|
||||
msgstr "Kein unterirdisches Energievorkommen"
|
||||
|
||||
|
@ -1752,6 +1756,10 @@ msgstr "Einheit"
|
|||
msgid "Unknown Object"
|
||||
msgstr "Das Objekt existiert nicht"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Unknown author"
|
||||
msgstr "Unbekannte Funktion"
|
||||
|
||||
msgid "Unknown command"
|
||||
msgstr "Befehl unbekannt"
|
||||
|
||||
|
@ -1788,6 +1796,9 @@ msgstr "Der Wert dieser Variable wurde nicht definiert"
|
|||
msgid "Vault"
|
||||
msgstr "Bunker"
|
||||
|
||||
msgid "Version"
|
||||
msgstr ""
|
||||
|
||||
msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1806,6 +1817,9 @@ msgstr "Wespe tödlich verwundet"
|
|||
msgid "Waste"
|
||||
msgstr "Abfall"
|
||||
|
||||
msgid "Website"
|
||||
msgstr ""
|
||||
|
||||
msgid "Wheeled builder"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1990,6 +2004,9 @@ msgstr "\\Violette Fahne"
|
|||
msgid "\\Yellow flags"
|
||||
msgstr "\\Gelbe Fahne"
|
||||
|
||||
msgid "by"
|
||||
msgstr ""
|
||||
|
||||
msgid "colobot.info"
|
||||
msgstr "colobot.info"
|
||||
|
||||
|
|
17
po/fr.po
17
po/fr.po
|
@ -1006,6 +1006,10 @@ msgstr "Sélectionner l'objet suivant\\Sélectionner l'objet suivant"
|
|||
msgid "No"
|
||||
msgstr "Non"
|
||||
|
||||
#, fuzzy
|
||||
msgid "No description."
|
||||
msgstr "Résolutions :"
|
||||
|
||||
msgid "No energy in the subsoil"
|
||||
msgstr "Pas d'énergie en sous-sol"
|
||||
|
||||
|
@ -1754,6 +1758,10 @@ msgstr "Unité"
|
|||
msgid "Unknown Object"
|
||||
msgstr "Objet inconnu"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Unknown author"
|
||||
msgstr "Routine inconnue"
|
||||
|
||||
msgid "Unknown command"
|
||||
msgstr "Commande inconnue"
|
||||
|
||||
|
@ -1790,6 +1798,9 @@ msgstr "Variable non initialisée"
|
|||
msgid "Vault"
|
||||
msgstr "Coffre-fort"
|
||||
|
||||
msgid "Version"
|
||||
msgstr ""
|
||||
|
||||
msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency"
|
||||
msgstr "Synchronisation verticale :\\Réduit la fréquence d'images par seconde à afficher."
|
||||
|
||||
|
@ -1808,6 +1819,9 @@ msgstr "Guêpe mortellement touchée"
|
|||
msgid "Waste"
|
||||
msgstr "Déchet"
|
||||
|
||||
msgid "Website"
|
||||
msgstr ""
|
||||
|
||||
msgid "Wheeled builder"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1992,6 +2006,9 @@ msgstr "\\Drapeaux violets"
|
|||
msgid "\\Yellow flags"
|
||||
msgstr "\\Drapeaux jaunes"
|
||||
|
||||
msgid "by"
|
||||
msgstr ""
|
||||
|
||||
msgid "colobot.info"
|
||||
msgstr "colobot.info"
|
||||
|
||||
|
|
46
po/pl.po
46
po/pl.po
|
@ -125,7 +125,7 @@ msgid "Apply changes\\Activates the changed settings"
|
|||
msgstr "Zastosuj zmiany\\Aktywuje zmienione ustawienia"
|
||||
|
||||
msgid "Apply\\Apply the current mod configuration"
|
||||
msgstr ""
|
||||
msgstr "Zastosuj\\Zastosuj obecną konfigurację modów"
|
||||
|
||||
msgid "Appropriate constructor missing"
|
||||
msgstr "Brak odpowiedniego konstruktora"
|
||||
|
@ -481,9 +481,8 @@ msgstr "Kopalnia"
|
|||
msgid "Descend\\Reduces the power of the jet"
|
||||
msgstr "W dół\\Zmniejsza moc silnika"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Description:"
|
||||
msgstr "Rozdzielczość:"
|
||||
msgstr "Opis:"
|
||||
|
||||
msgid "Destroy"
|
||||
msgstr "Zniszcz"
|
||||
|
@ -497,9 +496,8 @@ msgstr "Destroyer"
|
|||
msgid "Device\\Driver and resolution settings"
|
||||
msgstr "Urządzenie\\Ustawienia sterownika i rozdzielczości"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Disable\\Disable the selected mod"
|
||||
msgstr "Usuń\\Usuwa zaznaczony plik"
|
||||
msgstr "Wyłącz\\Wyłącza zaznaczonego moda"
|
||||
|
||||
msgid "Dividing by zero"
|
||||
msgstr "Dzielenie przez zero"
|
||||
|
@ -518,7 +516,7 @@ msgid "Down (\\key gdown;)"
|
|||
msgstr "Dół (\\key gdown;)"
|
||||
|
||||
msgid "Down\\Move the selected mod down so it's loaded later (mods may overwrite files from the mods above them)"
|
||||
msgstr ""
|
||||
msgstr "W dół\\Przenieś zaznaczonego moda w dół, aby był załadowany później (mody mogą nadpisywać pliki modów wyżej)"
|
||||
|
||||
msgid "Drawer bot"
|
||||
msgstr "Robot rysownik"
|
||||
|
@ -547,9 +545,8 @@ msgstr "Jajo"
|
|||
msgid "Empty character constant"
|
||||
msgstr ""
|
||||
|
||||
#, fuzzy
|
||||
msgid "Enable\\Enable the selected mod"
|
||||
msgstr "Wczytaj\\Wczytuje zaznaczoną misję"
|
||||
msgstr "Włącz\\Włącza zaznaczonego moda"
|
||||
|
||||
msgid "End of block missing"
|
||||
msgstr "Brak końca bloku"
|
||||
|
@ -778,7 +775,7 @@ msgid "Information exchange post"
|
|||
msgstr "Stacja przekaźnikowa informacji"
|
||||
|
||||
msgid "Information:"
|
||||
msgstr ""
|
||||
msgstr "Informacje:"
|
||||
|
||||
msgid "Instruction \"break\" outside a loop"
|
||||
msgstr "Polecenie \"break\" na zewnątrz pętli"
|
||||
|
@ -931,13 +928,13 @@ msgid "Missions\\Select mission"
|
|||
msgstr "Misje\\Wybierz misję"
|
||||
|
||||
msgid "Mods"
|
||||
msgstr ""
|
||||
msgstr "Mody"
|
||||
|
||||
msgid "Mods:"
|
||||
msgstr ""
|
||||
msgstr "Mody:"
|
||||
|
||||
msgid "Mods\\Mod manager"
|
||||
msgstr ""
|
||||
msgstr "Mody\\Zarządzanie modami"
|
||||
|
||||
msgid "Mouse inversion X\\Inversion of the scrolling direction on the X axis"
|
||||
msgstr "Odwrócenie myszy X\\Odwrócenie kierunków przewijania w poziomie"
|
||||
|
@ -987,6 +984,9 @@ msgstr "Następny obiekt\\Zaznacza następny obiekt"
|
|||
msgid "No"
|
||||
msgstr "Nie"
|
||||
|
||||
msgid "No description."
|
||||
msgstr "Brak opisu."
|
||||
|
||||
msgid "No energy in the subsoil"
|
||||
msgstr "Brak energii w ziemi"
|
||||
|
||||
|
@ -1108,7 +1108,7 @@ msgid "Open (Ctrl+O)"
|
|||
msgstr "Otwórz (Ctrl+O)"
|
||||
|
||||
msgid "Open Directory\\Open the mods directory"
|
||||
msgstr ""
|
||||
msgstr "Otwórz katalog\\Otwórz katalog z modami"
|
||||
|
||||
msgid "Opening brace missing"
|
||||
msgstr "Brak klamry otwierającej"
|
||||
|
@ -1321,7 +1321,7 @@ msgid "Reflections on the buttons \\Shiny buttons"
|
|||
msgstr "Odbicia na przyciskach \\Świecące przyciski"
|
||||
|
||||
msgid "Refresh\\Refresh the list of currently installed mods"
|
||||
msgstr ""
|
||||
msgstr "Odśwież\\Odśwież listę obecnie zainstalowanych modów"
|
||||
|
||||
msgid "Remains of Apollo mission"
|
||||
msgstr "Pozostałości z misji Apollo"
|
||||
|
@ -1608,7 +1608,7 @@ msgid "The types of the two operands are incompatible"
|
|||
msgstr "Niezgodne typy operatorów"
|
||||
|
||||
msgid "There are unsaved changes. Do you want to save them before leaving?"
|
||||
msgstr ""
|
||||
msgstr "Są niezapisane zmiany. Czy chcesz je zapisać przed wyjściem?"
|
||||
|
||||
msgid "This class already exists"
|
||||
msgstr "Taka klasa już istnieje"
|
||||
|
@ -1734,6 +1734,9 @@ msgstr "Jednostka"
|
|||
msgid "Unknown Object"
|
||||
msgstr "Obiekt nieznany"
|
||||
|
||||
msgid "Unknown author"
|
||||
msgstr "Nieznany autor"
|
||||
|
||||
msgid "Unknown command"
|
||||
msgstr "Nieznane polecenie"
|
||||
|
||||
|
@ -1747,7 +1750,7 @@ msgid "Up (\\key gup;)"
|
|||
msgstr "Góra (\\key gup;)"
|
||||
|
||||
msgid "Up\\Move the selected mod up so it's loaded sooner (mods may overwrite files from the mods above them)"
|
||||
msgstr ""
|
||||
msgstr "W górę\\Przenieś zaznaczonego moda w górę, aby był załadowany wcześniej (mody mogą nadpisywać pliki modów wyżej)"
|
||||
|
||||
msgid "Uranium deposit (site for derrick)"
|
||||
msgstr "Złoże uranu (miejsce na kopalnię)"
|
||||
|
@ -1770,6 +1773,9 @@ msgstr "Zmienna nie została zainicjalizowana"
|
|||
msgid "Vault"
|
||||
msgstr "Skrytka"
|
||||
|
||||
msgid "Version"
|
||||
msgstr "Wersja"
|
||||
|
||||
msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency"
|
||||
msgstr "Synchronizacja pionowa\\Ogranicza ilość klatek na sekundę do wartości odświeżania ekranu"
|
||||
|
||||
|
@ -1788,6 +1794,9 @@ msgstr "Osa śmiertelnie raniona"
|
|||
msgid "Waste"
|
||||
msgstr "Odpady"
|
||||
|
||||
msgid "Website"
|
||||
msgstr "Strona internetowa"
|
||||
|
||||
msgid "Wheeled builder"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1822,7 +1831,7 @@ msgid "Withdraw shield (\\key action;)"
|
|||
msgstr "Wyłącz osłonę (\\key action;)"
|
||||
|
||||
msgid "Workshop\\Open the workshop to search for mods"
|
||||
msgstr ""
|
||||
msgstr "Warsztat\\Otwórz warsztat, aby poszukać modów"
|
||||
|
||||
msgid "Worm"
|
||||
msgstr "Robal"
|
||||
|
@ -1974,6 +1983,9 @@ msgstr "\\Fioletowe flagi"
|
|||
msgid "\\Yellow flags"
|
||||
msgstr "\\Żółte flagi"
|
||||
|
||||
msgid "by"
|
||||
msgstr "autorstwa"
|
||||
|
||||
msgid "colobot.info"
|
||||
msgstr "colobot.info"
|
||||
|
||||
|
|
17
po/pt.po
17
po/pt.po
|
@ -1001,6 +1001,10 @@ msgstr "Próximo objeto\\Selecionar o próximo objeto"
|
|||
msgid "No"
|
||||
msgstr "Não"
|
||||
|
||||
#, fuzzy
|
||||
msgid "No description."
|
||||
msgstr "Resolução:"
|
||||
|
||||
msgid "No energy in the subsoil"
|
||||
msgstr "Nenhuma energia no subsolo"
|
||||
|
||||
|
@ -1749,6 +1753,10 @@ msgstr "Unidade"
|
|||
msgid "Unknown Object"
|
||||
msgstr "Objeto desconhecido"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Unknown author"
|
||||
msgstr "Função desconhecida"
|
||||
|
||||
msgid "Unknown command"
|
||||
msgstr "Comando desconhecido"
|
||||
|
||||
|
@ -1785,6 +1793,9 @@ msgstr "Variável não inicializada"
|
|||
msgid "Vault"
|
||||
msgstr "Cofre"
|
||||
|
||||
msgid "Version"
|
||||
msgstr ""
|
||||
|
||||
msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1803,6 +1814,9 @@ msgstr "Vespa fatalmente ferida"
|
|||
msgid "Waste"
|
||||
msgstr "Desperdício"
|
||||
|
||||
msgid "Website"
|
||||
msgstr ""
|
||||
|
||||
msgid "Wheeled builder"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1987,6 +2001,9 @@ msgstr "\\Bandeiras violetas"
|
|||
msgid "\\Yellow flags"
|
||||
msgstr "\\Bandeiras amarelas"
|
||||
|
||||
msgid "by"
|
||||
msgstr ""
|
||||
|
||||
msgid "colobot.info"
|
||||
msgstr "colobot.info"
|
||||
|
||||
|
|
17
po/ru.po
17
po/ru.po
|
@ -1012,6 +1012,10 @@ msgstr "Следующий объект\\Выбор следующего объ
|
|||
msgid "No"
|
||||
msgstr "Нет"
|
||||
|
||||
#, fuzzy
|
||||
msgid "No description."
|
||||
msgstr "Разрешение:"
|
||||
|
||||
msgid "No energy in the subsoil"
|
||||
msgstr "Под землей нет запасов энергии"
|
||||
|
||||
|
@ -1765,6 +1769,10 @@ msgstr "Юнит"
|
|||
msgid "Unknown Object"
|
||||
msgstr "Неизвестный объект"
|
||||
|
||||
#, fuzzy
|
||||
msgid "Unknown author"
|
||||
msgstr "Неизвестная функция"
|
||||
|
||||
msgid "Unknown command"
|
||||
msgstr "Неизвестная команда"
|
||||
|
||||
|
@ -1801,6 +1809,9 @@ msgstr "Переменная не инициализирована"
|
|||
msgid "Vault"
|
||||
msgstr "Хранилище"
|
||||
|
||||
msgid "Version"
|
||||
msgstr ""
|
||||
|
||||
msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1819,6 +1830,9 @@ msgstr "Оса смертельно ранена"
|
|||
msgid "Waste"
|
||||
msgstr "Мусор"
|
||||
|
||||
msgid "Website"
|
||||
msgstr ""
|
||||
|
||||
msgid "Wheeled builder"
|
||||
msgstr ""
|
||||
|
||||
|
@ -2003,6 +2017,9 @@ msgstr "\\Фиолетовый флаг"
|
|||
msgid "\\Yellow flags"
|
||||
msgstr "\\Желтый флаг"
|
||||
|
||||
msgid "by"
|
||||
msgstr ""
|
||||
|
||||
msgid "colobot.info"
|
||||
msgstr "colobot.info"
|
||||
|
||||
|
|
|
@ -145,6 +145,8 @@ set(BASE_SOURCES
|
|||
app/controller.h
|
||||
app/input.cpp
|
||||
app/input.h
|
||||
app/moddata.cpp
|
||||
app/moddata.h
|
||||
app/modman.cpp
|
||||
app/modman.h
|
||||
app/pathman.cpp
|
||||
|
|
|
@ -520,9 +520,7 @@ bool CApplication::Create()
|
|||
GetLogger()->Warn("Config could not be loaded. Default values will be used!\n");
|
||||
}
|
||||
|
||||
m_modManager->FindMods();
|
||||
m_modManager->SaveMods();
|
||||
m_modManager->UpdatePaths();
|
||||
m_modManager->Init();
|
||||
|
||||
// Create the sound instance.
|
||||
#ifdef OPENAL_SOUND
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* This file is part of the Colobot: Gold Edition source code
|
||||
* Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam
|
||||
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
|
||||
*
|
||||
* This program 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program. If not, see http://gnu.org/licenses
|
||||
*/
|
||||
|
||||
#include "app/moddata.h"
|
||||
|
||||
#include "common/logger.h"
|
||||
#include "common/make_unique.h"
|
||||
|
||||
#include "common/resources/resourcemanager.h"
|
||||
#include "common/resources/inputstream.h"
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
#include <istream>
|
||||
|
||||
namespace pt = boost::property_tree;
|
||||
|
||||
boost::optional<pt::ptree> LoadManifest(const std::string& path, bool loaded = false);
|
||||
std::string GetStringProperty(const pt::ptree& manifest, const std::string& key);
|
||||
std::unordered_map<Language, std::string> GetLanguageStringProperty(const pt::ptree& manifest, const std::string& key);
|
||||
|
||||
ModData LoadModData(const std::string& path, bool loaded)
|
||||
{
|
||||
ModData modData{};
|
||||
|
||||
auto manifestOptional = LoadManifest(path);
|
||||
if (!manifestOptional.has_value())
|
||||
{
|
||||
return modData;
|
||||
}
|
||||
auto manifest = manifestOptional.get();
|
||||
|
||||
modData.displayName = GetLanguageStringProperty(manifest, "DisplayName");
|
||||
modData.version = GetStringProperty(manifest, "Version");
|
||||
modData.author = GetStringProperty(manifest, "Author");
|
||||
modData.website = GetStringProperty(manifest, "Website");
|
||||
modData.summary = GetLanguageStringProperty(manifest, "Summary");
|
||||
|
||||
return modData;
|
||||
}
|
||||
|
||||
boost::optional<pt::ptree> LoadManifest(const std::string& path, bool loaded)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto inputStream = MakeUnique<CInputStream>("manifest.json");
|
||||
if (!inputStream->is_open())
|
||||
{
|
||||
GetLogger()->Error("Error on parsing the manifest file %s: failed to open file\n");
|
||||
return {};
|
||||
}
|
||||
|
||||
pt::ptree manifest{};
|
||||
boost::property_tree::json_parser::read_json(*inputStream, manifest);
|
||||
|
||||
return manifest;
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
GetLogger()->Warn("Error on parsing the manifest file %s: %s\n", path.c_str(), e.what());
|
||||
return {};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string GetStringProperty(const pt::ptree& manifest, const std::string& key)
|
||||
{
|
||||
auto prop = manifest.get_optional<std::string>(key);
|
||||
if (prop.has_value())
|
||||
{
|
||||
return prop.get();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::unordered_map<Language, std::string> GetLanguageStringProperty(const pt::ptree& manifest, const std::string& key)
|
||||
{
|
||||
std::unordered_map<Language, std::string> ret;
|
||||
auto prop = manifest.get_child_optional(key);
|
||||
if (prop.has_value())
|
||||
{
|
||||
for (const auto& child : prop.get())
|
||||
{
|
||||
Language language = LANGUAGE_ENGLISH;
|
||||
std::string strLanguage = child.first.data();
|
||||
if (!ParseLanguage(strLanguage, language))
|
||||
{
|
||||
GetLogger()->Warn("Error on parsing the manifest file: %s language %s is not a valid language\n", key.c_str(), strLanguage.c_str());
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.insert(std::make_pair(language, child.second.data()));
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* This file is part of the Colobot: Gold Edition source code
|
||||
* Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam
|
||||
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
|
||||
*
|
||||
* This program 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program. If not, see http://gnu.org/licenses
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/language.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
struct ModData
|
||||
{
|
||||
std::unordered_map<Language, std::string> displayName{};
|
||||
std::string author{};
|
||||
std::string version{};
|
||||
std::string website{};
|
||||
std::unordered_map<Language, std::string> summary{};
|
||||
};
|
||||
|
||||
//! Loads the metadata for a mod in the given path.
|
||||
ModData LoadModData(const std::string& path, bool loaded = false);
|
|
@ -42,10 +42,8 @@ CModManager::CModManager(CApplication* app, CPathManager* pathManager)
|
|||
{
|
||||
}
|
||||
|
||||
void CModManager::FindMods()
|
||||
void CModManager::Init()
|
||||
{
|
||||
m_mods.clear();
|
||||
|
||||
// Load names from the config file
|
||||
std::vector<std::string> savedModNames;
|
||||
GetConfigFile().GetArrayProperty("Mods", "Names", savedModNames);
|
||||
|
@ -102,6 +100,29 @@ void CModManager::FindMods()
|
|||
mod.path = newMod.second;
|
||||
m_mods.push_back(mod);
|
||||
}
|
||||
|
||||
SaveMods();
|
||||
|
||||
// Load the metadata for each mod
|
||||
for (auto& mod : m_mods)
|
||||
{
|
||||
m_pathManager->AddMod(mod.path);
|
||||
mod.data = LoadModData(mod.path);
|
||||
m_pathManager->RemoveMod(mod.path);
|
||||
}
|
||||
|
||||
UpdatePaths();
|
||||
}
|
||||
|
||||
void CModManager::ReloadMods()
|
||||
{
|
||||
m_mods.clear();
|
||||
m_pathManager->RemoveAllMods();
|
||||
|
||||
Init();
|
||||
|
||||
// Apply the configuration
|
||||
ReloadResources();
|
||||
}
|
||||
|
||||
void CModManager::EnableMod(size_t i)
|
||||
|
|
|
@ -19,13 +19,12 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "ui/maindialog.h"
|
||||
|
||||
#include "ui/screen/screen_setup.h"
|
||||
#include "app/moddata.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
class CApplication;
|
||||
class CPathManager;
|
||||
|
||||
struct Mod
|
||||
|
@ -33,7 +32,7 @@ struct Mod
|
|||
std::string name{};
|
||||
std::string path{};
|
||||
bool enabled = false;
|
||||
//TODO: add metadata for UI
|
||||
ModData data{};
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -43,20 +42,22 @@ struct Mod
|
|||
* The order matters since the order in which files are loaded matters,
|
||||
* because some files can be overwritten.
|
||||
*
|
||||
* The list can be kept in the config file with the \ref SaveMods function.
|
||||
*
|
||||
* The changes in the list do not immediately apply.
|
||||
* Separate calls to \ref UpdatePaths and \ref ReloadResources, probably in this order,
|
||||
* need to be done for the changes to apply.
|
||||
* The changes in the list do not immediately apply
|
||||
* and will be lost after the \ref ReloadMods call if they were not
|
||||
* saved beforehand with \ref SaveMods.
|
||||
*
|
||||
* The changes are also lost to mods which are no longer found in the search paths.
|
||||
*/
|
||||
class CModManager
|
||||
{
|
||||
public:
|
||||
CModManager(CApplication* app, CPathManager* pathManager);
|
||||
|
||||
//! Loads mods without resource reloading; should be called only once after creation
|
||||
void Init();
|
||||
|
||||
//! Finds all the mods along with their metadata
|
||||
void FindMods();
|
||||
void ReloadMods();
|
||||
|
||||
//! Removes a mod from the list of loaded mods
|
||||
void EnableMod(size_t i);
|
||||
|
@ -70,15 +71,9 @@ public:
|
|||
//! Moves the selected mod down in the list so that it's loaded later than others, returns the new index
|
||||
size_t MoveDown(size_t i);
|
||||
|
||||
//! Reloads application resources so the enabled mods are applied
|
||||
void ReloadResources();
|
||||
|
||||
//! Saves the current configuration of mods to the config file
|
||||
void SaveMods();
|
||||
|
||||
//! Updates the paths in Path Manager according to the current mod configuration
|
||||
void UpdatePaths();
|
||||
|
||||
//! Number of mods loaded
|
||||
size_t CountMods() const;
|
||||
|
||||
|
@ -88,10 +83,16 @@ public:
|
|||
//! Returns the list of mods
|
||||
const std::vector<Mod>& GetMods() const;
|
||||
|
||||
private:
|
||||
//! Updates the paths in Path Manager according to the current mod configuration
|
||||
void UpdatePaths();
|
||||
|
||||
//! Reloads application resources so the enabled mods are applied
|
||||
void ReloadResources();
|
||||
|
||||
private:
|
||||
CApplication* m_app;
|
||||
CPathManager* m_pathManager;
|
||||
|
||||
//TODO: better data structure?
|
||||
std::vector<Mod> m_mods;
|
||||
};
|
||||
|
|
|
@ -71,14 +71,14 @@ void CPathManager::AddModSearchDir(const std::string &modSearchDirPath)
|
|||
|
||||
void CPathManager::AddMod(const std::string &modPath)
|
||||
{
|
||||
GetLogger()->Info("Loading mod: '%s'\n", modPath.c_str());
|
||||
GetLogger()->Debug("Adding mod: '%s'\n", modPath.c_str());
|
||||
CResourceManager::AddLocation(modPath, true);
|
||||
m_mods.push_back(modPath);
|
||||
}
|
||||
|
||||
void CPathManager::RemoveMod(const std::string &modPath)
|
||||
{
|
||||
GetLogger()->Info("Unloading mod: '%s'\n", modPath.c_str());
|
||||
GetLogger()->Debug("Removing mod: '%s'\n", modPath.c_str());
|
||||
CResourceManager::RemoveLocation(modPath);
|
||||
auto it = std::find(m_mods.cbegin(), m_mods.cend(), modPath);
|
||||
if (it != m_mods.cend())
|
||||
|
|
|
@ -93,12 +93,6 @@ void InitializeRestext()
|
|||
stringsText[RT_SETUP_KEY1] = TR("1) First click on the key you want to redefine.");
|
||||
stringsText[RT_SETUP_KEY2] = TR("2) Then press the key you want to use instead.");
|
||||
|
||||
stringsText[RT_MOD_LIST] = TR("Mods:");
|
||||
stringsText[RT_MOD_DETAILS] = TR("Information:");
|
||||
stringsText[RT_MOD_SUMMARY] = TR("Description:");
|
||||
stringsText[RT_MOD_ENABLE] = TR("Enable\\Enable the selected mod");
|
||||
stringsText[RT_MOD_DISABLE] = TR("Disable\\Disable the selected mod");
|
||||
|
||||
stringsText[RT_PERSO_FACE] = TR("Face type:");
|
||||
stringsText[RT_PERSO_GLASSES] = TR("Eyeglasses:");
|
||||
stringsText[RT_PERSO_HAIR] = TR("Hair color:");
|
||||
|
@ -165,7 +159,16 @@ void InitializeRestext()
|
|||
stringsText[RT_SCOREBOARD_RESULTS_TIME]= TR("Time: %s");
|
||||
stringsText[RT_SCOREBOARD_RESULTS_LINE]= TR("%s: %d pts");
|
||||
|
||||
|
||||
stringsText[RT_MOD_LIST] = TR("Mods:");
|
||||
stringsText[RT_MOD_DETAILS] = TR("Information:");
|
||||
stringsText[RT_MOD_SUMMARY] = TR("Description:");
|
||||
stringsText[RT_MOD_ENABLE] = TR("Enable\\Enable the selected mod");
|
||||
stringsText[RT_MOD_DISABLE] = TR("Disable\\Disable the selected mod");
|
||||
stringsText[RT_MOD_UNKNOWN_AUTHOR] = TR("Unknown author");
|
||||
stringsText[RT_MOD_AUTHOR_FIELD_NAME] = TR("by");
|
||||
stringsText[RT_MOD_VERSION_FIELD_NAME] = TR("Version");
|
||||
stringsText[RT_MOD_WEBSITE_FIELD_NAME] = TR("Website");
|
||||
stringsText[RT_MOD_NO_SUMMARY] = TR("No description.");
|
||||
|
||||
stringsEvent[EVENT_LABEL_CODE_BATTLE] = TR("Code battle");
|
||||
|
||||
|
|
|
@ -153,11 +153,16 @@ enum ResTextType
|
|||
RT_SCOREBOARD_RESULTS_TIME= 232,
|
||||
RT_SCOREBOARD_RESULTS_LINE= 233,
|
||||
|
||||
RT_MOD_LIST = 234,
|
||||
RT_MOD_DETAILS = 235,
|
||||
RT_MOD_SUMMARY = 236,
|
||||
RT_MOD_ENABLE = 237,
|
||||
RT_MOD_DISABLE = 238,
|
||||
RT_MOD_LIST = 234,
|
||||
RT_MOD_DETAILS = 235,
|
||||
RT_MOD_SUMMARY = 236,
|
||||
RT_MOD_ENABLE = 237,
|
||||
RT_MOD_DISABLE = 238,
|
||||
RT_MOD_UNKNOWN_AUTHOR = 239,
|
||||
RT_MOD_AUTHOR_FIELD_NAME = 240,
|
||||
RT_MOD_VERSION_FIELD_NAME = 241,
|
||||
RT_MOD_WEBSITE_FIELD_NAME = 242,
|
||||
RT_MOD_NO_SUMMARY = 243,
|
||||
|
||||
RT_MAX //! < number of values
|
||||
};
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
|
||||
#include "common/system/system.h"
|
||||
|
||||
#include "level/robotmain.h"
|
||||
|
||||
#include "math/func.h"
|
||||
|
||||
#include "ui/controls/button.h"
|
||||
|
@ -94,7 +96,7 @@ void CScreenModList::CreateInterface()
|
|||
pl->SetTextAlign(Gfx::TEXT_ALIGN_LEFT);
|
||||
|
||||
pos.y = oy+sy*6.7f;
|
||||
ddim.y = dim.y*4.5f;
|
||||
ddim.y = dim.y*4.6f;
|
||||
ddim.x = dim.x*6.5f;
|
||||
pli = pw->CreateList(pos, ddim, 0, EVENT_INTERFACE_MOD_LIST);
|
||||
pli->SetState(STATE_SHADOW);
|
||||
|
@ -112,10 +114,13 @@ void CScreenModList::CreateInterface()
|
|||
pl->SetTextAlign(Gfx::TEXT_ALIGN_LEFT);
|
||||
|
||||
pos.y = oy+sy*6.7f;
|
||||
ddim.y = dim.y*4.5f;
|
||||
ddim.y = dim.y*4.3f;
|
||||
ddim.x = dim.x*6.5f;
|
||||
pli = pw->CreateList(pos, ddim, 0, EVENT_INTERFACE_LIST);
|
||||
pli->SetState(STATE_SHADOW);
|
||||
pe = pw->CreateEdit(pos, ddim, 0, EVENT_INTERFACE_MOD_DETAILS);
|
||||
pe->SetState(STATE_SHADOW);
|
||||
pe->SetMaxChar(500);
|
||||
pe->SetEditCap(false); // just to see
|
||||
pe->SetHighlightCap(true);
|
||||
|
||||
UpdateModDetails();
|
||||
|
||||
|
@ -139,7 +144,7 @@ void CScreenModList::CreateInterface()
|
|||
pe->SetState(STATE_SHADOW);
|
||||
pe->SetMaxChar(500);
|
||||
pe->SetEditCap(false); // just to see
|
||||
pe->SetHighlightCap(false);
|
||||
pe->SetHighlightCap(true);
|
||||
|
||||
UpdateModSummary();
|
||||
|
||||
|
@ -337,14 +342,10 @@ void CScreenModList::ApplyChanges()
|
|||
m_modManager->SaveMods();
|
||||
}
|
||||
|
||||
m_modManager->FindMods();
|
||||
m_modManager->SaveMods();
|
||||
m_modManager->ReloadMods();
|
||||
|
||||
m_empty = (m_modManager->CountMods() == 0);
|
||||
|
||||
m_modManager->UpdatePaths();
|
||||
m_modManager->ReloadResources();
|
||||
|
||||
m_modSelectedIndex = Math::Clamp(m_modSelectedIndex, static_cast<size_t>(0), m_modManager->CountMods() - 1);
|
||||
}
|
||||
|
||||
|
@ -372,7 +373,8 @@ void CScreenModList::UpdateModList()
|
|||
for (size_t i = 0; i < mods.size(); ++i)
|
||||
{
|
||||
const auto& mod = mods[i];
|
||||
pl->SetItemName(i, mod.name);
|
||||
auto name = GetLanguageStringProperty(mod.data.displayName, mod.name);
|
||||
pl->SetItemName(i, name);
|
||||
pl->SetCheck(i, mod.enabled);
|
||||
pl->SetEnable(i, true);
|
||||
}
|
||||
|
@ -383,12 +385,80 @@ void CScreenModList::UpdateModList()
|
|||
|
||||
void CScreenModList::UpdateModDetails()
|
||||
{
|
||||
//TODO
|
||||
CWindow* pw = static_cast<CWindow*>(m_interface->SearchControl(EVENT_WINDOW5));
|
||||
if (pw == nullptr) return;
|
||||
|
||||
CEdit* pe = static_cast<CEdit*>(pw->SearchControl(EVENT_INTERFACE_MOD_DETAILS));
|
||||
if (pe == nullptr) return;
|
||||
|
||||
if (m_empty)
|
||||
{
|
||||
pe->SetText("No information");
|
||||
return;
|
||||
}
|
||||
|
||||
std::string details{};
|
||||
|
||||
const auto& mod = m_modManager->GetMod(m_modSelectedIndex);
|
||||
const auto data = mod.data;
|
||||
|
||||
auto name = GetLanguageStringProperty(data.displayName, mod.name);
|
||||
details += "\\b;" + name + '\n';
|
||||
|
||||
std::string authorFieldName;
|
||||
GetResource(RES_TEXT, RT_MOD_AUTHOR_FIELD_NAME, authorFieldName);
|
||||
details += "\\s;" + authorFieldName + " ";
|
||||
if (!data.author.empty())
|
||||
{
|
||||
details += data.author;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string unknownAuthor;
|
||||
GetResource(RES_TEXT, RT_MOD_UNKNOWN_AUTHOR, unknownAuthor);
|
||||
details += unknownAuthor;
|
||||
}
|
||||
details += '\n';
|
||||
|
||||
details += '\n';
|
||||
|
||||
if (!data.version.empty())
|
||||
{
|
||||
std::string versionFieldName;
|
||||
GetResource(RES_TEXT, RT_MOD_VERSION_FIELD_NAME, versionFieldName);
|
||||
details += "\\t;" + versionFieldName + '\n' + data.version + '\n';
|
||||
}
|
||||
|
||||
if (!data.website.empty())
|
||||
{
|
||||
std::string websiteFieldName;
|
||||
GetResource(RES_TEXT, RT_MOD_WEBSITE_FIELD_NAME, websiteFieldName);
|
||||
details += "\\t;" + websiteFieldName + '\n' + data.website + '\n';
|
||||
}
|
||||
|
||||
pe->SetText(details);
|
||||
}
|
||||
|
||||
void CScreenModList::UpdateModSummary()
|
||||
{
|
||||
//TODO
|
||||
CWindow* pw = static_cast<CWindow*>(m_interface->SearchControl(EVENT_WINDOW5));
|
||||
if (pw == nullptr) return;
|
||||
|
||||
CEdit* pe = static_cast<CEdit*>(pw->SearchControl(EVENT_INTERFACE_MOD_SUMMARY));
|
||||
if (pe == nullptr) return;
|
||||
|
||||
std::string noSummary;
|
||||
GetResource(RES_TEXT, RT_MOD_NO_SUMMARY, noSummary);
|
||||
|
||||
if (m_empty)
|
||||
{
|
||||
pe->SetText(noSummary);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& mod = m_modManager->GetMod(m_modSelectedIndex);
|
||||
|
||||
pe->SetText(GetLanguageStringProperty(mod.data.summary, noSummary));
|
||||
}
|
||||
|
||||
void CScreenModList::UpdateEnableDisableButton()
|
||||
|
@ -487,4 +557,23 @@ void CScreenModList::UpdateUpDownButtons()
|
|||
}
|
||||
}
|
||||
|
||||
std::string CScreenModList::GetLanguageStringProperty(std::unordered_map<Language, std::string> property, const std::string& fallback)
|
||||
{
|
||||
std::string ret{};
|
||||
const auto language = m_app->GetLanguage();
|
||||
if (property.count(language) > 0)
|
||||
{
|
||||
ret = property.at(language);
|
||||
}
|
||||
else if (property.count(LANGUAGE_ENGLISH) > 0)
|
||||
{
|
||||
ret = property.at(LANGUAGE_ENGLISH);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = fallback;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace Ui
|
||||
|
|
|
@ -21,11 +21,12 @@
|
|||
|
||||
#include "app/modman.h"
|
||||
|
||||
#include "ui/maindialog.h"
|
||||
|
||||
#include "ui/screen/screen.h"
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class CMainDialog;
|
||||
|
||||
/**
|
||||
* \class CScreenModList
|
||||
|
@ -78,6 +79,8 @@ protected:
|
|||
void UpdateApplyButton();
|
||||
void UpdateUpDownButtons();
|
||||
|
||||
std::string GetLanguageStringProperty(std::unordered_map<Language, std::string> property, const std::string& fallback);
|
||||
|
||||
protected:
|
||||
Ui::CMainDialog* m_dialog;
|
||||
|
||||
|
|
Loading…
Reference in New Issue