UE4 Automatic Level Builder :: Construction and Pipeline Scripts

Very cool, people like you roxzor my boxzor :slight_smile:

If its okay with you, would you be able to PM me the pseudo-code for this script, so I can get to building a Maya version ASAP. Would be easier than trying to decipher maxscript, IMHO.

I wrote it in maxscript.
When I said:

I meant those who canā€™t open maxscript - I will simply paste it in a text editor and upload it (or paste it to a text field online).

I still need to make sure it works with ue4 plugin. I am going to most likely need to do tweaks to the output information and implement c++ outformat for data to be read right. Once I test it for bugs with ue4 I will send it.

@Luos - :cool:

amazing script!canā€™t wait to try it!
looks like very useful time saver.

In the pursuit of learning UE4 plugins, I see there isnā€™t too much information out yet. Due to the fact that I am having to learn how UE4 does certain things and accesses others, I will be releasing the maxscript so people can test it out now verses later. Over the next few hours I am going to be cleaning up one naming convention setting and creating a tutorial to go with it.

I should have it up before the day ends. :slight_smile:

Here is a temp download link :: http://www.jeremybaldwin3d.com/#!maxscript/c1mn9

@Crow (or anyone else not using max) - if you have any questions or need me to translate what is being done in specific parts just let me know.
Feel free to use it however you want (Or parts of it).

Oh wow, looks like we are currently investigating very similar things. This is great!

I just got my function to add actors in the level by specifying the asset working.
So, to add a StaticMesh or Blueprint the AssetPath would be something like ā€œ/Game/Props/SM_Chairā€
To add a PointLight, the AssetPath would be ā€œ/Script/Engine.PointLightā€



/**
 * Spawn a new Actor in the Level. Automatically find the type of Actor to create 
 * based on the type of Asset. 
 * 
 * @param AssetPath The full path to the asset "/Game/Meshes/MyStaticMesh"
 * @param InLevel The Level to add the Actor to
 * @param Name The Name to assign to the Actor (should be a valid FName) if NAME_None
 *             the engine will create a name based on the class
 * @param bSelectActor Select the Actor after it is created
 * @param Location Where to place the Actor
 *
 * @return The newly created Actor
 *
 * Inspired by the DragDrop functionality of the Viewports, see
 * LevelEditorViewport::AttemptDropObjAsActors and
 * SLevelViewport::HandlePlaceDraggedObjects
 */
	AActor* AddNewActorFromAsset( FString& AssetPath, 
								  ULevel* InLevel, 
								  const FName Name = NAME_None,
								  bool bSelectActor = true, 
								  const FVector& Location = FVector(0,0,0),
								  EObjectFlags ObjectFlags = RF_Transactional)
	{

		// If there is no dot, add a dot and repeat the object name.
		// /Game/Meshes/MyStaticMesh.MyStaticMesh would be the actual path
		// to the object, while the MyStaticMesh before the dot is the package
		// copied from ConstructorHelpers
		int32 PackageDelimPos = INDEX_NONE;
		AssetPath.FindChar( TCHAR('.'), PackageDelimPos );
		if( PackageDelimPos == INDEX_NONE )
		{
			int32 ObjectNameStart = INDEX_NONE;
			AssetPath.FindLastChar( TCHAR('/'), ObjectNameStart );
			if( ObjectNameStart != INDEX_NONE )
			{
				const FString ObjectName = AssetPath.Mid( ObjectNameStart+1 );
				AssetPath += TCHAR('.');
				AssetPath += ObjectName;
			}
		}


		// try to find the asset
		UE_LOG(LogM2U, Log, TEXT("Trying to find Asset %s."), *AssetPath);
		//UObject* Asset = FindObject<UObject>( ANY_PACKAGE, *AssetPath, false );
		UObject* Asset = StaticLoadObject(UObject::StaticClass(), NULL, *AssetPath);
		if( Asset == NULL)
		{
			// TODO: load full package, if Blueprint (see HandlePlaceDraggedObjects)
			UE_LOG(LogM2U, Log, TEXT("Failed to find Asset %s."), *AssetPath);
			return NULL;
		}
		UClass* AssetClass = Asset->GetClass();
		//UActorFactory* ActorFactory = GEditor->FindActorFactoryForActorClass( AssetClass );
		
		AActor* Actor = FActorFactoryAssetProxy::AddActorForAsset( Asset, &Location, false, bSelectActor, ObjectFlags, NULL, Name );
		// the Actor will sometimes receive the Name, but not if it is a blueprint?
		// it will never receive the name as Label, so we set the name explicitly 
		// again here.
		Actor->SetActorLabel(Name.ToString());
		
		return Actor;
	}// AActor* AddNewActorFromAsset()

for reference, I call it like this



		FString AssetName = FParse::Token(Str,0);
		const FString ActorName = FParse::Token(Str,0);
		auto World = GEditor->GetEditorWorldContext().World();
		ULevel* Level = World->GetCurrentLevel();

		FName ActorFName = m2uHelper::GetFreeName(ActorName);
		AActor* Actor = m2uHelper::AddNewActorFromAsset(AssetName, Level, ActorFName, false);

