aboutsummaryrefslogtreecommitdiff
path: root/src/mapgen_singlenode.cpp
blob: fd443995c6ef50a0c9040f484260ff82a5266baa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/*
Minetest
Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include "mapgen_singlenode.h"
#include "voxel.h"
#include "mapblock.h"
#include "mapnode.h"
#include "map.h"
#include "nodedef.h"
#include "voxelalgorithms.h"
#include "profiler.h"
#include "emerge.h"

//////////////////////// Mapgen Singlenode parameter read/write

bool MapgenSinglenodeParams::readParams(Settings *settings) {
	return true;
}


void MapgenSinglenodeParams::writeParams(Settings *settings) {
}

///////////////////////////////////////////////////////////////////////////////

MapgenSinglenode::MapgenSinglenode(int mapgenid, MapgenSinglenodeParams *params) {
	flags = params->flags;
}


MapgenSinglenode::~MapgenSinglenode() {
}

//////////////////////// Map generator

void MapgenSinglenode::makeChunk(BlockMakeData *data) {
	assert(data->vmanip);
	assert(data->nodedef);
	assert(data->blockpos_requested.X >= data->blockpos_min.X &&
		   data->blockpos_requested.Y >= data->blockpos_min.Y &&
		   data->blockpos_requested.Z >= data->blockpos_min.Z);
	assert(data->blockpos_requested.X <= data->blockpos_max.X &&
		   data->blockpos_requested.Y <= data->blockpos_max.Y &&
		   data->blockpos_requested.Z <= data->blockpos_max.Z);

	this->generating = true;
	this->vm   = data->vmanip;	
	this->ndef = data->nodedef;
			
	v3s16 blockpos_min = data->blockpos_min;
	v3s16 blockpos_max = data->blockpos_max;

	// Area of central chunk
	v3s16 node_min = blockpos_min*MAP_BLOCKSIZE;
	v3s16 node_max = (blockpos_max+v3s16(1,1,1))*MAP_BLOCKSIZE-v3s16(1,1,1);

	content_t c_node = ndef->getId("mapgen_singlenode");
	if (c_node == CONTENT_IGNORE)
		c_node = CONTENT_AIR;
	
	MapNode n_node(c_node);
	
	for (s16 z = node_min.Z; z <= node_max.Z; z++)
	for (s16 y = node_min.Y; y <= node_max.Y; y++) {
		u32 i = vm->m_area.index(node_min.X, y, z);
		for (s16 x = node_min.X; x <= node_max.X; x++) {
			if (vm->m_data[i].getContent() == CONTENT_IGNORE)
				vm->m_data[i] = n_node;
			i++;
		}
	}

	// Add top and bottom side of water to transforming_liquid queue
	updateLiquid(&data->transforming_liquid, node_min, node_max);

	// Calculate lighting
	if (!(flags & MG_NOLIGHT))
		calcLighting(node_min - v3s16(1, 0, 1) * MAP_BLOCKSIZE,
					 node_max + v3s16(1, 0, 1) * MAP_BLOCKSIZE);
	
	this->generating = false;
}

int MapgenSinglenode::getGroundLevelAtPoint(v2s16 p) {
	return 0;
}

' href='#n458'>458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720
/*
Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/


#include <iostream> 
#include <string>
#include <map>

#include "guiConfigureWorld.h"
#include "guiMessageMenu.h"
#include <IGUIButton.h>
#include <IGUICheckBox.h>
#include <IGUIListBox.h>
#include <IGUIStaticText.h>
#include <IGUITreeView.h>
#include "gettext.h"
#include "util/string.h"
#include "settings.h"
#include "filesys.h"

enum
{
	GUI_ID_MOD_TREEVIEW = 101,
	GUI_ID_ENABLED_CHECKBOX,
	GUI_ID_ENABLEALL,
	GUI_ID_DISABLEALL,
	GUI_ID_DEPENDS_LISTBOX,
	GUI_ID_RDEPENDS_LISTBOX,
	GUI_ID_CANCEL,
	GUI_ID_SAVE
};

#define QUESTIONMARK_STR L"?"
#define CHECKMARK_STR    L"\411"
#define CROSS_STR        L"\403"

GUIConfigureWorld::GUIConfigureWorld(gui::IGUIEnvironment* env,
		gui::IGUIElement* parent, s32 id,
		IMenuManager *menumgr, WorldSpec wspec):
	GUIModalMenu(env, parent, id, menumgr),
	m_wspec(wspec),
	m_gspec(findWorldSubgame(m_wspec.path)),
	m_menumgr(menumgr)
{
	//will be initialized in regenerateGUI()
	m_treeview=NULL;

	// game mods
	m_gamemods = flattenModTree(getModsInPath(m_gspec.gamemods_path));

	// world mods
	std::string worldmods_path = wspec.path + DIR_DELIM + "worldmods";
	m_worldmods = flattenModTree(getModsInPath(worldmods_path));

	// fill m_addontree with add-on mods
	std::set<std::string> paths = m_gspec.addon_mods_paths;
	for(std::set<std::string>::iterator it=paths.begin();
		it != paths.end(); ++it)
	{
		std::map<std::string,ModSpec> mods = getModsInPath(*it);
		m_addontree.insert(mods.begin(), mods.end());
	}

	// expand modpacks
	m_addonmods = flattenModTree(m_addontree);

	// collect reverse dependencies
	for(std::map<std::string, ModSpec>::iterator it = m_addonmods.begin();
		it != m_addonmods.end(); ++it)
	{
		std::string modname = (*it).first;
		ModSpec mod = (*it).second;
		for(std::set<std::string>::iterator dep_it = mod.depends.begin();
			dep_it != mod.depends.end(); ++dep_it)
		{
			m_reverse_depends.insert(std::make_pair((*dep_it),modname));
		}
	}

	m_settings.readConfigFile((m_wspec.path + DIR_DELIM + "world.mt").c_str());
	std::vector<std::string> names = m_settings.getNames();

	// mod_names contains the names of mods mentioned in the world.mt file
	std::set<std::string> mod_names;
	for(std::vector<std::string>::iterator it = names.begin(); 
		it != names.end(); ++it)
	{	
		std::string name = *it;  
		if (name.compare(0,9,"load_mod_")==0)
			mod_names.insert(name.substr(9));
	}

	// find new mods (installed but not mentioned in world.mt)
	for(std::map<std::string, ModSpec>::iterator it = m_addonmods.begin();
		it != m_addonmods.end(); ++it)
	{
		std::string modname = (*it).first;
		ModSpec mod = (*it).second;
		// a mod is new if it is not a modpack, and does not occur in
		// mod_names
		if(!mod.is_modpack &&
		   mod_names.count(modname) == 0)
			m_new_mod_names.insert(modname);
	}
	if(!m_new_mod_names.empty())
	{
		wchar_t* text = wgettext("Warning: Some mods are not configured yet.\n"
				"They will be enabled by default when you save the configuration.  ");
		GUIMessageMenu *menu = 
			new GUIMessageMenu(Environment, Parent, -1, m_menumgr, text);
		menu->drop();
		delete[] text;
	}
	

	// find missing mods (mentioned in world.mt, but not installed)
	std::set<std::string> missing_mods;
	for(std::set<std::string>::iterator it = mod_names.begin();
		it != mod_names.end(); ++it)
	{
		std::string modname = *it;
		if(m_addonmods.count(modname) == 0)
			missing_mods.insert(modname);
	}
	if(!missing_mods.empty())
	{
		wchar_t* text = wgettext("Warning: Some configured mods are missing.\n"
				"Their setting will be removed when you save the configuration.  ");
		GUIMessageMenu *menu = 
			new GUIMessageMenu(Environment, Parent, -1, m_menumgr, text);
		delete[] text;
		for(std::set<std::string>::iterator it = missing_mods.begin();
			it != missing_mods.end(); ++it)
			m_settings.remove("load_mod_"+(*it));
		menu->drop();
	}	
}

void GUIConfigureWorld::drawMenu()
{
	gui::IGUISkin* skin = Environment->getSkin();
	if (!skin)
		return;
	video::IVideoDriver* driver = Environment->getVideoDriver();
	
	video::SColor bgcolor(140,0,0,0);
	driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);

	gui::IGUIElement::draw();
}


void GUIConfigureWorld::regenerateGui(v2u32 screensize)
{

	/*
		Remove stuff
	*/
	removeChildren();
	
	/*
		Calculate new sizes and positions
	*/
	core::rect<s32> rect(
			screensize.X/2 - 580/2,
			screensize.Y/2 - 300/2,
			screensize.X/2 + 580/2,
			screensize.Y/2 + 300/2
	);
	
	DesiredRect = rect;
	recalculateAbsolutePosition(false);

	v2s32 size = rect.getSize();

	v2s32 topleft = v2s32(10, 10);

	/*
		Add stuff
	*/
	changeCtype("");
	{
		core::rect<s32> rect(0, 0, 200, 20);
		rect += topleft;
		//proper text is set below, when a mod is selected
		m_modname_text = Environment->addStaticText(L"Mod: N/A", rect, false, 
													false, this, -1);
	}
	{
		core::rect<s32> rect(0, 0, 200, 20);
		rect += v2s32(0, 25) + topleft;
		wchar_t* text = wgettext("enabled");
		m_enabled_checkbox = 
			Environment->addCheckBox(false, rect, this, GUI_ID_ENABLED_CHECKBOX, 
									 text);
		delete[] text;
		m_enabled_checkbox->setVisible(false);
	}
	{
		core::rect<s32> rect(0, 0, 85, 30);
		rect = rect + v2s32(0, 25) + topleft;
		wchar_t* text = wgettext("Enable All");
		m_enableall = Environment->addButton(rect, this, GUI_ID_ENABLEALL,
											 text);
		delete[] text;
		m_enableall->setVisible(false);
	}
	{
		core::rect<s32> rect(0, 0, 85, 30);
		rect = rect + v2s32(115, 25) + topleft;
		wchar_t* text = wgettext("Disable All");
		m_disableall = Environment->addButton(rect, this, GUI_ID_DISABLEALL, text );
		delete[] text;
		m_disableall->setVisible(false);
	}
	{
		core::rect<s32> rect(0, 0, 200, 20);
		rect += v2s32(0, 60) + topleft;
		wchar_t* text = wgettext("depends on:");
		Environment->addStaticText(text, rect, false, false, this, -1);
		delete[] text;
	}
	{
		core::rect<s32> rect(0, 0, 200, 85);
		rect += v2s32(0, 80) + topleft;
		m_dependencies_listbox = 
			Environment->addListBox(rect, this, GUI_ID_DEPENDS_LISTBOX, true);
	}
	{
		core::rect<s32> rect(0, 0, 200, 20);
		rect += v2s32(0, 175) + topleft;
		wchar_t* text = wgettext("is required by:");
		Environment->addStaticText( text, rect, false, false, this, -1);
		delete[] text;
	}
	{
		core::rect<s32> rect(0, 0, 200, 85);
		rect += v2s32(0, 195) + topleft;
		m_rdependencies_listbox = 
			Environment->addListBox(rect,this, GUI_ID_RDEPENDS_LISTBOX,true);
	}
	{
		core::rect<s32> rect(0, 0, 340, 250);
		rect += v2s32(220, 0) + topleft;
		m_treeview = Environment->addTreeView(rect, this,
											  GUI_ID_MOD_TREEVIEW,true);
		gui::IGUITreeViewNode* node 
			= m_treeview->getRoot()->addChildBack(L"Add-Ons");
		buildTreeView(m_addontree, node);
	}
	{
		core::rect<s32> rect(0, 0, 120, 30);
		rect = rect + v2s32(330, 270) - topleft;
		wchar_t* text = wgettext("Cancel");
		Environment->addButton(rect, this, GUI_ID_CANCEL, text);
		delete[] text;
	}
	{
		core::rect<s32> rect(0, 0, 120, 30);
		rect = rect + v2s32(460, 270) - topleft;
		wchar_t* text = wgettext("Save");
		Environment->addButton(rect, this, GUI_ID_SAVE, text);
		delete[] text;
	}
	changeCtype("C");

	// at start, none of the treeview nodes is selected, so we select
	// the first element in the treeview of mods manually here.
	if(m_treeview->getRoot()->hasChilds())
	{
		m_treeview->getRoot()->getFirstChild()->setExpanded(true);
		m_treeview->getRoot()->getFirstChild()->setSelected(true);
		// Because a manual ->setSelected() doesn't cause an event, we
		// have to do this here:
		adjustSidebar();
	}
}

