/* ExternalEditManager::monitorStopped
 * Called when a FileMonitor is stopped/deleted
 *******************************************************************/
void ExternalEditManager::monitorStopped(ExternalEditFileMonitor* monitor)
{
	if (VECTOR_EXISTS(file_monitors, monitor))
		VECTOR_REMOVE(file_monitors, monitor);
}
/* MapObjectPropsPanel::openObject
 * Populates the grid with properties for all MapObjects in [objects]
 *******************************************************************/
void MapObjectPropsPanel::openObjects(vector<MapObject*>& objects)
{
	// Check any objects were given
	if (objects.size() == 0 || objects[0] == NULL)
	{
		this->objects.clear();
		pg_properties->DisableProperty(pg_properties->GetGrid()->GetRoot());
		pg_properties->SetPropertyValueUnspecified(pg_properties->GetGrid()->GetRoot());
		pg_properties->Refresh();
		pg_props_side1->DisableProperty(pg_props_side1->GetGrid()->GetRoot());
		pg_props_side1->SetPropertyValueUnspecified(pg_props_side1->GetGrid()->GetRoot());
		pg_props_side1->Refresh();
		pg_props_side2->DisableProperty(pg_props_side2->GetGrid()->GetRoot());
		pg_props_side2->SetPropertyValueUnspecified(pg_props_side2->GetGrid()->GetRoot());
		pg_props_side2->Refresh();

		return;
	}
	else
		pg_properties->EnableProperty(pg_properties->GetGrid()->GetRoot());

	// Setup property grid for the object type
	if (theMapEditor->currentMapDesc().format == MAP_UDMF)
		setupTypeUDMF(objects[0]->getObjType());
	else
		setupType(objects[0]->getObjType());

	// Find any custom properties (UDMF only)
	if (theMapEditor->currentMapDesc().format == MAP_UDMF)
	{
		for (unsigned a = 0; a < objects.size(); a++)
		{
			// Go through object properties
			vector<MobjPropertyList::prop_t> objprops = objects[a]->props().allProperties();
			for (unsigned b = 0; b < objprops.size(); b++)
			{
				// Ignore side property
				if (objprops[b].name.StartsWith("side1.") || objprops[b].name.StartsWith("side2."))
					continue;

				// Check if hidden
				if (VECTOR_EXISTS(hide_props, objprops[b].name))
					continue;

				// Check if property is already on the list
				bool exists = false;
				for (unsigned c = 0; c < properties.size(); c++)
				{
					if (properties[c]->getPropName() == objprops[b].name)
					{
						exists = true;
						break;
					}
				}

				if (!exists)
				{
					// Create custom group if needed
					if (!group_custom)
						group_custom = pg_properties->Append(new wxPropertyCategory("Custom"));

					//LOG_MESSAGE(2, "Add custom property \"%s\"", objprops[b].name);

					// Add property
					switch (objprops[b].value.getType())
					{
					case PROP_BOOL:
						addBoolProperty(group_custom, objprops[b].name, objprops[b].name); break;
					case PROP_INT:
						addIntProperty(group_custom, objprops[b].name, objprops[b].name); break;
					case PROP_FLOAT:
						addFloatProperty(group_custom, objprops[b].name, objprops[b].name); break;
					default:
						addStringProperty(group_custom, objprops[b].name, objprops[b].name); break;
					}
				}
			}
		}
	}

	// Generic properties
	for (unsigned a = 0; a < properties.size(); a++)
		properties[a]->openObjects(objects);

	// Handle line sides
	if (objects[0]->getObjType() == MOBJ_LINE)
	{
		// Enable/disable side properties
		wxPGProperty* prop = pg_properties->GetProperty("sidefront");
		if (prop && (prop->IsValueUnspecified() || prop->GetValue().GetInteger() >= 0))
			pg_props_side1->EnableProperty(pg_props_side1->GetGrid()->GetRoot());
		else
		{
			pg_props_side1->DisableProperty(pg_props_side1->GetGrid()->GetRoot());
			pg_props_side1->SetPropertyValueUnspecified(pg_props_side1->GetGrid()->GetRoot());
		}
		prop = pg_properties->GetProperty("sideback");
		if (prop && (prop->IsValueUnspecified() || prop->GetValue().GetInteger() >= 0))
			pg_props_side2->EnableProperty(pg_props_side2->GetGrid()->GetRoot());
		else
		{
			pg_props_side2->DisableProperty(pg_props_side2->GetGrid()->GetRoot());
			pg_props_side2->SetPropertyValueUnspecified(pg_props_side2->GetGrid()->GetRoot());
		}
	}

	// Update internal objects list
	if (&objects != &this->objects)
	{
		this->objects.clear();
		for (unsigned a = 0; a < objects.size(); a++)
			this->objects.push_back(objects[a]);
	}

	// Possibly update the argument names and visibility
	updateArgs(NULL);

	pg_properties->Refresh();
	pg_props_side1->Refresh();
	pg_props_side2->Refresh();
}
Exemple #3
0
/* WadArchive::open
 * Reads wad format data from a MemChunk
 * Returns true if successful, false otherwise
 *******************************************************************/
