Plug-in dev help - getting values crashes editor

I’ve been trying to build this plug-in where we we can export the values of a texture as a preset so we can apply it back onto new textures. When I click the button to save out the preset, the editor crashes. I’ve remarked out everything but getting the first variable, so either I’m doing something wrong with the button or getting the values. Any suggestions what I could be doing wrong would be greatly appreciated

//adding button
	vertBox->AddSlot()
		.AutoHeight()
		[
			SNew(SHorizontalBox)
			+ SHorizontalBox::Slot()
			.VAlign(VAlign_Center)
			[
				SNew(STextBlock).Text(LOCTEXT("NewPreset", "New Preset"))
			]


			+ SHorizontalBox::Slot()
			.VAlign(VAlign_Center)
			[
				SNew(SEditableText)
				.Text(NSLOCTEXT("New Preset Name", "EnterText", "Enter text here..."))
				.OnTextCommitted(this, &TexturePresetUI::OnTextCommitted)
			]

			+ SHorizontalBox::Slot()
			.VAlign(VAlign_Center)
			[
				SNew(SButton)
				.Text(FString(TEXT("Save")))
				.OnClicked(this, &TexturePresetUI::SaveNewPreset)
			]
		];

Here’s my save new preset function:

FReply TexturePresetUI::SaveNewPreset()
{
	//get the texture
	FAssetEditorManager::Get().OnAssetEditorOpened().AddRaw(this, &WMD_TexturePresetUI::HandleAssetEditorOpened);

	//get the texture attributes
	float brightness						= _texture->AdjustBrightness;
	float brightnessCurve					= _texture->AdjustBrightnessCurve;
	float adjustHue						= _texture->AdjustHue;
	float adjustMaxAlpha					= _texture->AdjustMaxAlpha;
	float adjustMinAlpha					= _texture->AdjustMinAlpha;
	float adjustRGBCurve					= _texture->AdjustRGBCurve;
	float adjustSautration					= _texture->AdjustSaturation;
	float adjustVibrance					= _texture->AdjustVibrance;
	bool  chromaKeyTexture				= _texture->bChromaKeyTexture;
	uint32 ditherMipMapAlpha				= _texture->bDitherMipMapAlpha;
	uint32 flipGreenChannel				= _texture->bFlipGreenChannel;
	uint32 forcePVRTC4					= _texture->bForcePVRTC4;
	uint32 noTiling						= _texture->bNoTiling;
	uint32 preserveBorder					= _texture->bPreserveBorder;
	uint32 useCinematicMipLevels			= _texture->bUseCinematicMipLevels;
	uint32 useLegacyGamma				= _texture->bUseLegacyGamma;
	FColor chromaKeyColor				= _texture->ChromaKeyColor;
	float chromaKeyThreshold				= _texture->ChromaKeyThreshold;
	uint32 compressionNoAlpha			= _texture->CompressionNoAlpha;
	uint32 compressionNone				= _texture->CompressionNone;
	TEnumAsByte< enum TextureCompressionSettings >  compressionSettings = _texture->CompressionSettings;
	uint32 deferCompression				= _texture->DeferCompression;
	TEnumAsByte< enum TextureFilter >  filter	=  _texture->Filter;
	int32 lodBias						= _texture->LODBias;
	TEnumAsByte< enum TextureGroup >  lodGroup	= _texture->LODGroup;
	int32 maxTextureSize					= _texture->MaxTextureSize;
	TEnumAsByte< enum TextureMipGenSettings >  mipGenSettings			= _texture->MipGenSettings;
	uint32 neverStream					= _texture->NeverStream;
	int32 numCinematicMipLevels			= _texture->NumCinematicMipLevels;
	FColor paddingColor					= _texture->PaddingColor;
	TEnumAsByte< enum ETexturePowerOfTwoSetting::Type >  powerOfTwoMode = _texture->PowerOfTwoMode;
	uint32 srgb						= _texture->SRGB;

	//get output file name
	FFileManagerGeneric FileMgr;
	FileMgr.SetSandboxEnabled(true);// don't ask why, I don't know :P
	FString extension("preset"); // May be "" (empty string) to search all files
	FString outputPath(FPaths::Combine(*FPaths::GamePluginsDir(), TEXT("WMD_TexturePreset/presets")));

	FString SaveText;

	SaveText = ("brightness = " + FString::SanitizeFloat(brightness) + "\n" +
				"brightnessCurve = " + FString::SanitizeFloat(brightnessCurve) + "\n" +
				"adjustHue = " + FString::SanitizeFloat(adjustHue) + "\n" +
				"adjustMaxAlpha = " + FString::SanitizeFloat(adjustMaxAlpha) + "\n" +
				"adjustMinAlpha = " + FString::SanitizeFloat(adjustMinAlpha) + "\n" +
				"adjustRGBCurve = " + FString::SanitizeFloat(adjustRGBCurve) + "\n" +
				"adjustSautration = " + FString::SanitizeFloat(adjustSautration) + "\n" +
				"adjustVibrance = " + FString::SanitizeFloat(adjustVibrance) + "\n" +
				"chromaKeyTexture= " + (chromaKeyTexture ? "true" : "false") +"\n" +
				"ditherMipMapAlpha = " + FString::FromInt(ditherMipMapAlpha) + "\n" +
				"flipGreenChannel = " + FString::FromInt(flipGreenChannel) + "\n" +
				"forcePVRTC4 = " + FString::FromInt(forcePVRTC4) + "\n" +
				"noTiling = " + FString::FromInt(noTiling) + "\n" +
				"preserveBorder = " + FString::FromInt(preserveBorder) + "\n" +
				"useCinematicMipLevels = " + FString::FromInt(useCinematicMipLevels) + "\n" +
				"useLegacyGamma = " + FString::FromInt(useLegacyGamma) + "\n" +
				"chromaKeyColor = " + chromaKeyColor.ToString() + "\n" +
				"chromaKeyThreshold = " + FString::SanitizeFloat(chromaKeyThreshold) + "\n" +
				"compressionNoAlpha = " + FString::FromInt(compressionNoAlpha) + "\n" +
				"compressionNone = " + FString::FromInt(compressionNone) + "\n" +
				"compressionSettings = " + compressionSettings.GetValue() + "\n" +
				"deferCompression = " + FString::FromInt(deferCompression) + "\n" +
				"filter = " + filter.GetValue() + "\n" +
				"lodBias = " + FString::FromInt(lodBias) + "\n" +
				"lodGroup= " + lodGroup.GetValue() + "\n" +
				"maxTextureSize = " + FString::FromInt(maxTextureSize) + "\n" +
				"mipGenSettings	= " + mipGenSettings.GetValue() + "\n" +
				"neverStream = " + FString::FromInt(neverStream) + "\n" +
				"numCinematicMipLevels = " + FString::FromInt(numCinematicMipLevels) + "\n" +
				"paddingColor = " + paddingColor.ToString() + "\n" +
				"powerOfTwoMode = " + powerOfTwoMode.GetValue() + "\n" +
				"srgb = " + FString::FromInt(srgb) + "\n"
				);

	FFileHelper::SaveStringToFile(SaveText, *outputPath);

	return FReply::Handled();
}

