From d8822eaaaa567e6ba48261388b77233843744431 Mon Sep 17 00:00:00 2001 From: nordsoft Date: Mon, 29 Aug 2022 01:28:36 +0400 Subject: [PATCH] Initial commit for new map editor --- CMakeLists.txt | 8 +- mapeditor/CGameInfo.cpp | 107 +++++++++++++++++++++++++ mapeditor/CGameInfo.h | 93 ++++++++++++++++++++++ mapeditor/CMakeLists.txt | 87 +++++++++++++++++++++ mapeditor/StdInc.cpp | 1 + mapeditor/StdInc.h | 29 +++++++ mapeditor/VCMI_launcher.cbp | 110 ++++++++++++++++++++++++++ mapeditor/VCMI_launcher.ico | Bin 0 -> 32038 bytes mapeditor/VCMI_launcher.rc | 1 + mapeditor/icons/menu-game.png | Bin 0 -> 5482 bytes mapeditor/icons/menu-mods.png | Bin 0 -> 2986 bytes mapeditor/icons/menu-settings.png | Bin 0 -> 4474 bytes mapeditor/icons/mod-delete.png | Bin 0 -> 1449 bytes mapeditor/icons/mod-disabled.png | Bin 0 -> 1604 bytes mapeditor/icons/mod-download.png | Bin 0 -> 895 bytes mapeditor/icons/mod-enabled.png | Bin 0 -> 1104 bytes mapeditor/icons/mod-update.png | Bin 0 -> 1341 bytes mapeditor/jsonutils.cpp | 125 ++++++++++++++++++++++++++++++ mapeditor/jsonutils.h | 22 ++++++ mapeditor/launcherdirs.cpp | 36 +++++++++ mapeditor/launcherdirs.h | 22 ++++++ mapeditor/main.cpp | 20 +++++ mapeditor/mainwindow.cpp | 95 +++++++++++++++++++++++ mapeditor/mainwindow.h | 28 +++++++ mapeditor/mainwindow.ui | 61 +++++++++++++++ 25 files changed, 843 insertions(+), 2 deletions(-) create mode 100644 mapeditor/CGameInfo.cpp create mode 100644 mapeditor/CGameInfo.h create mode 100644 mapeditor/CMakeLists.txt create mode 100644 mapeditor/StdInc.cpp create mode 100644 mapeditor/StdInc.h create mode 100644 mapeditor/VCMI_launcher.cbp create mode 100644 mapeditor/VCMI_launcher.ico create mode 100644 mapeditor/VCMI_launcher.rc create mode 100644 mapeditor/icons/menu-game.png create mode 100644 mapeditor/icons/menu-mods.png create mode 100644 mapeditor/icons/menu-settings.png create mode 100644 mapeditor/icons/mod-delete.png create mode 100644 mapeditor/icons/mod-disabled.png create mode 100644 mapeditor/icons/mod-download.png create mode 100644 mapeditor/icons/mod-enabled.png create mode 100644 mapeditor/icons/mod-update.png create mode 100644 mapeditor/jsonutils.cpp create mode 100644 mapeditor/jsonutils.h create mode 100644 mapeditor/launcherdirs.cpp create mode 100644 mapeditor/launcherdirs.h create mode 100644 mapeditor/main.cpp create mode 100644 mapeditor/mainwindow.cpp create mode 100644 mapeditor/mainwindow.h create mode 100644 mapeditor/mainwindow.ui diff --git a/CMakeLists.txt b/CMakeLists.txt index 3263f6233..a961da04c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,6 +47,7 @@ set(VCMI_VERSION_PATCH 0) option(ENABLE_ERM "Enable compilation of ERM scripting module" ON) option(ENABLE_LUA "Enable compilation of LUA scripting module" ON) option(ENABLE_LAUNCHER "Enable compilation of launcher" ON) +option(ENABLE_EDITOR "Enable compilation of map editor" ON) option(ENABLE_TEST "Enable compilation of unit tests" ON) if(NOT ${CMAKE_VERSION} VERSION_LESS "3.16.0") option(ENABLE_PCH "Enable compilation using precompiled headers" ON) @@ -247,7 +248,7 @@ if(TARGET SDL2_ttf::SDL2_ttf) endif() find_package(TBB REQUIRED) -if(ENABLE_LAUNCHER) +if(ENABLE_LAUNCHER OR ENABLE_EDITOR) # Widgets finds its own dependencies (QtGui and QtCore). find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets Network) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Network) @@ -355,6 +356,9 @@ add_subdirectory_with_folder("AI" AI) if(ENABLE_LAUNCHER) add_subdirectory(launcher) endif() +if(ENABLE_EDITOR) + add_subdirectory(mapeditor) +endif() if(ENABLE_TEST) enable_testing() add_subdirectory(test) @@ -389,7 +393,7 @@ if(WIN32) set(debug_postfix d) endif() - if(ENABLE_LAUNCHER) + if(ENABLE_LAUNCHER OR ENABLE_EDITOR) get_target_property(QtCore_location Qt${QT_VERSION_MAJOR}::Core LOCATION) get_filename_component(Qtbin_folder ${QtCore_location} PATH) file(GLOB dep_files diff --git a/mapeditor/CGameInfo.cpp b/mapeditor/CGameInfo.cpp new file mode 100644 index 000000000..d8c58296a --- /dev/null +++ b/mapeditor/CGameInfo.cpp @@ -0,0 +1,107 @@ +/* + * CGameInfo.cpp, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ +#include "StdInc.h" +#include "CGameInfo.h" + +#include "../lib/VCMI_Lib.h" + +const CGameInfo * CGI; +CClientState * CCS = nullptr; +CServerHandler * CSH; + + +CGameInfo::CGameInfo() +{ + generaltexth = nullptr; + mh = nullptr; + townh = nullptr; + globalServices = nullptr; +} + +void CGameInfo::setFromLib() +{ + globalServices = VLC; + modh = VLC->modh; + generaltexth = VLC->generaltexth; + creh = VLC->creh; + townh = VLC->townh; + heroh = VLC->heroh; + objh = VLC->objh; + spellh = VLC->spellh; + skillh = VLC->skillh; + objtypeh = VLC->objtypeh; + battleFieldHandler = VLC->battlefieldsHandler; + obstacleHandler = VLC->obstacleHandler; +} + +const ArtifactService * CGameInfo::artifacts() const +{ + return globalServices->artifacts(); +} + +const BattleFieldService * CGameInfo::battlefields() const +{ + return globalServices->battlefields(); +} + +const CreatureService * CGameInfo::creatures() const +{ + return globalServices->creatures(); +} + +const FactionService * CGameInfo::factions() const +{ + return globalServices->factions(); +} + +const HeroClassService * CGameInfo::heroClasses() const +{ + return globalServices->heroClasses(); +} + +const HeroTypeService * CGameInfo::heroTypes() const +{ + return globalServices->heroTypes(); +} + +const scripting::Service * CGameInfo::scripts() const +{ + return globalServices->scripts(); +} + +const spells::Service * CGameInfo::spells() const +{ + return globalServices->spells(); +} + +const SkillService * CGameInfo::skills() const +{ + return globalServices->skills(); +} + +const ObstacleService * CGameInfo::obstacles() const +{ + return globalServices->obstacles(); +} + +void CGameInfo::updateEntity(Metatype metatype, int32_t index, const JsonNode & data) +{ + logGlobal->error("CGameInfo::updateEntity call is not expected."); +} + +spells::effects::Registry * CGameInfo::spellEffects() +{ + return nullptr; +} + +const spells::effects::Registry * CGameInfo::spellEffects() const +{ + return globalServices->spellEffects(); +} diff --git a/mapeditor/CGameInfo.h b/mapeditor/CGameInfo.h new file mode 100644 index 000000000..70b56905c --- /dev/null +++ b/mapeditor/CGameInfo.h @@ -0,0 +1,93 @@ +/* + * CGameInfo.h, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ +#pragma once + +#include + +#include "../lib/ConstTransitivePtr.h" + +class CModHandler; +class CMapHandler; +class CHeroHandler; +class CCreatureHandler; +class CSpellHandler; +class CSkillHandler; +class CBuildingHandler; +class CObjectHandler; +class CSoundHandler; +class CMusicHandler; +class CObjectClassesHandler; +class CTownHandler; +class CGeneralTextHandler; +class CConsoleHandler; +class CCursorHandler; +class CGameState; +class IMainVideoPlayer; +class CServerHandler; +class BattleFieldHandler; +class ObstacleHandler; + +class CMap; + + +//a class for non-mechanical client GUI classes +class CClientState +{ +public: + CSoundHandler * soundh; + CMusicHandler * musich; + CConsoleHandler * consoleh; + CCursorHandler * curh; + IMainVideoPlayer * videoh; +}; +extern CClientState * CCS; + +/// CGameInfo class +/// for allowing different functions for accessing game informations +class CGameInfo : public Services +{ +public: + const ArtifactService * artifacts() const override; + const CreatureService * creatures() const override; + const FactionService * factions() const override; + const HeroClassService * heroClasses() const override; + const HeroTypeService * heroTypes() const override; + const scripting::Service * scripts() const override; + const spells::Service * spells() const override; + const SkillService * skills() const override; + const BattleFieldService * battlefields() const override; + const ObstacleService * obstacles() const override; + + void updateEntity(Metatype metatype, int32_t index, const JsonNode & data) override; + + const spells::effects::Registry * spellEffects() const override; + spells::effects::Registry * spellEffects() override; + + + ConstTransitivePtr modh; //public? + ConstTransitivePtr battleFieldHandler; + ConstTransitivePtr heroh; + ConstTransitivePtr creh; + ConstTransitivePtr spellh; + ConstTransitivePtr skillh; + ConstTransitivePtr objh; + ConstTransitivePtr objtypeh; + ConstTransitivePtr obstacleHandler; + CGeneralTextHandler * generaltexth; + CMapHandler * mh; + CTownHandler * townh; + + void setFromLib(); + + CGameInfo(); +private: + const Services * globalServices; +}; +extern const CGameInfo* CGI; diff --git a/mapeditor/CMakeLists.txt b/mapeditor/CMakeLists.txt new file mode 100644 index 000000000..6c2564bda --- /dev/null +++ b/mapeditor/CMakeLists.txt @@ -0,0 +1,87 @@ +set(editor_SRCS + StdInc.cpp + main.cpp + launcherdirs.cpp + jsonutils.cpp + mainwindow.cpp + CGameInfo.cpp +) + +set(editor_HEADERS + StdInc.h + launcherdirs.h + jsonutils.h + mainwindow.h + CGameInfo.h +) + +set(editor_FORMS + mainwindow.ui +) + +assign_source_group(${editor_SRCS} ${editor_HEADERS} VCMI_launcher.rc) + +# Tell CMake to run moc when necessary: +set(CMAKE_AUTOMOC ON) + +if(POLICY CMP0071) + cmake_policy(SET CMP0071 NEW) +endif() + +# As moc files are generated in the binary dir, tell CMake +# to always look for includes there: +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +if(TARGET Qt6::Core) + qt_wrap_ui(editor_UI_HEADERS ${editor_FORMS}) +else() + qt5_wrap_ui(editor_UI_HEADERS ${editor_FORMS}) +endif() + +if(WIN32) + set(editor_ICON VCMI_launcher.rc) +endif() + +add_executable(vcmieditor WIN32 ${editor_SRCS} ${editor_HEADERS} ${editor_UI_HEADERS} ${editor_ICON}) + +if(WIN32) + set_target_properties(vcmieditor + PROPERTIES + OUTPUT_NAME "VCMI_mapeditor" + PROJECT_LABEL "VCMI_mapeditor" + ) + + # FIXME: Can't to get CMP0020 working with Vcpkg and CMake 3.8.2 + # So far I tried: + # - cmake_minimum_required set to 2.8.11 globally and in this file + # - cmake_policy in all possible places + # - used NO_POLICY_SCOPE to make sure no other parts reset policies + # Still nothing worked, warning kept appearing and WinMain didn't link automatically + target_link_libraries(vcmieditor Qt${QT_VERSION_MAJOR}::WinMain) +endif() + +if(APPLE) + # This makes Xcode project prettier by moving vcmilauncher_autogen directory into vcmiclient subfolder + set_property(GLOBAL PROPERTY AUTOGEN_TARGETS_FOLDER vcmieditor) +endif() + +target_link_libraries(vcmieditor vcmi Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Network) +target_include_directories(vcmieditor + PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} +) +vcmi_set_output_dir(vcmieditor "") +enable_pch(vcmieditor) + +# Copy to build directory for easier debugging +add_custom_command(TARGET vcmieditor POST_BUILD + COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/mapeditor/icons + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/mapeditor/icons ${CMAKE_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/mapeditor/icons +) + +install(TARGETS vcmieditor DESTINATION ${BIN_DIR}) +# copy whole directory +install(DIRECTORY icons DESTINATION ${DATA_DIR}/mapeditor) +# Install icons and desktop file on Linux +if(NOT WIN32 AND NOT APPLE) + install(FILES "vcmilauncher.desktop" DESTINATION share/applications) +endif() diff --git a/mapeditor/StdInc.cpp b/mapeditor/StdInc.cpp new file mode 100644 index 000000000..b64b59be5 --- /dev/null +++ b/mapeditor/StdInc.cpp @@ -0,0 +1 @@ +#include "StdInc.h" diff --git a/mapeditor/StdInc.h b/mapeditor/StdInc.h new file mode 100644 index 000000000..dcaee354c --- /dev/null +++ b/mapeditor/StdInc.h @@ -0,0 +1,29 @@ +#pragma once + +#include "../Global.h" + +#include +#include +#include +#include +#include +#include +#include + +inline QString pathToQString(const boost::filesystem::path & path) +{ +#ifdef VCMI_WINDOWS + return QString::fromStdWString(path.wstring()); +#else + return QString::fromStdString(path.string()); +#endif +} + +inline boost::filesystem::path qstringToPath(const QString & path) +{ +#ifdef VCMI_WINDOWS + return boost::filesystem::path(path.toStdWString()); +#else + return boost::filesystem::path(path.toUtf8().data()); +#endif +} diff --git a/mapeditor/VCMI_launcher.cbp b/mapeditor/VCMI_launcher.cbp new file mode 100644 index 000000000..b7c1bedf3 --- /dev/null +++ b/mapeditor/VCMI_launcher.cbp @@ -0,0 +1,110 @@ + + + + + + diff --git a/mapeditor/VCMI_launcher.ico b/mapeditor/VCMI_launcher.ico new file mode 100644 index 0000000000000000000000000000000000000000..40818c4644c43924635690ea58dcdce6786e5466 GIT binary patch literal 32038 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 literal 0 HcmV?d00001 diff --git a/mapeditor/icons/menu-settings.png b/mapeditor/icons/menu-settings.png new file mode 100644 index 0000000000000000000000000000000000000000..4cce5d91ea81b0b051dfd7736f7beeda24380e0d GIT binary patch literal 4474 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 M07*qoM6N<$g8#!*Hvj+t literal 0 HcmV?d00001 diff --git a/mapeditor/icons/mod-delete.png b/mapeditor/icons/mod-delete.png new file mode 100644 index 0000000000000000000000000000000000000000..fa0c04d95bd286e97de68da3b40bc1cfd0dbcfb9 GIT binary patch literal 1449 zcmV;a1y=frP)zs}v|HDFrc-hzT#gh&~y7Ly3t7qk>Rx(HIkm z62M4;FC<_hFD4igee!`sF(?wTkwWh@P+IA3cei_X&wXb6XZCbygJOK}B>&DiGv9pQ zf0_BS0RQtt9<(^HbzRz^{&U1IUck=|!g#%$7aA>qfMMbLUm3(W*LLxb{C^U-($kYj z8ume<(|xJ6oiw?jGahMf1}za+>&&vipZXKZ{R4LS#vlX6kEBHLlh#X<_P+{Tf4sAe zaq@kly`!aJ`?feW5K_*8aLNGOuYhO-NGu7EOapg0+tX!FBUO}B31Hfz#op)huItSLA1jj5p_bmB5c(T@3-(57e*ejM+nj5I7#Do58fu;L*O1V9KZg zO9^<&87|hGlO8R zHb|Q}aSZ&~EX2}{u=UtU$Tl@A+j{gQMAK=tHgn>56)(-p%s{-cF~K<9CAoF^<1?~e zk47Pw%3|Rd5Iije3+mpw4U_L4gw{hxAkxqPTMi$s)T^cjy)D3<_xcn@$WtW?FUNcl z-cI6N8tY*Ys=gtNK%RW&xQg>$1RQdXY2*DN zRZpZ?+4Ui_WGOsx@(YM!isS*17Ok&`Z8(>0TBb03VHC*Wlq?7YnXL*4K?cl%iQ-xX z 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 literal 0 HcmV?d00001 diff --git a/mapeditor/icons/mod-enabled.png b/mapeditor/icons/mod-enabled.png new file mode 100644 index 0000000000000000000000000000000000000000..40204a56f4f2a67fae6c199ac8ac30be8dea745f GIT binary patch literal 1104 zcmV-W1h4yvP)0tFiqx|hd}<3erfn=qt&NE_Y22jAp4`vw+1+!_%=off)+BAv_0d24 zABLIve$4m(7~ua}r%1U1FMM=|PJOY{0I3sPygpr3``M8vkMQC?Ef*lw=u2Cw>l&VW zxTCVZx~98kX>z=)r)}4N0@!zG=LSZ|Tf3WEjewCsNBeHQqkT^eW%#CeMkxoN5I51% z(4_cv0o(Z#0AOV;p;Gd5*)MqhaNA~8)t=eW*kt6~2~gsLkYW5Va5nEaqO)v(kJ1m? zo0@zeOW?wW#^N|LJmh$u^JUM0Gb3dIx_Vl6=!&+hv96A#b4duHW7(GI`}LA1^ZD0G z&;E0O1W{Gi`@r^X{=A!l<7UA~6@I)hXiLrycE5Pu{M($?(nusgQ?b@pDJ6Pz#&|c8 zIN@DOPH*cY!BFt_+GrKYWG_QuLCh`NxRji5xHR5hskP<{X5;t19j&NH)W$ZxF?UnG z@7WLA;sCJstG!I2^y8h4n}c?K2CnCUkqAx={gUAlZywrzBE2eUtNm^3&=lpBJ@;%g zG?ijF8Qgwucx&Me}#_(mnD-x)f2VdR(x?lsrn8cb)W;Rz0%`O!CgG0i>sa_RSQLyIUSL%$^_ zb3&>Rl48kDA{21RL(L6F+t!+(u5;MVA_(zgEM-c|&W`pR=>PV5nOFt5x}o;LDRbe| z;{(GP$MJ)}hji8im$TSZ87Ap$3Lcl>o{Dq7CvDF8)Box>-QU}?Poc`emMzu(3O|r@ z7eNSxlpMMm!FVd?j84uS>+bA-;zj_r29N?!&wf8Oc-Q@#PS04@V+x~6BoLyGmxYuR zTI#u+$ncFl~X9VsORK!gxPN{LV?L~PqeDd3tlkw}C{ zDT$Pll+I^%BAuNY%za&bckt#}+pS-oci%br`IVmtA%YOXDW!r^DilTGnx+ZMvIGDQ zK#&#wvqIBYEXFwJR0u(f&;l5Q5Ls+WsbGu=(=<7NqA)McgRGOV(q0*9Q4lHZRrMEM WTe#;$n{L(s00005I1-UB5ex=H zbavvp!=0tNw7!5kT-MzQH|#`Tp^I8t&0DORVK8b1 zu7^DBVd?WY;e$_(BteJgh7_ez?q^WoIrlR9`3&C^$%r9C6-1Fsv#58{R5Sm_&14G9 z7bKw2=kCFAY;Y(MOC@7<8ESe=wePlRK!zT}r=BH21uTGo+;6D~2VRRM2f8EKapZdf z3T$`Si-SDnry4u$Pk=3D+0=?0Dm0z;<9rWkL*~b$fCv@Xy4h<%!ob-8Li{Px8J?=b zB#`kws9l((s=;3POW{NS`sFGW5aHM>CyALCRId-NQ7dz)huK6$Q*jg9QlJeR?B=<&zfvxfspCv`YKVaU(d7}&$OA$w3$jfc1k$R8lI=*?~`nKOgKIkVO{6RhxARh{z8xETr37;Q}oF6;4 zFrKt9Ay|@JUy|f4&z7&s>lF)sDHeMai+#$Km&%p#5AWY@Y$!K2K5TAo;*a?D!6$Vl z%H72SgH==4z~QvCw6qZfPau&|ltQ6U=?s>hp1!_;vB@^G?K^i{^LRl){NM{0V=rHc zPt47$t*x(bXl!lk9~>GP9eXuC^?G_nDwEI6%`ZW``xwhBA7d3_ZB3z2u0wn`;-nIuo0j;$-S-j9Nx{S_(*u zYEF6kh{Pjy?5uvn4DWPF0G&rwUJ6sz*I6X%|JXoYBRAXL?m4p zyJ5Z5E7lx_YGX#?j%)G>1Kct~xsiLr8*#BHrv{error("Failed to open file %s", filename.toUtf8().data()); + return QVariant(); + } + else + { + JsonNode node(data.data(), data.size()); + return toVariant(node); + } +} + +JsonNode toJson(QVariant object) +{ + JsonNode ret; + + if(object.canConvert()) + ret.Struct() = VariantToMap(object.toMap()); + else if(object.canConvert()) + ret.Vector() = VariantToList(object.toList()); + else if(object.userType() == QMetaType::QString) + ret.String() = object.toString().toUtf8().data(); + else if(object.userType() == QMetaType::Bool) + ret.Bool() = object.toBool(); + else if(object.canConvert()) + ret.Float() = object.toFloat(); + + return ret; +} + +void JsonToFile(QString filename, QVariant object) +{ + FileStream file(qstringToPath(filename), std::ios::out | std::ios_base::binary); + file << toJson(object).toJson(); +} + +} diff --git a/mapeditor/jsonutils.h b/mapeditor/jsonutils.h new file mode 100644 index 000000000..09425b48f --- /dev/null +++ b/mapeditor/jsonutils.h @@ -0,0 +1,22 @@ +/* + * jsonutils.h, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ +#pragma once + +#include +#include "../lib/JsonNode.h" + +namespace JsonUtils +{ +QVariant toVariant(const JsonNode & node); +QVariant JsonFromFile(QString filename); + +JsonNode toJson(QVariant object); +void JsonToFile(QString filename, QVariant object); +} diff --git a/mapeditor/launcherdirs.cpp b/mapeditor/launcherdirs.cpp new file mode 100644 index 000000000..97d456bb5 --- /dev/null +++ b/mapeditor/launcherdirs.cpp @@ -0,0 +1,36 @@ +/* + * launcherdirs.cpp, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ +#include "StdInc.h" +#include "launcherdirs.h" + +#include "../lib/VCMIDirs.h" + +static CLauncherDirs launcherDirsGlobal; + +CLauncherDirs::CLauncherDirs() +{ + QDir().mkdir(downloadsPath()); + QDir().mkdir(modsPath()); +} + +CLauncherDirs & CLauncherDirs::get() +{ + return launcherDirsGlobal; +} + +QString CLauncherDirs::downloadsPath() +{ + return pathToQString(VCMIDirs::get().userCachePath() / "downloads"); +} + +QString CLauncherDirs::modsPath() +{ + return pathToQString(VCMIDirs::get().userDataPath() / "Mods"); +} diff --git a/mapeditor/launcherdirs.h b/mapeditor/launcherdirs.h new file mode 100644 index 000000000..9117bd9fb --- /dev/null +++ b/mapeditor/launcherdirs.h @@ -0,0 +1,22 @@ +/* + * launcherdirs.h, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ +#pragma once + +/// similar to lib/VCMIDirs, controls where all launcher-related data will be stored +class CLauncherDirs +{ +public: + CLauncherDirs(); + + static CLauncherDirs & get(); + + QString downloadsPath(); + QString modsPath(); +}; diff --git a/mapeditor/main.cpp b/mapeditor/main.cpp new file mode 100644 index 000000000..98dd57bea --- /dev/null +++ b/mapeditor/main.cpp @@ -0,0 +1,20 @@ +/* + * main.cpp, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ +#include +#include "StdInc.h" +#include "mainwindow.h" + +int main(int argc, char * argv[]) +{ + QApplication vcmieditor(argc, argv); + MainWindow mainWindow; + mainWindow.show(); + return vcmieditor.exec(); +} diff --git a/mapeditor/mainwindow.cpp b/mapeditor/mainwindow.cpp new file mode 100644 index 000000000..57e7d9e15 --- /dev/null +++ b/mapeditor/mainwindow.cpp @@ -0,0 +1,95 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" + +#include +#include + +#include "../lib/VCMIDirs.h" +#include "../lib/VCMI_Lib.h" +#include "../lib/logging/CBasicLogConfigurator.h" +#include "../lib/CConfigHandler.h" +#include "../lib/filesystem/Filesystem.h" +#include "../lib/GameConstants.h" + + +#include "CGameInfo.h" + +static CBasicLogConfigurator * logConfig; + +void init() +{ + loadDLLClasses(); + const_cast(CGI)->setFromLib(); + logGlobal->info("Initializing VCMI_Lib"); +} + +MainWindow::MainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::MainWindow) +{ + ui->setupUi(this); + + //configure logging + const boost::filesystem::path logPath = VCMIDirs::get().userCachePath() / "VCMI_Editor_log.txt"; + console = new CConsoleHandler(); + logConfig = new CBasicLogConfigurator(logPath, console); + logConfig->configureDefault(); + logGlobal->info("The log file will be saved to %s", logPath); + + //init + preinitDLL(::console); + settings.init(); + + // Initialize logging based on settings + logConfig->configure(); + logGlobal->debug("settings = %s", settings.toJsonNode().toJson()); + + // Some basic data validation to produce better error messages in cases of incorrect install + auto testFile = [](std::string filename, std::string message) -> bool + { + if (CResourceHandler::get()->existsResource(ResourceID(filename))) + return true; + + logGlobal->error("Error: %s was not found!", message); + return false; + }; + + if(!testFile("DATA/HELP.TXT", "Heroes III data") || + !testFile("MODS/VCMI/MOD.JSON", "VCMI data")) + { + QApplication::quit(); + } + + conf.init(); + logGlobal->info("Loading settings"); + + CGI = new CGameInfo(); //contains all global informations about game (texts, lodHandlers, map handler etc.) + init(); + + + if(!testFile("DATA/new-menu/Background.png", "Cannot find file")) + { + QApplication::quit(); + } + + //now let's try to draw + auto resPath = *CResourceHandler::get()->getResourceName(ResourceID("DATA/new-menu/Background.png")); + + scene = new QGraphicsScene(this); + ui->graphicsView->setScene(scene); + scene->addPixmap(QPixmap(QString::fromStdString(resPath.native()))); + + +} + +MainWindow::~MainWindow() +{ + delete ui; +} + +void MainWindow::on_actionOpen_triggered() +{ + auto fileName = QFileDialog::getOpenFileName(this, tr("Open Image"), QString::fromStdString(VCMIDirs::get().userCachePath().native()), tr("Homm3 Files (*.vmap *.h3m)")); + +} + diff --git a/mapeditor/mainwindow.h b/mapeditor/mainwindow.h new file mode 100644 index 000000000..153ccc709 --- /dev/null +++ b/mapeditor/mainwindow.h @@ -0,0 +1,28 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include + +namespace Ui { +class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = nullptr); + ~MainWindow(); + +private slots: + void on_actionOpen_triggered(); + +private: + Ui::MainWindow *ui; + + QGraphicsScene * scene; +}; + +#endif // MAINWINDOW_H diff --git a/mapeditor/mainwindow.ui b/mapeditor/mainwindow.ui new file mode 100644 index 000000000..d1c21259c --- /dev/null +++ b/mapeditor/mainwindow.ui @@ -0,0 +1,61 @@ + + + MainWindow + + + + 0 + 0 + 1055 + 737 + + + + MainWindow + + + + + + + + + + + + 0 + 0 + 1055 + 22 + + + + + File + + + + + + + + + toolBar + + + TopToolBarArea + + + false + + + + + + Open + + + + + +