How do you plan to tell your Plugin to do stuff? Maybe the FSelfRegisteringExec would be a good start? By deriving your Plugin class from it you can add the Exec function and receive commands that the user types into the ā€œEnter Console Command hereā€ field in the Editor. Of course it is not as nice as providing a UI, but maybe it is a good start :slight_smile: I guess there are a few Infos on programming Slate UI out there, but I didnā€™t look into it yet :stuck_out_tongue:
example:


bool Fm2uPlugin::Exec( UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar )
{
	if( FParse::Command(&Cmd, TEXT("m2uSayHello")) )
	{
		UE_LOG(LogM2U, Log, TEXT("Received a command via Exec"));
		return true;
	}
	return false;
}

Btw. feel free to get my code from here: https://bitbucket.org/m2u/m2uue4plugin/src
You can use anything from it that helps.

I guess we now have to find out how to tell the Editor to import FBX files as Assets, at least that is what Iā€™m going to look into tomorrow :smiley:

Thx for posting your max script code, I still have to do similar stuff for maya, this might be helpful.

Letā€™s do this! :smiley:

this is so awesome!! I have a fairly complex scene built in max and was dreading the process of placing everything again in the ue4 editor. A lot of things in my scene have to fit together very closely and it can get out of control real easy. This is EXACTLY what I was wishing for!

Cant wait for this to be ready to use.
Thanks

@alfalfasprossen - No problem :smiley:
Thanks for posting your thoughts and code! I definitely need to look into it. When it comes to C++ I am comfortable enough to write small applications and programs. But I am very new to how it is implemented in UE4. It seems you have more experience than I do when it comes to coding in UE4, so please donā€™t hesitate to start writing a plugin for this! Collaboration would be fantastic.
If you would like to start looking into the UE4 implementation, I could work on getting collision, LODā€™s, blueprints, etc. created in 3DS Max. I will do UE4 stuff as well, but no sense in me doing something that will take 4 weeks when someone who is more comfortable can do it in 2 weeks (which then I could spend more time getting more things ready for export).

Let me know if that would be something you are interested in doing :stuck_out_tongue:

@anonymous_user_9c39f750 Punisher - Awesome! I canā€™t wait to hear feedback once you get a go at it :slight_smile:

In max I have recently decided to use containers for various reasons. Does your system have to ability to export closed containers as fbx files? If not will it work if I simply ā€œopenā€ all the containers in the container explorer and then run the script? If that wont work either, its no big deal, I can just unload all the containers then run it. Containers have proven to be a huge help to me so far, but Iā€™ll happily unload the containers rather than place several hundred (probably a couple thousand really) meshes by hand.

Hey Punisher,

If the containers are closed, then it may not work due to some operations being directly linked to modifying the geometry (example - batch rename).
If all of the containers are open then it shouldnā€™t be a problem.

Here is a simple bit that will loop through all container helpers and execute a command.



for x in helpers do
(
	if classof x == container then
	(
		print x.name -- instead of printing, you could do many other things such as open the container
	)
)


ok thanks.

I want this!

Really cool- Iā€™m working on a modular set right now and could use this.

Possible concern- say I have two pieces in MAX I assemble in configuration A. Now I take the same pieces and make configuration B.

Now I import into UE4 with your script starting with A. When I import B, will it duplicate the two models because they are identical- or create two more entries?

I hope that made sense.

TimeSpirit - I think I understand what you were saying. It should make two more entries :slight_smile:
This is the beauty of individual mesh files generated from every unique mesh and instance in 3ds max.

Hey Jeremy, as said, Iā€™m implementing functionality to automate the import and asset-placement process into my Plugin anyway. I guess the best solution would be if I implement a function that reads your file(s) and executes the appropriate commands then. So we donā€™t have to create yet-another-plugin, just to implement functionality that already exists :smiley:

I will now first implement the functionality for my maya script, after that it will only be a minor effort to do the file-parsing stuff. I will keep you posted.

Ah ok. I apologize, I must have not read the previous post correctly. That sounds great!
After you finish the maya work, let me know what you need the files to output in order to be read properly and I will change my script accordingly.

Canā€™t wait to see the maya version as well!

So if I understand it right you guys are both going to adjust your scripts(max and maya) to output the same format and then use a common method for importing into unreal. It sounds like this could also help people working in other DCC tools later on, since they would only have to figure out half of the process.

Looks promising. It your Youtube you show generation of the txt files , but how do you get all these text files into UE. Have you considered writing out a t3d file?

The text files were just a demonstration that the script successfully spits out information to some kind of external file. I am starting a new version of the script that is going to be working with alfalfasprossenā€™s UE4 plugin.

Here is his plugin for UE4. It is definitely worth taking the time to watch all videos and soak everything in :slight_smile: