Could be asleep, typing random messages instead.

BRUSHBUILDERS ARE SOME SERIOUSLY CRAZY DARK MAGIC FROM THE SEVENTH CIRCLE

For questions and discussion about UnrealEd, UnrealScript, and other aspects of Unreal Engine design.

Moderators: Semfry, ividyon

User avatar Buff Skeleton
>:E >:E
Posts: 4173
Joined: 15 Dec 2007, 00:46

Subject: BRUSHBUILDERS ARE SOME SERIOUSLY CRAZY DARK MAGIC FROM THE SEVENTH CIRCLE

Post Posted: 05 Feb 2013, 06:00

WHICH MEANS THEY ARE INCREDIBLE. YOU CAN DO ANYTHING WITH BRUSHBUILDERS! ANYTHING. YOU CAN PRETTY MUCH BE SUCCESSFUL IN LIFE FOREVER IF YOU LEARN HOW TO MAKE AND USE BRUSHBUILDERS. I'M GOING TO SHOW YOU HOW BECAUSE MY LATEST BRUSHBUILDER JUST SAVED ME TONS OF HOURS OF TIME SPENT DOING TEDIOUS HORRIBLE THINGS AND ALSO TURNED MY CAT INTO A POLITE YOUNG GENTLEMAN AND WON ME THREE DIFFERENT LOTTERIES. I'M NOT KIDDING. P.S. - NO CAPSLOCK, HOLDING DOWN SHIFT.

First of all, Brushbuilder is a class under Object, so open UED and uncheck "Actor classes only."

Ah ha! Now you should see Object >> Brushbuilder! Beneath this class, all your hopes and dreams are just waiting to come true.

Brushbuilders are basically your means of executing UnrealScript inside the editor. This means that if you know some UScript, you can write utility functions in a couple of seconds that can LITERALLY SAVE YOU HOURS IN THE EDITOR. This is especially useful if you have a really old map with a jillion things that need to be updated, but not deleted outright, and not ALL of those jillion things are necessary for removal or updating or what have you, but certain kinds are. I'll provide an example, and I'll link to the BBWaffleBox code that UArchitect wrote for me ages ago, but I never really used too much until somewhat recently. I've made some AWESOME quick batch operations with this thing.

Here's the full BBWaffleBox package: http://www.mediafire.com/download.php?rl6fmag0vnt2g9x

To install, extract everything to \UT\System\. There should be a Waffle icon, and that goes in \System\editorres\ if you didn't put it there already. Now open UnrealTournament.ini and add BBWaffleBox to your EditPackages list somewhere at the end. Open UED and you should see the icon! YOU'RE ON YOUR WAY TO GREATNESS!

Now go to Object >> Brushbuilder >> BBWaffleBox and edit the script!

If you already know how to make your own packages and just want to see the code UArch gave me initially to set up some serious brushbuildin', then look no further:
[spoiler]

Code: Select all

//=============================================================================
// BBWafflebox.
//=============================================================================
class BBWafflebox expands BrushBuilder;

var transient brush _bbrush; // builder brush
var transient levelinfo _level; // current levelinfo actor
var transient editorengine _eengine;
var transient camera _camera;
var transient object _input;

/////////////////////////////////////////////////////////////
// SET UP REQUIRED VARS
/////////////////////////////////////////////////////////////
function bool Setup() {
   local int i;

   _bbrush=none;
   _level=none;
   _eengine=none;
   _camera=none;
   _input=none;

   for(i=0; (i<100 && _level==none); i++)
      setpropertytext("_level","levelinfo'levelinfo"$i$"'");
   if(_level==none) return badparameters("failed to find levelinfo");
   else log(getclassname(self.class)$" found levelinfo: "$_level);

   for(i=0; (i<100 && _bbrush==none); i++)
      setpropertytext("_bbrush","brush'brush"$i$"'");
   if(_bbrush==none) return badparameters("failed to find builder brush");
   else log(getclassname(self.class)$" found builder brush: "$_bbrush);

   for(i=0; (i<100 && _eengine==none); i++)
      setpropertytext("_eengine","editorengine'editorengine"$i$"'");
   if(_eengine==none) return badparameters("failed to find editor engine");
   else log(getclassname(self.class)$" found editor engine: "$_eengine);

   return true;
}

// this function gets called when the builder brush button is clicked
event bool Build()
{
   Setup(); // set up initial vars and stuff for more advanced brushbuildin'

   Waffle();

   return BadParameters("YOUR FORGOT THE CODE YOU DUMPASS!");
}