So on which line it crashes? Did you checked the logs? Where do you set _texture?

Near as I can tell, the moment I try to get the attribute.

_texture is a UTexture2D* I set with that function &WMD_TexturePresetUI::HandleAssetEditorOpened. That looks like this:

void WMD_TexturePresetUI::HandleAssetEditorOpened(UObject* AssetObject)
{
	if (AssetObject->GetClass()->IsChildOf(UTexture2D::StaticClass()))
	{
		if (AssetObject != NULL)
			_texture = Cast<UTexture2D>(AssetObject);
			

	}
}

Actually, as a test I remarked out everything but the function call that should be setting _texture, and it crashes about the second or third time I call it, so that function appears to be unstable. Is there a safer way to get the active texture from the open texture settings window?

This is where I got the idea for getting the active texture from:

Here’s the first part of the crash log, if that helps. This is with everything but the call to HandleAssetEditorOpened remarked out. When I remark that out too, no crashes

Unknown exception - code 00000001 (first/second chance not available)

"Assertion failed: !DelegateInstanceInterface->IsSameFunction(*InDelegateInstance) [File:c:\program files\epic games\4.9\engine\source\runtime\core\public\delega

UE4Editor_Core!FDebug::AssertFailed() [d:\buildfarm\buildmachine_++depot+ue4-releases+4.9\engine\source\runtime\core\private\misc\outputdevice.cpp:354]
UE4Editor_WMD_TexturePreset!TBaseMulticastDelegate::AddDelegateInstance() [c:\program files\epic games\4.9\engine\source\runtime\core\public\delegates\delegatesignatureimpl_variadics.inl:775]
UE4Editor_WMD_TexturePreset!TBaseMulticastDelegate::AddRaw() [c:\program files\epic games\4.9\engine\source\runtime\core\public\delegates\delegatesignatureimpl_variadics.inl:589]
UE4Editor_WMD_TexturePreset!WMD_TexturePresetUI::SaveNewPreset() [c:\users\documents\unreal projects\wmd_pluginproject\plugins\wmd_texturepreset\source\wmd_texturepreset\private\wmd_texturepresetui.cpp:247]
UE4Editor_WMD_TexturePreset!TMemberFunctionCaller::operator()<>() [c:\program files\epic games\4.9\engine\source\runtime\core\public\delegates\delegateinstanceinterface_variadics.h:161]
UE4Editor_WMD_TexturePreset!TTupleImpl >::ApplyAfter_ExplicitReturnType >() [c:\program files\epic games\4.9\engine\source\runtime\core\public\delegates\tuple.h:113]
UE4Editor_WMD_TexturePreset!TBaseSPMethodDelegateInstance<0,WMD_TexturePresetUI,0,FReply __cdecl(void)>::Execute() [c:\program files\epic games\4.9\engine\source\runtime\core\public\delegates\delegateinstancesimpl_variadics.inl:282]