bool GUIConfigureWorld::OnEvent(const SEvent& event)
{

	gui::IGUITreeViewNode* selected_node = NULL;
	if(m_treeview != NULL)
		selected_node = m_treeview->getSelected();

	if(event.EventType==EET_KEY_INPUT_EVENT && event.KeyInput.PressedDown)
	{
		switch (event.KeyInput.Key) {
		case KEY_ESCAPE: {
			quitMenu();
			return true;
		}
		//	irrlicht's built-in TreeView gui has no keyboard control,
		//	so we do it here: up/down to select prev/next node,
		//	left/right to collapse/expand nodes, space to toggle
		//	enabled/disabled.
		case KEY_DOWN: {
			if(selected_node != NULL)
			{
				gui::IGUITreeViewNode* node = selected_node->getNextVisible();
				if(node != NULL)
				{
					node->setSelected(true);
					adjustSidebar();
				}
			}
			return true;
		}
		case KEY_UP: {
			if(selected_node != NULL)
			{
				gui::IGUITreeViewNode* node = selected_node->getPrevSibling();
				if(node!=NULL)
				{
					node->setSelected(true);
					adjustSidebar();
				}
				else 
				{
					gui::IGUITreeViewNode* parent = selected_node->getParent();
					if(selected_node == parent->getFirstChild() &&
					   parent != m_treeview->getRoot()) 
					{
						parent->setSelected(true);
						adjustSidebar();
					}
				}
			}
			return true;
		}
		case KEY_RIGHT: {
			if(selected_node != NULL && selected_node->hasChilds())
				selected_node->setExpanded(true);
			return true;
		}
		case KEY_LEFT: {
			if(selected_node != NULL && selected_node->hasChilds())
				selected_node->setExpanded(false);
			return true;
		}
		case KEY_SPACE: {
			if(selected_node != NULL && !selected_node->hasChilds() && 
			   selected_node->getText() != NULL)
			{
				std::string modname = wide_to_narrow(selected_node->getText());
				bool checked = m_enabled_checkbox->isChecked();
				m_enabled_checkbox->setChecked(!checked);
				setEnabled(modname,!checked);
			}
			return true;
		}
		default: {}
		}
	}
	if(event.EventType==EET_GUI_EVENT)
	{
		if(event.GUIEvent.EventType==gui::EGET_ELEMENT_FOCUS_LOST
				&& isVisible())
		{
			if(!canTakeFocus(event.GUIEvent.Element))
			{
				dstream<<"GUIConfigureWorld: Not allowing focus change."
						<<std::endl;
				// Returning true disables focus change
				return true;
			}
		}
		if(event.GUIEvent.EventType==gui::EGET_BUTTON_CLICKED){
			switch(event.GUIEvent.Caller->getID()){
			case GUI_ID_CANCEL: {
				quitMenu();
				return true;
			}
			case GUI_ID_SAVE: {
				for(std::set<std::string>::iterator it = m_new_mod_names.begin();
					it!= m_new_mod_names.end(); ++it)
				{
					m_settings.setBool("load_mod_"+(*it),true);
				}
				std::string worldmtfile = m_wspec.path+DIR_DELIM+"world.mt";
				m_settings.updateConfigFile(worldmtfile.c_str());

				// The trailing spaces are because there seems to be a
				// bug in the text-size calculation. if the trailing
				// spaces are removed from the message text, the
				// message gets wrapped and parts of it are cut off:
				wchar_t* text = wgettext("Configuration saved.  ");
				GUIMessageMenu *menu = 
					new GUIMessageMenu(Environment, Parent, -1, m_menumgr, 
									 text );
				delete[] text;
				menu->drop();

				ModConfiguration modconf(m_wspec.path);
				if(!modconf.isConsistent())
				{
					wchar_t* text = wgettext("Warning: Configuration not consistent.  ");
					GUIMessageMenu *menu =
						new GUIMessageMenu(Environment, Parent, -1, m_menumgr, 
										 text );
					delete[] text;
					menu->drop();
				}

				quitMenu();	
				return true;
			}
			case GUI_ID_ENABLEALL: {
				if(selected_node != NULL && selected_node->getParent() == m_treeview->getRoot())
				{  
					enableAllMods(m_addonmods,true);
				} 
				else if(selected_node != NULL && selected_node->getText() != NULL)
				{  
					std::string modname = wide_to_narrow(selected_node->getText());
					std::map<std::string, ModSpec>::iterator mod_it = m_addonmods.find(modname);
					if(mod_it != m_addonmods.end())
						enableAllMods(mod_it->second.modpack_content,true);
				}
				return true;
			}
			case GUI_ID_DISABLEALL: {
				if(selected_node != NULL && selected_node->getParent() == m_treeview->getRoot())
				{
					enableAllMods(m_addonmods,false);
				} 
				if(selected_node != NULL && selected_node->getText() != NULL)
				{
					std::string modname = wide_to_narrow(selected_node->getText());
					std::map<std::string, ModSpec>::iterator mod_it = m_addonmods.find(modname);
					if(mod_it != m_addonmods.end())
						enableAllMods(mod_it->second.modpack_content,false);
				}
				return true;
			}
			}
		}	
		if(event.GUIEvent.EventType==gui::EGET_CHECKBOX_CHANGED &&
			event.GUIEvent.Caller->getID() == GUI_ID_ENABLED_CHECKBOX)
		{
			if(selected_node != NULL && !selected_node->hasChilds() && 
			   selected_node->getText() != NULL)
			{
				std::string modname = wide_to_narrow(selected_node->getText());
				setEnabled(modname, m_enabled_checkbox->isChecked());
			}
			return true;
		}
		if(event.GUIEvent.EventType==gui::EGET_TREEVIEW_NODE_SELECT &&
		   event.GUIEvent.Caller->getID() == GUI_ID_MOD_TREEVIEW)
		{
			selecting_dep = -1;
			selecting_rdep = -1;
			adjustSidebar();
			return true;
		}
		if(event.GUIEvent.EventType==gui::EGET_LISTBOX_CHANGED &&
		   event.GUIEvent.Caller->getID() == GUI_ID_DEPENDS_LISTBOX)
		{
			selecting_dep = m_dependencies_listbox->getSelected();
			selecting_rdep = -1;
			return true;
		}
		if(event.GUIEvent.EventType==gui::EGET_LISTBOX_CHANGED &&
		   event.GUIEvent.Caller->getID() == GUI_ID_RDEPENDS_LISTBOX)
		{
			selecting_dep = -1;
			selecting_rdep = m_rdependencies_listbox->getSelected();
			return true;
		}

		//double click in a dependency listbox: find corresponding
		//treeviewnode and select it:
		if(event.GUIEvent.EventType==gui::EGET_LISTBOX_SELECTED_AGAIN)
		{
			gui::IGUIListBox* box = NULL;
			if(event.GUIEvent.Caller->getID() == GUI_ID_DEPENDS_LISTBOX)
			{
				box = m_dependencies_listbox;
				if(box->getSelected() != selecting_dep)
					return true;
			}
			if(event.GUIEvent.Caller->getID() == GUI_ID_RDEPENDS_LISTBOX)
			{
				box = m_rdependencies_listbox;
				if(box->getSelected() != selecting_rdep)
					return true;
			}
			if(box != NULL && box->getSelected() != -1 &&
			   box->getListItem(box->getSelected()) != NULL)
			{
				std::string modname = 
					wide_to_narrow(box->getListItem(box->getSelected()));
				std::map<std::string, gui::IGUITreeViewNode*>::iterator it =
					m_nodes.find(modname);
				if(it != m_nodes.end())
				{
					// select node and make sure node is visible by
					// expanding all parents
					gui::IGUITreeViewNode* node = (*it).second;
					node->setSelected(true);
					while(!node->isVisible() && 
						  node->getParent() != m_treeview->getRoot())
					{
						node = node->getParent();
						node->setExpanded(true);
					}
					adjustSidebar();
				}
			}
			return true;
		}
	}

	return Parent ? Parent->OnEvent(event) : false;
}