/////////////////////////////////////////////////////////////
// PUT YOUR DAMN BROKEN ASS CODE HERE
/////////////////////////////////////////////////////////////
function Waffle()
{
/*   // BEST BRUSHBUILDER YET
   local Candle C;
   local EXUFlare E;

   foreach _level.Allactors(class'Candle', C)
   {
      if(C.DrawScale == 0.3)
      {
         E = _level.Spawn(Class'EXUFlare',,, c.location + vect(0,0,3.76) );
         if(E!=none)
         {
            E.Group = 'CandleClusterFlicker3';
            E.DrawScale = 0.15;
            E.Texture = Texture'GenFX.LensFlar.flare7';
            E.bFlickering = True;
            E.bFlickerDrawScale = True;
            E.DSMax = 0.15;
            E.DSMin = 0.125;
            E.SGMax = 1.0;
            E.SGMin = 0.75;
         }
      }
   }
*/
}


/////////////////////////////////////////////////////////////
// UTILITY FUNCTIONS
/////////////////////////////////////////////////////////////
function string GetClassName(class<object> c)
{
   local string s;
   if(c==none) return "";
   s = string(c);
   return right(s,instr(s,"."));
}

function string GetPackageName(class<object> c)
{
   local string s;
   if(c==none) return "";
   return string(c.outer);
}

static final function float acos (float a)
{
   if(a>1||a<-1) return 0;
   if(a==0) return pi/2;
   a = atan(sqrt(1.0-square(a))/a);
   if(a<0) a += pi;
   return a;
}

static final function float asin(float a)
{
   if(a>1||a<-1) return 0;
   if(a==1) return pi/2;
   if(a==-1) return -pi/2;
   return atan(a/sqrt(1-square(a)));
}
[/spoiler]

I honestly haven't the foggiest clue what those utility functions are for, but SOMEONE HERE PROBABLY DOES! THEY PROBABLY HOLD THE SECRET TO COLD FUSION OR SOMETHING! UARCHITECT IS A GENIUS AND CLEARLY HAS HARNESSED THE POWER OF BRUSHBUILDERS TO ENHANCE HIS LIFE IN WAYS MERE MORTALS CAN ONLY BEGIN TO COMPREHEND.

Note that in that code, I have included my example (which I just used tonight). I'll go into detail on that now, as well as a couple other examples.

In an EXU2 map, Highlands specifically for anyone familiar, I had tons, and I mean TONS, of candles. All over the map. Clumped together in threes, with one big candle, one medium candle, and one little candle. All the same "Candle" actor to boot. I had them grouped properly, so all the big candles were in a group and etc, and each candle also had a corona. I decided that I'd rather replace the corona lights with EXUFlare classes, which are much more flexible and able to be set up to look more like an actual flickering candle without being super bright at long range.

BUT HOW AM I SUPPOSED TO REPLACE OVER 180 CANDLES' WORTH OF FLARES WHEN THEY'RE ALL OVER THE MAP, DIFFERENTLY SIZED, AND NOT EVEN IN ALL THE SAME RELATIVE POSITIONS? Well, my friend, I'm glad you asked! BRUSHBUILDERS!

Let's go through this line-by-line:

Code: Select all

/////////////////////////////////////////////////////////////
// PUT YOUR DAMN BROKEN ASS CODE HERE
/////////////////////////////////////////////////////////////
function Waffle()
{
/*   // BEST BRUSHBUILDER YET
   local Candle C;
   local EXUFlare E;

   foreach _level.Allactors(class'Candle', C)
   {
      if(C.DrawScale == 0.3)
      {
         E = _level.Spawn(Class'EXUFlare',,, c.location + vect(0,0,3.76) );
         if(E!=none)
         {
            E.Group = 'CandleClusterFlicker3';
            E.DrawScale = 0.15;
            E.Texture = Texture'GenFX.LensFlar.flare7';
            E.bFlickering = True;
            E.bFlickerDrawScale = True;
            E.DSMax = 0.15;
            E.DSMin = 0.125;
            E.SGMax = 1.0;
            E.SGMin = 0.75;
         }
      }
   }
*/
}


local Candle C; allows me to iterate through all the actors in the level. Since UArch already set up _level for us in Setup(), we call _level.foreach(allactors). Since foreach(allactors) is a native function defined in Actor, not Object, we can't call just foreach(allactors) in an Object subclass. So we instead hook into the LevelInfo, an Actor, and reference that instead. Bam! We are now able to iterate through all the actors in the level FROM an object class, the brushbuilder! Are you amazed yet? You should be.

local EXUFlare E; sets me up for spawning an EXUFlare E at each Candle C I find in the level. But wait, surely you don't mean EVERY candle, right? They're all differently sized, and you can't just use one EXUFlare class to fit all three sizes for all 180+ candles! EXACTLY, MY FRIEND. EXACTLY. WE'VE GOT THIS COVERED.