The crash is caused by assertation error and looking at it i think fault is you trying to bind same function that is already binded.

Assertation error may look cryptic at first but they are triggered by check() function , which has bool argument where you place condition. If it’s false it crashes the engine in controllable way, as because condition fail code can’t guaranty that it will be stable and may crash in uncontrollable way without leaving you any information, so it’s better to crash it now with some information. So as you can see if it fails it prints condition thats was inputed in check() function:

Assertion failed: !DelegateInstanceInterface->IsSameFunction(*InDelegateInstance) 

IsSameFunction returned true and check() stopped the engine. If you look on stack dump:

UE4Editor_WMD_TexturePreset!TBaseMulticastDelegate::AddRaw() [c:\program files\epic games\4.9\engine\source\runtime\core\public\delegates\delegatesignatureimpl_variadics.inl:589] UE4Editor_WMD_TexturePreset!WMD_TexturePresetUI::SaveNewPreset() [c:\users\\documents\unreal projects\wmd_pluginproject\plugins\wmd_texturepreset\source\wmd_texturepreset\private\wmd_texturepresetui.cpp:247

It happens when you call AddRaw so you can tie things up it happens because you binding “SameFunction” and you bind over and over again without any protection each time you call SaveNewPreset, so cause is somewhere here.

Everytime you have crash check the logs look on stack dump and search for error (it might also be above crash log)

That makes some sense, but I’ve tried moving that function call to the constructor or the construct function of my UI, and while id doesn’t crash it looks now like it’s never called. I added a check to see if _texture is NULL before before trying to get the values, and now it’s never being set. Is there a safer way to get the active texture than the FAssetEditorManager class function?

I’m still not getting this to work.

I started looking at the source code for the texture editor to see if I can just mimic what the engine code did. Looks like the UI code uses a pointer to a toolkit class.

// Pointer back to the Texture editor tool that owns us.
TWeakPtr<ITextureEditorToolkit> ToolkitPtr;

According to the code for the texture UI, the Construct looks like this:

void STextureEditorViewport::Construct( const FArguments& InArgs, const TSharedRef<ITextureEditorToolkit>& InToolkit )
{
	ExposureBias = 0;
	bIsRenderingEnabled = true;
	ToolkitPtr = InToolkit;
	. . . 

However when I try it, I get an error saying Construct doesn’t take one function and a conflict with DeclaritiveSyntaxSupport.h

Am I missing something, or am I heading down a wrong path?

Well, worked around that problem, and I’m back to crashing the editor. I got the call to FAssetEditorManager only to work from the module definition. I created a function which takes a pointer as a parameter so I can pass the pointer to the texture back to the UI code. But now we’re back to crashing.

UE4Editor_WMD_TexturePreset!WMD_TexturePresetUI::SaveNewPreset() [c:\users\documents\unreal projects\wmd_pluginproject\plugins\wmd_texturepreset\source\wmd_texturepreset\private\wmd_texturepresetui.cpp:170]
UE4Editor_WMD_TexturePreset!TMemberFunctionCaller::operator()<>() [c:\program files\epic games\4.9\engine\source\runtime\core\public\delegates\delegateinstanceinterface_variadics.h:161]
UE4Editor_WMD_TexturePreset!TTupleImpl >::ApplyAfter_ExplicitReturnType >() [c:\program files\epic games\4.9\engine\source\runtime\core\public\delegates\tuple.h:113]
UE4Editor_WMD_TexturePreset!TBaseSPMethodDelegateInstance<0,WMD_TexturePresetUI,0,FReply __cdecl(void)>::Execute() [c:\program files\epic games\4.9\engine\source\runtime\core\public\delegates\delegateinstancesimpl_variadics.inl:282]

Here’s from the .h

static void ReturnTextureNode(UTexture2D* txtrPtr);

static UTexture2D* texture;

Here’s the function call:

void WMD_TexturePresetModule::ReturnTextureNode(UTexture2D* txtrPtr)
{
	txtrPtr = texture;

}

the offending part of the code:

FReply WMD_TexturePresetUI::SaveNewPreset()
{
	WMD_TexturePresetModule::ReturnTextureNode(texture);

	if (texture != NULL)
	{
		UE_LOG(TestLog, Warning, TEXT("Gathering Texture Information"));

		//get the texture attributes
		float brightness = texture->AdjustBrightness;

K, I seem to have found an answer

Unreal didn’t like me passing the pointer to the texture back to the UI code, but I did it the other way around and that seems to be working. So my functions dealing with the texture are in the module with public static functions I call from the UI. Don’t know if that’s the best answer but it’s working and not crashing.