Merge lp:~widelands-dev/widelands/map_object_info into lp:widelands

Proposed by GunChleoc
Status: Merged
Merged at revision: 8007
Proposed branch: lp:~widelands-dev/widelands/map_object_info
Merge into: lp:widelands
Diff against target: 960 lines (+728/-69)
14 files modified
CMakeLists.txt (+1/-0)
compile.sh (+47/-18)
data/tribes/scripting/mapobject_info/building_helptext.lua (+9/-0)
data/tribes/scripting/mapobject_info/ware_helptext.lua (+9/-0)
data/tribes/scripting/mapobject_info/worker_helptext.lua (+9/-0)
debian/widelands.install (+1/-0)
src/CMakeLists.txt (+3/-0)
src/logic/CMakeLists.txt (+0/-16)
src/logic/map_objects/immovable.cc (+19/-10)
src/logic/map_objects/immovable.h (+3/-0)
src/scripting/lua_map.cc (+6/-25)
src/website/CMakeLists.txt (+30/-0)
src/website/map_object_info.cc (+536/-0)
utils/validate_json.py (+55/-0)
To merge this branch: bzr merge lp:~widelands-dev/widelands/map_object_info
Reviewer Review Type Date Requested Status
Miroslav Remák code, testing Approve
GunChleoc Needs Resubmitting
kaputtnik (community) testing Approve
Review via email: mp+287409@code.launchpad.net

Commit message

Created a new executable that will generate JSON files for updating the encyclopedia on the website.

Description of the change

Created a new executable that will generate JSON files for updating the encyclopedia on the website.

I recommend that we wait with merging this when we get close to the release candidate, because we now have extra linking time with each compile.

Related website branch:

https://code.launchpad.net/~widelands-dev/widelands-website/encyclopedia

To post a comment you must log in.
Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 781. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/112440876.
Appveyor build 627. State: failed. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_map_object_info-627.

Revision history for this message
kaputtnik (franku) wrote :

Works :-)

review: Approve (testing)
Revision history for this message
GunChleoc (gunchleoc) wrote :

Putting this on hold to give bunnybot a break - will make a new merge request when this is ready again.

Revision history for this message
GunChleoc (gunchleoc) wrote :

The output path is now defined on the command line when calling the executable. If the new changes are OK, this can go in now.

review: Needs Resubmitting
Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 797. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/113180179.
Appveyor build 643. State: failed. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_map_object_info-643.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 1114. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/130181884.
Appveyor build 951. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_map_object_info-951.

Revision history for this message
Miroslav Remák (miroslavr256) wrote :

> I recommend that we wait with merging this when we get close to the release
> candidate, because we now have extra linking time with each compile.

How about a CMake option for compiling website-related tools?

Revision history for this message
GunChleoc (gunchleoc) wrote :

> How about a CMake option for compiling website-related tools?

Tried and failed and decided not to spent more time on it at the moment.

Revision history for this message
Miroslav Remák (miroslavr256) wrote :

Review in the diff comments. JSON seems to be generated properly, but I don't have the website set up, so I am unable to test with your other branch there.

review: Needs Fixing (code, running)
Revision history for this message
GunChleoc (gunchleoc) wrote :

Thanks for the review and CMake tips - this should now be ready.

The corresponding branch for the website can't read the command-line parameter for the output path yet. This is not a problem for this branch though, because the encyclopedia is only updated manually. So, it can't screw up the website.

review: Needs Resubmitting
Revision history for this message
Miroslav Remák (miroslavr256) wrote :

Changes LGTM.

review: Approve (code, testing)
Revision history for this message
GunChleoc (gunchleoc) wrote :

Thanks!