foreach _level.allactors(class'Candle', C) as mentioned above, we're iteratin' now! Any candle that gets found will be stored and accessible as C.

if( C.DrawScale == 0.3 ) Heeeeere's where things get interesting! I have set up a condition to ONLY work with Candle actors that fit this specific parameter. Since it's extremely unlikely that any other Candle actors in the map that are set to DrawScale=0.03 will NOT be the kind I'm looking to modify, I leave it at this. But I could always append an && Group=='NameOfCandleGroup1' to be absolutely sure I ONLY get the Candle classes I want (since, like I said, they're all grouped. Use groups, people, they are absolutely indispensable for editing large groups of the same kind of actors all at once).

In this case, Candles that are 0.03 are the little ones, with bigger ones being 0.05 and the biggest being 0.075. That's mostly irrelevant, though, because what comes NEXT in the list is where I do the magic!

E = _level.Spawn(Class'EXUFlare',,, c.location + vect(0,0,3.76) ); allows me to spawn an EXUFlare EXACTLY where I want it, right at the base of the candle's flame, which is located ~3.76 units above the candle's local origin. I gathered this by subtracting Candle.Location.Z from EXUFlare.Location.Z from the first EXUFlare I placed in the level and configured as a test. (I also did two other test flares for the other two candle sizes, naturally.)

Now, if(E!=none), we set up E, the EXUFlare that just spawned at C.Location + 3.67 z-axis units! You can see I set the size, group, some booleans, and some floats to get it to look just like my test flare. That's basically it!

I compiled the code, then simply clicked the Waffle icon. Because I was too lazy to remove UArch's error message, I was berated for "forgetting the code" and, voila, ALL MY SMALL CANDLES HAD FLARES ON THEM TO REPLACE THE CORONAS. JUST. LIKE. THAT.

I edited the code to correspond to the other two sizes, adjusting the E.whatever variables as needed, then built again and a third time until ALL the Candle classes had an EXUFlare that was appropriate for its size. And since I assigned group labels, all my EXUFlare classes for each size are all mass-selectable via the Group menu so I can make further global changes without having to manually select each one!!! HOLY BALLS!!!!! TIMESAVINGS OUT THE ASS!


I also noticed I had a whole bunch of coronas on some other candles that were never grouped. There were tons of them, and since corona lights are naturally quite tiny, I really did not feel like manually selecting all of them. IN COMES THE BRUSHBUILDER!

Code: Select all

function Waffle()
{
   local Light L;

   foreach _level.Allactors(class'Light', L)
   {
      if( L.DrawScale == 0.025 && L.bCorona==True && L.Skin==Texture'GenFX.LensFlar.flare7' )
         L.Destroy(); // Wow! We killed those bastards! And not a single other light that shouldn't have been nuked!!
   }
}


Compile. Click. DONE. Coronas DESTROYED!

You can very easily make a Brushbuilder that converts actors into other actors as well. If you don't want to go through the .t3d method, you can basically get an actor class, spawn another actor at its same location and set its parameters as necessary, then destroy the original. Or something else like that! You can also do mass edits to actors, like when I had a billion EXUSpawnPoints with SpawnEffectClass set to UnrealShare.SpriteBallExplosion, an obsolete Effects class, I simply got every single EXUSpawnPoint in the level which used that as its SpawnEffectClass, then overrode it so SpawnEffectClass=Class'EXU.EXUOldSpriteBallExplosion'; and DONE! INSTANT CONVERSION OF HUNDREDS OF ACTORS. ONE CLICK. DONE. NO NONSENSE!!

If you don't know anything about UScript, well, great time to learn! But if you just have specific questions on how to make a quickie brushbuilder to do X, post your questions here! Wow! BRUSHBUILDERS ARE A SHINING BEACON OF HOPE IN THIS DARK WORLD WE INHABIT


Image A WORD OF WARNING: IF YOU DELETE ACTORS... Image

...be SURE you comment out the code in your brushbuilder that referenced the deleted class if you're going to remove it from your code package once you're done removing it from your level! Otherwise, if you save the brushbuilder's .u file with references to nonexistent classes, your brushbuilder won't work and it won't be editable anymore! That is the ultimate travesty. An uneditable, nonfunctional brushbuilder. Don't let it happen to you. Comment out your function code once you're done with it, then compile and save the package! Or don't save it at all if you're just doing a quickie one-off operation! Though it's always handy to keep records of what you did for future reference.