bool WadArchive::open(MemChunk& mc)
{
	// Check data was given
	if (!mc.hasData())
		return false;

	// Read wad header
	uint32_t	num_lumps = 0;
	uint32_t	dir_offset = 0;
	char		wad_type[4] = "";
	mc.seek(0, SEEK_SET);
	mc.read(&wad_type, 4);		// Wad type
	mc.read(&num_lumps, 4);		// No. of lumps in wad
	mc.read(&dir_offset, 4);	// Offset to directory

	// Byteswap values for big endian if needed
	num_lumps = wxINT32_SWAP_ON_BE(num_lumps);
	dir_offset = wxINT32_SWAP_ON_BE(dir_offset);

	// Check the header
	if (wad_type[1] != 'W' || wad_type[2] != 'A' || wad_type[3] != 'D')
	{
		wxLogMessage("WadArchive::openFile: File %s has invalid header", filename);
		Global::error = "Invalid wad header";
		return false;
	}

	// Check for iwad
	if (wad_type[0] == 'I')
		iwad = true;

	// Stop announcements (don't want to be announcing modification due to entries being added etc)
	setMuted(true);

	vector<uint32_t> offsets;

	// Read the directory
	mc.seek(dir_offset, SEEK_SET);
	theSplashWindow->setProgressMessage("Reading wad archive data");
	for (uint32_t d = 0; d < num_lumps; d++)
	{
		// Update splash window progress
		theSplashWindow->setProgress(((float)d / (float)num_lumps));

		// Read lump info
		char name[9] = "";
		uint32_t offset = 0;
		uint32_t size = 0;

		mc.read(&offset, 4);	// Offset
		mc.read(&size, 4);		// Size
		mc.read(name, 8);		// Name
		name[8] = '\0';

		// Byteswap values for big endian if needed
		offset = wxINT32_SWAP_ON_BE(offset);
		size = wxINT32_SWAP_ON_BE(size);

		// Check to catch stupid shit
		if (size > 0)
		{
			if (offset == 0)
			{
				LOG_MESSAGE(2, "No.");
				continue;
			}
			if (VECTOR_EXISTS(offsets, offset))
			{
				LOG_MESSAGE(1, "Ignoring entry %d: %s, is a clone of a previous entry", d, name);
				continue;
			}
			offsets.push_back(offset);
		}

		// Hack to open Operation: Rheingold WAD files
		if (size == 0 && offset > mc.getSize())
			offset = 0;

		// Is there a compression/encryption thing going on?
		bool jaguarencrypt = !!(name[0] & 0x80);	// look at high bit
		name[0] = name[0] & 0x7F;					// then strip it away

		// Look for encryption shenanigans
		size_t actualsize = size;
		if (jaguarencrypt)
		{
			if (d < num_lumps - 1)
			{
				size_t pos = mc.currentPos();
				uint32_t nextoffset = 0;
				for (int i = 0; i + d < num_lumps; ++i)
				{
					mc.read(&nextoffset, 4);
					if (nextoffset != 0) break;
					mc.seek(12, SEEK_CUR);
				}
				nextoffset = wxINT32_SWAP_ON_BE(nextoffset);
				if (nextoffset == 0) nextoffset = dir_offset;
				mc.seek(pos, SEEK_SET);
				actualsize = nextoffset - offset;
			}
			else
			{
				if (offset > dir_offset)
				{
					actualsize = mc.getSize() - offset;
				}
				else
				{
					actualsize = dir_offset - offset;
				}
			}
		}

		// If the lump data goes past the end of the file,
		// the wadfile is invalid
		if (offset + actualsize > mc.getSize())
		{
			wxLogMessage("WadArchive::open: Wad archive is invalid or corrupt");
			Global::error = S_FMT("Archive is invalid and/or corrupt (lump %d: %s data goes past end of file)", d, name);
			setMuted(false);
			return false;
		}

		// Create & setup lump
		ArchiveEntry* nlump = new ArchiveEntry(wxString::FromAscii(name), size);
		nlump->setLoaded(false);
		nlump->exProp("Offset") = (int)offset;
		nlump->setState(0);

		if (jaguarencrypt)
		{
			nlump->setEncryption(ENC_JAGUAR);
			nlump->exProp("FullSize") = (int)size;
		}

		// Add to entry list
		getRoot()->addEntry(nlump);
	}

	// Detect namespaces (needs to be done before type detection as some types
	// rely on being within certain namespaces)
	updateNamespaces();

	// Detect all entry types
	MemChunk edata;
	theSplashWindow->setProgressMessage("Detecting entry types");
	for (size_t a = 0; a < numEntries(); a++)
	{
		// Update splash window progress
		theSplashWindow->setProgress((((float)a / (float)numEntries())));

		// Get entry
		ArchiveEntry* entry = getEntry(a);

		// Read entry data if it isn't zero-sized
		if (entry->getSize() > 0)
		{
			// Read the entry data
			mc.exportMemChunk(edata, getEntryOffset(entry), entry->getSize());
			if (entry->isEncrypted())
			{
				if (entry->exProps().propertyExists("FullSize")
				        && (unsigned)(int)(entry->exProp("FullSize")) >  entry->getSize())
					edata.reSize((int)(entry->exProp("FullSize")), true);
				if (!JaguarDecode(edata))
					wxLogMessage("%i: %s (following %s), did not decode properly", a, entry->getName(), a>0?getEntry(a-1)->getName():"nothing");
			}
			entry->importMemChunk(edata);
		}

		// Detect entry type
		EntryType::detectEntryType(entry);

		// Unload entry data if needed
		if (!archive_load_data)
			entry->unloadData();

		// Set entry to unchanged
		entry->setState(0);
	}

	// Identify #included lumps (DECORATE, GLDEFS, etc.)
	detectIncludes();

	// Detect maps (will detect map entry types)
	theSplashWindow->setProgressMessage("Detecting maps");
	detectMaps();

	// Setup variables
	setMuted(false);
	setModified(false);
	//if (iwad && iwad_lock) read_only = true;
	announce("opened");

	theSplashWindow->setProgressMessage("");

	return true;
}
/* MapObjectPropsPanel::setupTypeUDMF
 * Adds all relevant UDMF properties to the grid for [objtype]
 *******************************************************************/