void GUIConfigureWorld::buildTreeView(std::map<std::string, ModSpec> mods, 
									  gui::IGUITreeViewNode* node)
{
	for(std::map<std::string,ModSpec>::iterator it = mods.begin();
		it != mods.end(); ++it)    
	{
		std::string modname = (*it).first;
		ModSpec mod = (*it).second;
		gui::IGUITreeViewNode* new_node = 
			node->addChildBack(narrow_to_wide(modname).c_str());
		m_nodes.insert(std::make_pair(modname, new_node));
		if(mod.is_modpack)
			buildTreeView(mod.modpack_content, new_node);
		else
		{
			// set icon for node: ? for new mods, x for disabled mods,
			// checkmark for enabled mods
			if(m_new_mod_names.count(modname) > 0)
			{
				new_node->setIcon(QUESTIONMARK_STR);
			}
			else
			{
				bool mod_enabled = true;
				if(m_settings.exists("load_mod_"+modname))
					mod_enabled = m_settings.getBool("load_mod_"+modname);
				if(mod_enabled)
					new_node->setIcon(CHECKMARK_STR);
				else 
					new_node->setIcon(CROSS_STR);
			}
		}
	}
}


void GUIConfigureWorld::adjustSidebar()
{
	gui::IGUITreeViewNode* node = m_treeview->getSelected();
	std::wstring modname_w;
	if(node->getText() != NULL)
		modname_w = node->getText();
	else 
		modname_w = L"N/A";
	std::string modname = wide_to_narrow(modname_w);

	ModSpec mspec;
	std::map<std::string, ModSpec>::iterator it = m_addonmods.find(modname);
	if(it != m_addonmods.end())
		mspec = it->second;

	m_dependencies_listbox->clear();
	m_rdependencies_listbox->clear();

	// if no mods installed, there is nothing to enable/disable, so we
	// don't show buttons or checkbox on the sidebar
	if(node->getParent() == m_treeview->getRoot() && !node->hasChilds())
	{
		m_disableall->setVisible(false);
		m_enableall->setVisible(false);
		m_enabled_checkbox->setVisible(false);
		return;
	} 
	
    // a modpack is not enabled/disabled by itself, only its cotnents
    // are. so we show show enable/disable all buttons, but hide the
    // checkbox
	if(node->getParent() == m_treeview->getRoot() ||
	   mspec.is_modpack)
	{
		m_enabled_checkbox->setVisible(false);
		m_disableall->setVisible(true);
		m_enableall->setVisible(true);
		m_modname_text->setText((L"Modpack: "+modname_w).c_str());
		return;
	}	

	// for a normal mod, we hide the enable/disable all buttons, but show the checkbox.
	m_disableall->setVisible(false);
	m_enableall->setVisible(false);
	m_enabled_checkbox->setVisible(true);
	m_modname_text->setText((L"Mod: "+modname_w).c_str());

	// the mod is enabled unless it is disabled in the world.mt settings. 
	bool mod_enabled = true;
	if(m_settings.exists("load_mod_"+modname))
		mod_enabled = m_settings.getBool("load_mod_"+modname);
	m_enabled_checkbox->setChecked(mod_enabled);

	for(std::set<std::string>::iterator it=mspec.depends.begin();
		it != mspec.depends.end(); ++it)
	{
		// check if it is an add-on mod or a game/world mod. We only
		// want to show add-ons
		std::string dependency = (*it);
		if(m_gamemods.count(dependency) > 0)
			dependency += " (" + m_gspec.id + ")";
		else if(m_worldmods.count(dependency) > 0)
			dependency += " (" + m_wspec.name + ")";
		else if(m_addonmods.count(dependency) == 0)
			dependency += " (missing)";
		m_dependencies_listbox->addItem(narrow_to_wide(dependency).c_str());
	}

	// reverse dependencies of this mod:
	std::pair< std::multimap<std::string, std::string>::iterator, 
			std::multimap<std::string, std::string>::iterator > rdep = 
		m_reverse_depends.equal_range(modname);
	for(std::multimap<std::string,std::string>::iterator it = rdep.first;
		it != rdep.second; ++it)
	{
		// check if it is an add-on mod or a game/world mod. We only
		// want to show add-ons
		std::string rdependency = (*it).second;
		if(m_addonmods.count(rdependency) > 0)
			m_rdependencies_listbox->addItem(narrow_to_wide(rdependency).c_str());
	}
}

void GUIConfigureWorld::enableAllMods(std::map<std::string, ModSpec> mods,bool enable)
{
	for(std::map<std::string, ModSpec>::iterator it = mods.begin();
		it != mods.end(); ++it)
	{
		ModSpec mod = (*it).second;
		if(mod.is_modpack) 
			// a modpack, recursively enable all mods in it
			enableAllMods(mod.modpack_content,enable);
		else // not a modpack
			setEnabled(mod.name, enable);

	}
}

void GUIConfigureWorld::enableMod(std::string modname)
{
	std::map<std::string, ModSpec>::iterator mod_it = m_addonmods.find(modname);
	if(mod_it == m_addonmods.end()){
		errorstream << "enableMod() called with invalid mod name \"" << modname << "\"" << std::endl;
		return;
	}
	ModSpec mspec = mod_it->second;
	m_settings.setBool("load_mod_"+modname,true);
	std::map<std::string,gui::IGUITreeViewNode*>::iterator it = 
		m_nodes.find(modname);
	if(it != m_nodes.end())
		(*it).second->setIcon(CHECKMARK_STR);
	m_new_mod_names.erase(modname);
	//also enable all dependencies