If you DO mess up like I did a few times, you just have to recreate the missing classes in the code package you edited, recompile it, then reload the brushbuilder package and comment out the code, save it, then re-delete the classes and recompile the code package so that the references are scrubbed. GOOD LUCK FRIENDS, MAY THE POWER OF BRUSHBUILDERS IMBUE YOUR LIVES WITH PROSPERITY AND JOY
Last edited by Buff Skeleton on 05 Feb 2013, 06:31, edited 4 times in total.
Image

Z-enzyme
White Tusk White Tusk
Posts: 2136
Joined: 13 Nov 2007, 20:01

Subject: Re: BRUSHBUILDERS ARE SOME SERIOUSLY CRAZY DARK MAGIC FROM THE SEVENTH CIRCLE

Post Posted: 05 Feb 2013, 06:11

Oooooh, I see... I might consider looking into that later on.

Thanks Waff!

User avatar ebd
Trustee Member Trustee Member
Posts: 441
Joined: 05 Apr 2008, 19:08
Contact:

Subject: Re: BRUSHBUILDERS ARE SOME SERIOUSLY CRAZY DARK MAGIC FROM THE SEVENTH CIRCLE

Post Posted: 05 Feb 2013, 08:06

Unreal 227 also defines DrawEditorSelection(Canvas c) which is called every frame if bEditorSelectRender == true. It is a little clunkier for editor sorcery (Calling destroy() in DrawEditorSelection() after you are done with your wizardry usually does the trick) but it still provides tons of utility for showing an actor's properties at a glance by rendering onto the canvas (I assume this was its actual intended purpose).

UB_
Nali Priest Nali Priest
Posts: 7960
Joined: 11 Nov 2007, 21:00

Subject: Re: BRUSHBUILDERS ARE SOME SERIOUSLY CRAZY DARK MAGIC FROM THE SEVENTH CIRCLE

Post Posted: 05 Feb 2013, 13:53

Had the first experience with THE POWER OF BRUSHBUILDERS when I had to screw around with the EXUSpawnPoints spawneffects. Worked perfectly.
ImageImage

Z-enzyme
White Tusk White Tusk
Posts: 2136
Joined: 13 Nov 2007, 20:01

Subject: Re: BRUSHBUILDERS ARE SOME SERIOUSLY CRAZY DARK MAGIC FROM THE SEVENTH CIRCLE

Post Posted: 05 Feb 2013, 17:30

ebd wrote:Unreal 227 also defines DrawEditorSelection(Canvas c) which is called every frame if bEditorSelectRender == true. It is a little clunkier for editor sorcery (Calling destroy() in DrawEditorSelection() after you are done with your wizardry usually does the trick) but it still provides tons of utility for showing an actor's properties at a glance by rendering onto the canvas (I assume this was its actual intended purpose).

Yea, I used it in my Computer Panel - I would love to be able to turn it on in the Editor and not through UCC script import.

...

Wait, maybe I can make a button, brush builder that would enable that option at a selected actor? LOL...

User avatar TheIronKnuckle
Gilded Claw Gilded Claw
Posts: 1967
Joined: 12 Nov 2007, 07:21
Location: Riding my bicycle from the highest hill in Sydney to these forums

Subject: Re: BRUSHBUILDERS ARE SOME SERIOUSLY CRAZY DARK MAGIC FROM THE SEVENTH CIRCLE

Post Posted: 05 Feb 2013, 21:14

haha sick as. and worded so eloquently as always! :lol:
ImageIgnorance is knowing anything
And only idiots know everything

User avatar Buff Skeleton
>:E >:E
Posts: 4173
Joined: 15 Dec 2007, 00:46

Subject: Re: BRUSHBUILDERS ARE SOME SERIOUSLY CRAZY DARK MAGIC FROM THE SEVENTH CIRCLE

Post Posted: 06 Mar 2013, 16:01

Also, in case anyone was wondering (like I was), creating a brushbuilder that only deals with selected actors is actually way simpler than you'd think. Actor.bSelected is flagged True every time you select something in the editor, so if you want to perform some operation on selected actors, just check a.bSelected. You can easily do !a.bSelected if you want to invert the process and do it only on unselected actors.

You can also work with bHiddenEd the same way to work only on visible actors (or only hidden ones if you like to live on the edge).
Image

User avatar Dr.Flay
Skaarj Lord Skaarj Lord
Posts: 222
Joined: 23 Aug 2012, 06:24
Location: Kernow, UK
Contact:

Subject: BRUSHBUILDERS ARE SOME SERIOUSLY CRAZY DARK MAGIC FROM THE SEVENTH CIRCLE

Post Posted: 02 Apr 2013, 10:33



Who is online

Users browsing this forum: No registered users and 39 guests

Copyright © 2001-2024 UnrealSP.org

Powered by phpBB® Forum Software © phpBB Limited