void MapObjectPropsPanel::setupTypeUDMF(int objtype)
{
	// Nothing to do if it was already this type
	if (last_type == objtype)
		return;

	// Clear property grids
	clearGrid();

	// Hide buttons if not needed
	if (no_apply || mobj_props_auto_apply)
	{
		btn_apply->Show(false);
		btn_reset->Show(false);
	}
	else if (!no_apply)
	{
		btn_apply->Show();
		btn_reset->Show();
	}

	// Set main tab title
	if (objtype == MOBJ_VERTEX)
		stc_sections->SetPageText(0, "Vertex");
	else if (objtype == MOBJ_LINE)
		stc_sections->SetPageText(0, "Line");
	else if (objtype == MOBJ_SECTOR)
		stc_sections->SetPageText(0, "Sector");
	else if (objtype == MOBJ_THING)
		stc_sections->SetPageText(0, "Thing");

	// Go through all possible properties for this type
	vector<udmfp_t> props = theGameConfiguration->allUDMFProperties(objtype);
	sort(props.begin(), props.end());
	for (unsigned a = 0; a < props.size(); a++)
	{
		// Skip if hidden
		if ((hide_flags && props[a].property->isFlag()) ||
			(hide_triggers && props[a].property->isTrigger()))
		{
			hide_props.push_back(props[a].property->getProperty());
			continue;
		}
		if (VECTOR_EXISTS(hide_props, props[a].property->getProperty()))
			continue;

		addUDMFProperty(props[a].property, objtype);
	}

	// Add side properties if line type
	if (objtype == MOBJ_LINE)
	{
		// Add side tabs
		pg_props_side1->Show(true);
		pg_props_side2->Show(true);
		stc_sections->AddPage(pg_props_side1, "Front Side");
		stc_sections->AddPage(pg_props_side2, "Back Side");

		// Get side properties
		vector<udmfp_t> sprops = theGameConfiguration->allUDMFProperties(MOBJ_SIDE);
		sort(sprops.begin(), sprops.end());

		// Front side
		for (unsigned a = 0; a < sprops.size(); a++)
		{
			// Skip if hidden
			if ((hide_flags && sprops[a].property->isFlag()) ||
				(hide_triggers && sprops[a].property->isTrigger()))
			{
				hide_props.push_back(sprops[a].property->getProperty());
				continue;
			}
			if (VECTOR_EXISTS(hide_props, sprops[a].property->getProperty()))
				continue;

			addUDMFProperty(sprops[a].property, objtype, "side1", pg_props_side1);
		}

		// Back side
		for (unsigned a = 0; a < sprops.size(); a++)
		{
			// Skip if hidden
			if ((hide_flags && sprops[a].property->isFlag()) ||
				(hide_triggers && sprops[a].property->isTrigger()))
			{
				hide_props.push_back(sprops[a].property->getProperty());
				continue;
			}
			if (VECTOR_EXISTS(hide_props, sprops[a].property->getProperty()))
				continue;

			addUDMFProperty(sprops[a].property, objtype, "side2", pg_props_side2);
		}
	}

	// Set all bool properties to use checkboxes
	pg_properties->SetPropertyAttributeAll(wxPG_BOOL_USE_CHECKBOX, true);

	// Remember arg properties for passing to type/special properties (or set
	// to NULL if args don't exist)
	for (unsigned arg = 0; arg < 5; arg++)
		args[arg] = pg_properties->GetProperty(S_FMT("arg%u", arg));

	last_type = objtype;

	Layout();
}