@bunnybot merge

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2016-04-23 08:16:51 +0000
3+++ CMakeLists.txt 2016-05-17 16:16:33 +0000
4@@ -6,6 +6,7 @@
5
6 option(OPTION_USE_GLBINDING "Use glbinding instead of GLEW" OFF)
7 option(OPTION_GLEW_STATIC "Use static GLEW Library" OFF)
8+option(OPTION_BUILD_WEBSITE_TOOLS "Build website-related tools" ON)
9
10 if (CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
11 message(FATAL_ERROR "Build directory and source directory must not be the same.")
12
13=== modified file 'compile.sh'
14--- compile.sh 2016-01-28 05:47:13 +0000
15+++ compile.sh 2016-05-17 16:16:33 +0000
16@@ -1,8 +1,8 @@
17 #!/bin/sh
18 echo " "
19-echo "################################################"
20-echo "# Script to simplify compilations of Widelands #"
21-echo "################################################"
22+echo "###########################################################"
23+echo "# Script to simplify the compilation of Widelands #"
24+echo "###########################################################"
25 echo " "
26 echo " Because of the many different systems Widelands"
27 echo " might be compiled on, we unfortunally can not"
28@@ -10,17 +10,38 @@
29 echo " compilation. To ensure your system is ready, best"
30 echo " check http://wl.widelands.org/wiki/BuildingWidelands"
31 echo " "
32-echo " You often find helpfully hands at our"
33+echo " You will often find helpful hands at our"
34 echo " * IRC Chat: http://wl.widelands.org/webchat/"
35 echo " * Forums: http://wl.widelands.org/forum/"
36 echo " * Mailinglist: http://wl.widelands.org/wiki/MailLists/"
37 echo " "
38-echo " Please post your bugreports and feature requests at:"
39+echo " Please post your bug reports and feature requests at:"
40 echo " https://bugs.launchpad.net/widelands"
41 echo " "
42-echo "################################################"
43-echo " "
44-
45+echo "###########################################################"
46+echo " "
47+
48+
49+## Option to avoid building and linking website-related executables.
50+NO_WEBSITE=0
51+while [ "$1" != "" ]; do
52+ if [ "$1" = "--no-website" -o "$1" = "-n" ]; then
53+ NO_WEBSITE=1
54+ fi
55+ shift
56+done
57+if [ $NO_WEBSITE -eq 0 ]; then
58+ echo "A complete build will be created."
59+ echo "You can use -n or --no-website to omit building and"
60+ echo "linking website-related executables."
61+else
62+ echo "Any website-related code will be OMITTED in the build."
63+ echo "Make sure that you have created and tested a full"
64+ echo "build before submitting code to the repository!"
65+fi
66+echo " "
67+echo "###########################################################"
68+echo " "
69
70
71 ######################################
72@@ -73,9 +94,17 @@
73 echo "for instructions on how to adjust options and build with CMake."
74
75 if [ $buildtool = "ninja" ] || [ $buildtool = "ninja-build" ] ; then
76- cmake -G Ninja .. -DCMAKE_BUILD_TYPE=Debug
77+ if [ $NO_WEBSITE -eq 0 ]; then
78+ cmake -G Ninja .. -DCMAKE_BUILD_TYPE=Debug -DOPTION_BUILD_WEBSITE_TOOLS=ON
79+ else
80+ cmake -G Ninja .. -DCMAKE_BUILD_TYPE=Debug -DOPTION_BUILD_WEBSITE_TOOLS=OFF
81+ fi
82 else
83- cmake .. -DCMAKE_BUILD_TYPE=Debug
84+ if [ $NO_WEBSITE -eq 0 ]; then
85+ cmake .. -DCMAKE_BUILD_TYPE=Debug -DOPTION_BUILD_WEBSITE_TOOLS=ON
86+ else
87+ cmake .. -DCMAKE_BUILD_TYPE=Debug -DOPTION_BUILD_WEBSITE_TOOLS=OFF
88+ fi
89 fi
90
91 $buildtool
92@@ -150,12 +179,12 @@
93 cd ..
94 create_update_script
95 echo " "
96-echo "#####################################################"
97-echo "# Congratulations Widelands was successfully build. #"
98-echo "# You should now be able to run Widelands via #"
99-echo "# typing ./widelands + ENTER in your terminal #"
100-echo "# #"
101-echo "# You can update Widelands via running ./update.sh #"
102-echo "# in the same directory you ran this script in. #"
103-echo "#####################################################"
104+echo "###########################################################"
105+echo "# Congratulations! Widelands has been built successfully. #"
106+echo "# You should now be able to run Widelands via #"
107+echo "# typing ./widelands + ENTER in your terminal #"
108+echo "# #"
109+echo "# You can update Widelands via running ./update.sh #"
110+echo "# in the same directory that you ran this script in. #"
111+echo "###########################################################"
112 ######################################
113
114=== added directory 'data/tribes/scripting/mapobject_info'
115=== added file 'data/tribes/scripting/mapobject_info/building_helptext.lua'
116--- data/tribes/scripting/mapobject_info/building_helptext.lua 1970-01-01 00:00:00 +0000
117+++ data/tribes/scripting/mapobject_info/building_helptext.lua 2016-05-17 16:16:33 +0000
118@@ -0,0 +1,9 @@
119+-- This is used by the mapinfo standalone executable to get buildings' helptexts.
120+-- Note that this can't handle localization properly.
121+
122+return {
123+ func = function(helptext_script)
124+ include(helptext_script)
125+ return building_helptext_purpose()
126+ end
127+}
128
129=== added file 'data/tribes/scripting/mapobject_info/ware_helptext.lua'
130--- data/tribes/scripting/mapobject_info/ware_helptext.lua 1970-01-01 00:00:00 +0000
131+++ data/tribes/scripting/mapobject_info/ware_helptext.lua 2016-05-17 16:16:33 +0000
132@@ -0,0 +1,9 @@
133+-- This is used by the mapinfo standalone executable to get wares' helptexts.
134+-- Note that this can't handle localization properly.
135+
136+return {
137+ func = function(tribename, helptext_script)
138+ include(helptext_script)
139+ return ware_helptext(tribename)
140+ end
141+}
142
143=== added file 'data/tribes/scripting/mapobject_info/worker_helptext.lua'
144--- data/tribes/scripting/mapobject_info/worker_helptext.lua 1970-01-01 00:00:00 +0000
145+++ data/tribes/scripting/mapobject_info/worker_helptext.lua 2016-05-17 16:16:33 +0000
146@@ -0,0 +1,9 @@
147+-- This is used by the mapinfo standalone executable to get workers' helptexts.
148+-- Note that this can't handle localization properly.
149+
150+return {
151+ func = function(helptext_script)
152+ include(helptext_script)
153+ return worker_helptext()
154+ end
155+}
156
157=== modified file 'debian/widelands.install'
158--- debian/widelands.install 2016-01-22 07:20:01 +0000
159+++ debian/widelands.install 2016-05-17 16:16:33 +0000
160@@ -1,5 +1,6 @@
161 usr/widelands usr/games
162 usr/wl_map_info usr/games
163+usr/wl_mapobject_info usr/games
164 usr/wl_render_richtext usr/games
165 usr/share/applications
166 usr/share/icons
167
168=== modified file 'src/CMakeLists.txt'
169--- src/CMakeLists.txt 2016-02-06 11:11:24 +0000
170+++ src/CMakeLists.txt 2016-05-17 16:16:33 +0000
171@@ -82,6 +82,9 @@
172 add_subdirectory(third_party)
173 add_subdirectory(ui_basic)
174 add_subdirectory(ui_fsmenu)
175+if (OPTION_BUILD_WEBSITE_TOOLS)
176+ add_subdirectory(website)
177+endif (OPTION_BUILD_WEBSITE_TOOLS)
178 add_subdirectory(wui)
179
180 # TODO(unknown): Ideally widelands_ball_of_mud shouldn't exist, everything should be in a
181
182=== modified file 'src/logic/CMakeLists.txt'
183--- src/logic/CMakeLists.txt 2016-03-19 15:49:51 +0000
184+++ src/logic/CMakeLists.txt 2016-05-17 16:16:33 +0000
185@@ -1,19 +1,3 @@
186-wl_binary(wl_map_info
187- SRCS
188- map_info.cc
189- USES_SDL2
190- DEPENDS
191- base_log
192- graphic
193- graphic_image_io
194- graphic_minimap_renderer
195- graphic_surface
196- io_fileread
197- io_filesystem
198- logic
199- map_io_map_loader
200-)
201-
202 wl_library(logic_widelands_geometry
203 SRCS
204 widelands_geometry.cc
205
206=== modified file 'src/logic/map_objects/immovable.cc'
207--- src/logic/map_objects/immovable.cc 2016-05-14 06:24:45 +0000
208+++ src/logic/map_objects/immovable.cc 2016-05-17 16:16:33 +0000
209@@ -58,9 +58,11 @@
210
211 namespace Widelands {
212
213-namespace {
214+BaseImmovable::BaseImmovable(const MapObjectDescr & mo_descr) :
215+MapObject(&mo_descr)
216+{}
217
218-BaseImmovable::Size string_to_size(const std::string& size) {
219+int32_t BaseImmovable::string_to_size(const std::string& size) {
220 if (size == "none")
221 return BaseImmovable::NONE;
222 if (size == "small")
223@@ -72,13 +74,20 @@
224 throw GameDataError("Unknown size %s.", size.c_str());
225 }
226
227-} // namespace
228-
229-
230-BaseImmovable::BaseImmovable(const MapObjectDescr & mo_descr) :
231-MapObject(&mo_descr)
232-{}
233-
234+std::string BaseImmovable::size_to_string(int32_t size) {
235+ switch (size) {
236+ case BaseImmovable::NONE:
237+ return "none";
238+ case BaseImmovable::SMALL:
239+ return "small";
240+ case BaseImmovable::MEDIUM:
241+ return "medium";
242+ case BaseImmovable::BIG:
243+ return "big";
244+ default:
245+ NEVER_HERE();
246+ }
247+}
248
249 static std::string const base_immovable_name = "unknown";
250
251@@ -203,7 +212,7 @@
252 }
253
254 if (table.has_key("size")) {
255- size_ = string_to_size(table.get_string("size"));
256+ size_ = BaseImmovable::string_to_size(table.get_string("size"));
257 }
258
259 if (table.has_key("terrain_affinity")) {
260
261=== modified file 'src/logic/map_objects/immovable.h'
262--- src/logic/map_objects/immovable.h 2016-03-19 09:58:41 +0000
263+++ src/logic/map_objects/immovable.h 2016-05-17 16:16:33 +0000
264@@ -96,6 +96,9 @@
265 (const EditorGameBase &, RenderTarget &, const FCoords&, const Point&)
266 = 0;
267
268+ static int32_t string_to_size(const std::string& size);
269+ static std::string size_to_string(int32_t size);
270+
271 protected:
272 void set_position(EditorGameBase &, Coords);
273 void unset_position(EditorGameBase &, Coords);
274
275=== modified file 'src/scripting/lua_map.cc'
276--- src/scripting/lua_map.cc 2016-04-23 09:31:28 +0000
277+++ src/scripting/lua_map.cc 2016-05-17 16:16:33 +0000
278@@ -1562,20 +1562,9 @@
279 * :const:`big` -- Example: Big sized buildings or rocks
280 */
281 int LuaImmovableDescription::get_size(lua_State * L) {
282- switch (get()->get_size()) {
283- case BaseImmovable::NONE:
284- lua_pushstring(L, "none");
285- break;
286- case BaseImmovable::SMALL:
287- lua_pushstring(L, "small");
288- break;
289- case BaseImmovable::MEDIUM:
290- lua_pushstring(L, "medium");
291- break;
292- case BaseImmovable::BIG:
293- lua_pushstring(L, "big");
294- break;
295- default:
296+ try {
297+ lua_pushstring(L, BaseImmovable::size_to_string(get()->get_size()));
298+ } catch (std::exception&) {
299 report_error(L, "Unknown size %i in LuaImmovableDescription::get_size: %s",
300 get()->get_size(), get()->name().c_str());
301 }
302@@ -1821,17 +1810,9 @@
303 * :const:`big` -- Big sized buildings
304 */
305 int LuaBuildingDescription::get_size(lua_State * L) {
306- switch (get()->get_size()) {
307- case BaseImmovable::SMALL:
308- lua_pushstring(L, "small");
309- break;
310- case BaseImmovable::MEDIUM:
311- lua_pushstring(L, "medium");
312- break;
313- case BaseImmovable::BIG:
314- lua_pushstring(L, "big");
315- break;
316- default:
317+ try {
318+ lua_pushstring(L, BaseImmovable::size_to_string(get()->get_size()));
319+ } catch (std::exception&) {
320 report_error(L, "Unknown size %i in LuaBuildingDescription::get_size: %s",
321 get()->get_size(), get()->name().c_str());
322 }
323
324=== added directory 'src/website'
325=== added file 'src/website/CMakeLists.txt'
326--- src/website/CMakeLists.txt 1970-01-01 00:00:00 +0000
327+++ src/website/CMakeLists.txt 2016-05-17 16:16:33 +0000
328@@ -0,0 +1,30 @@
329+wl_binary(wl_map_info
330+ SRCS
331+ map_info.cc
332+ USES_SDL2
333+ DEPENDS
334+ base_log
335+ graphic
336+ graphic_image_io
337+ graphic_minimap_renderer
338+ graphic_surface
339+ io_fileread
340+ io_filesystem
341+ logic
342+ map_io_map_loader
343+)
344+
345+wl_binary(wl_map_object_info
346+ SRCS
347+ map_object_info.cc
348+ USES_SDL2
349+ DEPENDS
350+ base_i18n
351+ base_log
352+ base_macros
353+ graphic
354+ io_fileread
355+ io_filesystem
356+ logic
357+ sound
358+)
359
360=== renamed file 'src/logic/map_info.cc' => 'src/website/map_info.cc'
361=== added file 'src/website/map_object_info.cc'
362--- src/website/map_object_info.cc 1970-01-01 00:00:00 +0000
363+++ src/website/map_object_info.cc 2016-05-17 16:16:33 +0000
364@@ -0,0 +1,536 @@
365+/*
366+ * Copyright (C) 2016 by the Widelands Development Team
367+ *
368+ * This program is free software; you can redistribute it and/or
369+ * modify it under the terms of the GNU General Public License
370+ * as published by the Free Software Foundation; either version 2
371+ * of the License, or (at your option) any later version.
372+ *
373+ * This program is distributed in the hope that it will be useful,
374+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
375+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
376+ * GNU General Public License for more details.
377+ *
378+ * You should have received a copy of the GNU General Public License
379+ * along with this program; if not, write to the Free Software
380+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
381+ *
382+ */
383+
384+#include <memory>
385+
386+#include <SDL.h>
387+#include <boost/algorithm/string.hpp>
388+#include <boost/format.hpp>
389+#include <boost/lexical_cast.hpp>
390+
391+#include "base/i18n.h"
392+#include "base/log.h"
393+#include "base/macros.h"
394+#include "config.h"
395+#include "graphic/graphic.h"
396+#include "io/filesystem/filesystem.h"
397+#include "io/filesystem/layered_filesystem.h"
398+#include "io/filewrite.h"
399+#include "logic/editor_game_base.h"
400+#include "logic/map_objects/tribes/tribes.h"
401+#include "logic/map_objects/world/world.h"
402+#include "sound/sound_handler.h"
403+
404+using namespace Widelands;
405+
406+namespace {
407+
408+/*
409+ ==========================================================
410+ SETUP
411+ ==========================================================
412+ */
413+
414+
415+// Setup the static objects Widelands needs to operate and initializes systems.
416+std::unique_ptr<FileSystem> initialize(const std::string& output_path) {
417+ i18n::set_locale("en");
418+
419+ if (SDL_Init(SDL_INIT_VIDEO) != 0) {
420+ throw wexception("Unable to initialize SDL: %s", SDL_GetError());
421+ }
422+
423+ g_fs = new LayeredFileSystem();
424+ g_fs->add_file_system(&FileSystem::create(INSTALL_DATADIR));
425+
426+ std::unique_ptr<FileSystem> out_filesystem(&FileSystem::create(output_path));
427+
428+ // We don't really need graphics or sound here, but we will get error messages
429+ // when they aren't initialized
430+ g_gr = new Graphic();
431+ g_gr->initialize(Graphic::TraceGl::kNo, 1, 1, false);
432+
433+ g_sound_handler.init();
434+ g_sound_handler.nosound_ = true;
435+ return out_filesystem;
436+}
437+
438+// Cleanup before program end
439+void cleanup() {
440+ g_sound_handler.shutdown();
441+
442+ if (g_gr) {
443+ delete g_gr;
444+ g_gr = nullptr;
445+ }
446+
447+ if (g_fs) {
448+ delete g_fs;
449+ g_fs = nullptr;
450+ }
451+
452+ SDL_Quit();
453+}
454+
455+/*
456+ ==========================================================
457+ SPECIALIZED FILEWRITE
458+ ==========================================================
459+ */
460+
461+// Defines some convenience writing functions for the JSON format
462+class JSONFileWrite : public FileWrite {
463+public:
464+ JSONFileWrite() : FileWrite(), level_(0) {}
465+
466+ void write_string(const std::string& s, bool use_indent = false) {
467+ std::string writeme = s;
468+ if (use_indent) {
469+ for (int i = 0; i < level_; ++i) {
470+ writeme = (boost::format(" %s") % writeme).str();
471+ }
472+ }
473+ data(writeme.c_str(), writeme.size());
474+ }
475+ void write_key(const std::string& key) {
476+ write_string((boost::format("\"%s\":\n") % key).str(), true);
477+ }
478+ void write_value_string(const std::string& quoted_value) {
479+ write_string((boost::format("\"%s\"") % quoted_value).str(), true);
480+ }
481+ void write_key_value(const std::string& key, const std::string& quoted_value) {
482+ write_string((boost::format("\"%s\": %s") % key % quoted_value).str(), true);
483+ }
484+ void write_key_value_string(const std::string& key, const std::string& value) {
485+ std::string quoted_value = value;
486+ boost::replace_all(quoted_value, "\"", "\\\"");
487+ write_key_value(key, "\"" + value + "\"");
488+ }
489+ void write_key_value_int(const std::string& key, const int value) {
490+ write_key_value(key, boost::lexical_cast<std::string>(value));
491+ }
492+ void open_brace() {
493+ write_string("{\n", true);
494+ ++level_;
495+ }
496+ // JSON hates a final comma. This defaults to having NO comma.
497+ void close_brace(bool precede_newline = false, int current = 0, int total = 0) {
498+ --level_;
499+ if (precede_newline) {
500+ write_string("\n");
501+ }
502+ if (current < total - 1) {
503+ write_string("},\n", true);
504+ } else {
505+ write_string("}", true);
506+ }
507+ }
508+ void open_array(const std::string& name) {
509+ write_string((boost::format("\"%s\":[\n") % name).str(), true);
510+ ++level_;
511+ }
512+ // JSON hates a final comma. This defaults to having NO comma.
513+ void close_array(int current = 0, int total = 0) {
514+ --level_;
515+ write_string("\n");
516+ if (current < total - 1) {
517+ write_string("],\n", true);
518+ } else {
519+ write_string("]\n", true);
520+ }
521+ }
522+ // JSON hates a final comma. This defaults to having a comma.
523+ void close_element(int current = -2, int total = 0) {
524+ if (current < total - 1) {
525+ write_string(",\n");
526+ }
527+ }
528+private:
529+ int level_;
530+};
531+
532+/*
533+ ==========================================================
534+ BUILDINGS
535+ ==========================================================
536+ */
537+
538+void write_buildings(const TribeDescr& tribe, EditorGameBase& egbase, FileSystem* out_filesystem) {
539+
540+ log("\n==================\nWriting buildings:\n==================\n");
541+ JSONFileWrite fw;
542+ fw.open_brace(); // Main
543+ fw.open_array("buildings"); // Buildings
544+
545+ // We don't want any partially finished buildings
546+ std::vector<const BuildingDescr*> buildings;
547+ for (const DescriptionIndex& index : tribe.buildings()) {
548+ const BuildingDescr* building = tribe.get_building_descr(index);
549+ if (building->type() != MapObjectType::CONSTRUCTIONSITE &&
550+ building->type() != MapObjectType::DISMANTLESITE) {
551+ buildings.push_back(building);
552+ }
553+ }
554+
555+ // Now write
556+ for (size_t i = 0; i < buildings.size(); ++i) {
557+ const BuildingDescr& building = *buildings[i];
558+ log(" %s", building.name().c_str());
559+ fw.open_brace(); // Building
560+
561+ fw.write_key_value_string("name", building.name());
562+ fw.close_element();
563+ fw.write_key_value_string("descname", building.descname());
564+ fw.close_element();
565+ fw.write_key_value_string("icon", building.representative_image_filename());
566+ fw.close_element();
567+
568+ // Conditional stuff in between, so we won't run into trouble with the commas.
569+
570+ // Buildcost
571+ if (building.is_buildable()) {
572+ fw.open_array("buildcost"); // Buildcost
573+ size_t buildcost_counter = 0;
574+ for (WareAmount buildcost : building.buildcost()) {
575+ const WareDescr& ware = *tribe.get_ware_descr(buildcost.first);
576+ fw.open_brace(); // Buildcost
577+ fw.write_key_value_string("name", ware.name());
578+ fw.close_element();
579+ fw.write_key_value_int("amount", buildcost.second);
580+ fw.close_brace(true, buildcost_counter, building.buildcost().size()); // Buildcost
581+ ++buildcost_counter;
582+ }
583+ fw.close_array(1, 5); // Buildcost - we need a comma
584+ }
585+
586+ if (building.is_enhanced()) {
587+ fw.write_key_value_string("enhanced", tribe.get_building_descr(building.enhanced_from())->name());
588+ fw.close_element();
589+ }
590+
591+ if (building.enhancement() != INVALID_INDEX) {
592+ fw.write_key_value_string("enhancement", tribe.get_building_descr(building.enhancement())->name());
593+ fw.close_element();
594+ }
595+
596+ if (upcast(ProductionSiteDescr const, productionsite, &building)) {
597+ // Produces
598+ if (productionsite->output_ware_types().size() > 0) {
599+ fw.open_array("produced_wares"); // Produces
600+ size_t produces_counter = 0;
601+ for (DescriptionIndex ware_index : productionsite->output_ware_types()) {
602+ fw.write_value_string(tribe.get_ware_descr(ware_index)->name());
603+ fw.close_element(produces_counter, productionsite->output_ware_types().size());
604+ ++produces_counter;
605+ }
606+ fw.close_array(1, 5); // Produces - we need a comma
607+ }
608+ if (productionsite->output_worker_types().size() > 0) {
609+ fw.open_array("produced_workers"); // Produces
610+ size_t produces_counter = 0;
611+ for (DescriptionIndex worker_index : productionsite->output_worker_types()) {
612+ fw.write_value_string(tribe.get_worker_descr(worker_index)->name());
613+ fw.close_element(produces_counter, productionsite->output_worker_types().size());
614+ ++produces_counter;
615+ }
616+ fw.close_array(1, 5); // Produces - we need a comma
617+ }
618+
619+ // Consumes
620+ if (productionsite->inputs().size() > 0) {
621+ fw.open_array("stored_wares"); // Consumes
622+ size_t consumes_counter = 0;
623+ for (WareAmount input : productionsite->inputs()) {
624+ const WareDescr& ware = *tribe.get_ware_descr(input.first);
625+ fw.open_brace(); // Input
626+ fw.write_key_value_string("name", ware.name());
627+ fw.close_element();
628+ fw.write_key_value_int("amount", input.second);
629+ fw.close_brace(true, consumes_counter, productionsite->inputs().size()); // Input
630+ ++consumes_counter;
631+ }
632+ fw.close_array(1, 5); // Consumes - we need a comma
633+ }
634+
635+ fw.open_array("workers"); // Workers
636+ size_t worker_counter = 0;
637+ for (WareAmount input : productionsite->working_positions()) {
638+ const WorkerDescr& worker = *tribe.get_worker_descr(input.first);
639+ fw.open_brace(); // Worker
640+ fw.write_key_value_string("name", worker.name());
641+ fw.close_element();
642+ fw.write_key_value_int("amount", input.second);
643+ fw.close_brace(true, worker_counter, productionsite->working_positions().size()); // Worker
644+ ++worker_counter;
645+ }
646+ fw.close_array(1, 5); // Workers - we need a comma
647+ } else if (upcast(MilitarySiteDescr const, militarysite, &building)) {
648+ fw.write_key_value_int("conquers", militarysite->get_conquers());
649+ fw.close_element();
650+ fw.write_key_value_int("max_soldiers", militarysite->get_max_number_of_soldiers());
651+ fw.close_element();
652+ fw.write_key_value_int("heal_per_second", militarysite->get_heal_per_second());
653+ fw.close_element();
654+ }
655+
656+ switch (building.type()) {
657+ case MapObjectType::PRODUCTIONSITE:
658+ fw.write_key_value_string("type", "productionsite");
659+ break;
660+ case MapObjectType::WAREHOUSE:
661+ fw.write_key_value_string("type", "warehouse");
662+ break;
663+ case MapObjectType::MILITARYSITE:
664+ fw.write_key_value_string("type", "militarysite");
665+ break;
666+ case MapObjectType::TRAININGSITE:
667+ fw.write_key_value_string("type", "trainingsite");
668+ break;
669+ default:
670+ NEVER_HERE();
671+ }
672+ fw.close_element();
673+
674+ // Size
675+ if (building.type() == MapObjectType::WAREHOUSE &&
676+ !building.is_buildable() && !building.is_enhanced()) {
677+ fw.write_key_value_string("size", "headquarters");
678+ } else if (building.get_ismine()) {
679+ fw.write_key_value_string("size", "mine");
680+ } else if (building.get_isport()) {
681+ fw.write_key_value_string("size", "port");
682+ } else {
683+ fw.write_key_value_string("size", BaseImmovable::size_to_string(building.get_size()));
684+ }
685+ fw.close_element();
686+
687+ // Helptext
688+ try {
689+ std::unique_ptr<LuaTable> table(
690+ egbase.lua().run_script("tribes/scripting/mapobject_info/building_helptext.lua"));
691+ std::unique_ptr<LuaCoroutine> cr(table->get_coroutine("func"));
692+ cr->push_arg(building.helptext_script());
693+ cr->resume();
694+ const std::string help_text = cr->pop_string();
695+ fw.write_key_value_string("helptext", help_text);
696+ } catch (LuaError& err) {
697+ fw.write_key_value_string("helptext", err.what());
698+ }
699+
700+ fw.close_brace(true, i, buildings.size()); // Building
701+ }
702+ fw.close_array(); // Buildings
703+ fw.close_brace(); // Main
704+ fw.write(*out_filesystem, (boost::format("%s_buildings.json") % tribe.name()).str().c_str());
705+ log("\n");
706+}
707+
708+/*
709+ ==========================================================
710+ WARES
711+ ==========================================================
712+ */
713+
714+void write_wares(const TribeDescr& tribe, EditorGameBase& egbase, FileSystem* out_filesystem) {
715+ log("\n===============\nWriting wares:\n===============\n");
716+ JSONFileWrite fw;
717+ fw.open_brace(); // Main
718+
719+ fw.open_array("wares"); // Wares
720+ size_t counter = 0;
721+ const size_t no_of_wares = tribe.wares().size();
722+ for (DescriptionIndex ware_index : tribe.wares()) {
723+ const WareDescr& ware = *tribe.get_ware_descr(ware_index);
724+ log(" %s", ware.name().c_str());
725+ fw.open_brace();
726+ fw.write_key_value_string("name", ware.name());
727+ fw.close_element();
728+ fw.write_key_value_string("descname", ware.descname());
729+ fw.close_element();
730+ fw.write_key_value_string("icon", ware.icon_filename());
731+ fw.close_element();
732+
733+ // Helptext
734+ try {
735+ std::unique_ptr<LuaTable> table(
736+ egbase.lua().run_script("tribes/scripting/mapobject_info/ware_helptext.lua"));
737+ std::unique_ptr<LuaCoroutine> cr(table->get_coroutine("func"));
738+ cr->push_arg(tribe.name());
739+ cr->push_arg(ware.helptext_script());
740+ cr->resume();
741+ const std::string help_text = cr->pop_string();
742+ fw.write_key_value_string("helptext", help_text);
743+ } catch (LuaError& err) {
744+ fw.write_key_value_string("helptext", err.what());
745+ }
746+ fw.close_brace(true, counter, no_of_wares); // Ware
747+ ++counter;
748+ }
749+ fw.close_array(); // Wares
750+
751+ fw.close_brace(); // Main
752+ fw.write(*out_filesystem, (boost::format("%s_wares.json") % tribe.name()).str().c_str());
753+ log("\n");
754+}
755+
756+/*
757+ ==========================================================
758+ WORKERS
759+ ==========================================================
760+ */
761+
762+void write_workers(const TribeDescr& tribe, EditorGameBase& egbase, FileSystem* out_filesystem) {
763+ log("\n================\nWriting workers:\n================\n");
764+ JSONFileWrite fw;
765+ fw.open_brace(); // Main
766+
767+ fw.open_array("workers"); // Workers
768+ size_t counter = 0;
769+ const size_t no_of_workers = tribe.workers().size();
770+ for (DescriptionIndex worker_index : tribe.workers()) {
771+ const WorkerDescr& worker = *tribe.get_worker_descr(worker_index);
772+ log(" %s", worker.name().c_str());
773+ fw.open_brace();
774+ fw.write_key_value_string("name", worker.name());
775+ fw.close_element();
776+ fw.write_key_value_string("descname", worker.descname());
777+ fw.close_element();
778+ fw.write_key_value_string("icon", worker.icon_filename());
779+ fw.close_element();
780+
781+ // Helptext
782+ try {
783+ std::unique_ptr<LuaTable> table(
784+ egbase.lua().run_script("tribes/scripting/mapobject_info/worker_helptext.lua"));
785+ std::unique_ptr<LuaCoroutine> cr(table->get_coroutine("func"));
786+ cr->push_arg(worker.helptext_script());
787+ cr->resume();
788+ const std::string help_text = cr->pop_string();
789+ fw.write_key_value_string("helptext", help_text);
790+ } catch (LuaError& err) {
791+ fw.write_key_value_string("helptext", err.what());
792+ }
793+
794+ if (worker.becomes() != INVALID_INDEX) {
795+ fw.close_element();
796+ const WorkerDescr& becomes = *tribe.get_worker_descr(worker.becomes());
797+ fw.write_key("becomes");
798+ fw.open_brace();
799+ fw.write_key_value_string("name", becomes.name());
800+ fw.close_element();
801+ fw.write_key_value_int("experience", worker.get_needed_experience());
802+ fw.close_brace(true);
803+ }
804+ fw.close_brace(true, counter, no_of_workers); // Worker
805+ ++counter;
806+ }
807+ fw.close_array(); // Workers
808+
809+ fw.close_brace(); // Main
810+ fw.write(*out_filesystem, (boost::format("%s_workers.json") % tribe.name()).str().c_str());
811+ log("\n");
812+}
813+
814+/*
815+ ==========================================================
816+ TRIBES
817+ ==========================================================
818+ */
819+
820+void add_tribe_info(const TribeBasicInfo& tribe_info, JSONFileWrite* fw) {
821+ fw->write_key_value_string("name", tribe_info.name);
822+ fw->close_element();
823+ fw->write_key_value_string("descname", tribe_info.descname);
824+ fw->close_element();
825+ fw->write_key_value_string("author", tribe_info.author);
826+ fw->close_element();
827+ fw->write_key_value_string("tooltip", tribe_info.tooltip);
828+ fw->close_element();
829+ fw->write_key_value_string("icon", tribe_info.icon);
830+}
831+
832+void write_tribes(EditorGameBase& egbase, FileSystem* out_filesystem) {
833+ JSONFileWrite fw;
834+ fw.open_brace(); // Main
835+ fw.open_array("tribes"); // Tribes
836+
837+ /// Tribes
838+ egbase.mutable_tribes()->postload(); // Make sure that all values have been set.
839+ const Tribes& tribes = egbase.tribes();
840+
841+ std::vector<TribeBasicInfo> tribeinfos = tribes.get_all_tribeinfos();
842+ for (size_t tribe_index = 0; tribe_index < tribeinfos.size(); ++tribe_index) {
843+ const TribeBasicInfo& tribe_info = tribeinfos[tribe_index];
844+ log("\n\n=========================\nWriting tribe: %s\n=========================\n",
845+ tribe_info.name.c_str());
846+
847+ fw.open_brace(); // TribeDescr
848+ add_tribe_info(tribe_info, &fw);
849+ fw.close_brace(true, tribe_index, tribeinfos.size()); // TribeDescr
850+
851+ // These go in separate files
852+
853+ JSONFileWrite fw_tribe;
854+ fw_tribe.open_brace(); // TribeDescr
855+ add_tribe_info(tribe_info, &fw_tribe);
856+ fw_tribe.close_brace(true); // TribeDescr
857+ fw_tribe.write(*out_filesystem, (boost::format("tribe_%s.json") % tribe_info.name).str().c_str());
858+
859+ const TribeDescr& tribe =
860+ *tribes.get_tribe_descr(tribes.tribe_index(tribe_info.name));
861+
862+ write_buildings(tribe, egbase, out_filesystem);
863+ write_wares(tribe, egbase, out_filesystem);
864+ write_workers(tribe, egbase, out_filesystem);
865+ }
866+ fw.close_array(); // Tribes
867+ fw.close_brace(); // Main
868+ fw.write(*out_filesystem, "tribes.json");
869+}
870+
871+} // namespace
872+
873+/*
874+ ==========================================================
875+ MAIN
876+ ==========================================================
877+ */
878+
879+int main(int argc, char ** argv)
880+{
881+ if (argc != 2) {
882+ log("Usage: %s <existing-output-path>\n", argv[0]);
883+ return 1;
884+ }
885+
886+ const std::string output_path = argv[argc - 1];
887+
888+ try {
889+ std::unique_ptr<FileSystem> out_filesystem = initialize(output_path);
890+ EditorGameBase egbase(nullptr);
891+ write_tribes(egbase, out_filesystem.get());
892+ }
893+ catch (std::exception& e) {
894+ log("Exception: %s.\n", e.what());
895+ cleanup();
896+ return 1;
897+ }
898+ cleanup();
899+ return 0;
900+}
901
902=== added file 'utils/validate_json.py'
903--- utils/validate_json.py 1970-01-01 00:00:00 +0000
904+++ utils/validate_json.py 2016-05-17 16:16:33 +0000
905@@ -0,0 +1,55 @@
906+#!/usr/bin/env python
907+# encoding: utf-8
908+
909+import codecs
910+import json
911+import os.path
912+import sys
913+
914+# Tests if the .json files in the directories on the bottom are valid JSON files
915+
916+def validate_files_in_path(source_path):
917+
918+ if (not os.path.isdir(source_path)):
919+ print("Error: Path " + source_path + " not found.")
920+ sys.exit(1)
921+
922+ source_files = sorted(os.listdir(source_path), key=str.lower)
923+
924+ print("\nReading JSON files in: " + source_path + "\n")
925+ failed = 0
926+ for source_filename in source_files:
927+ file_path = source_path + "/" + source_filename
928+ if source_filename.endswith(".json"):
929+ source_file = open(file_path, "r")
930+ try:
931+ dataset = json.load(source_file)
932+ print(source_filename)
933+ except ValueError as err:
934+ failed = failed + 1
935+ print("\n Error reading " + source_filename + ":");
936+ print(" " + str(err))
937+
938+ if failed == 0:
939+ print("\nAll JSON files are OK.")
940+ else:
941+ if failed == 1:
942+ print("\n" + str(failed) + " file is not valid JSON!");
943+ else:
944+ print("\n" + str(failed) + " files are not valid JSON!");
945+ return failed < 1
946+
947+sucess = False
948+
949+if (len(sys.argv) == 2):
950+ base_path = os.path.normpath(sys.argv[1])
951+ if (not os.path.exists(base_path) or os.path.isfile(base_path)):
952+ base_path = os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir))
953+
954+ if (os.path.exists(base_path) and not os.path.isfile(base_path)):
955+ success = validate_files_in_path(os.path.normpath(base_path))
956+
957+if success:
958+ sys.exit(0)
959+else:
960+ sys.exit(1)

Subscribers

People subscribed via source and target branches

to status/vote changes: