I love the smell of UnrealEd crashing in the morning. – tarquin

Legacy:CheshireCat/Developer Journal

From Unreal Wiki, The Unreal Engine Documentation Site
Jump to: navigation, search

I liked Reconn's reverse-chronological journal - I have, shall we say, "borrowed" the idea. Anyways, if anyone besides me actually reads this, umm, the current day is at the top. The events of each day are in forward chronological order (not reversed) - call it an experiment, I think this will write and read pretty easily for me. Generally a horizontal rule between paragraphs means that the second one was written some time later. I realize some other DJ pages do this as well, Reconn's just happens to be the first one I saw.


please use this area for comments :-)

Reconn: I'm guessing that when you say (for the bio-soaker) that the alt-fire will have a higher rate of fire, you meant higher as in greater, as in more distance between the shots, as in a slower rate of fire. Or do I not understand the gameplay mechanic you're using?

CheshireCat: Sorry if that was unclear... I meant faster. The primary fire is a tight stream for doing heavy damage to one target, the alternate is going to produce more slime, but will spread more and have shorter range.

current project: Bio-Soaker[edit]


I've just added some screenshots for the BioSoaker project: http://mywebpages.comcast.net/cheshirecat97/slime.html. I could really use some feedback on these, especially in the way of suggestions on fixing the visual effects of the first two. I think a particle emitter is probably the best way to fix this...


Scrapped the sprites, I'm now using the Bio-Rifle glob model with my own scripted behaviors. I'm still not satisfied with the way the projectiles look when fired, but they interact with the world beautifully. They stick to floors and walls and slowly spread out, and you get continuous damage while standing in them. Globs that are close enough together also merge so that there aren't quite so many meshes (it fires a LOT of slime). For some reason, the flying projectiles don't seem to be hurting players now, I will have to figure out what's wrong there. Need to fix that, tweak the parameters for the slime physics, tweak the ammo and rate of fire for best gameplay... and get some screenies up, the slime pools on the ground look nice :-)


Some more work on physics, and also on visual effects... the physics are pretty good, I'm not getting anywhere with visuals. They look very eh. I'll post some screenshots later...


Some projectile behavior tweaking, which will need testing - they should now bounce off of each other, and all bounces should have a slight random factor to them, so that spraying one spot will cause the shots to spread and form a puddle (hopefully).

Something is not quite right with the way projectiles bounce/splash - it looks beautiful off of walls, but as soon as they hit anything level enough, they land and stick there, even though their Landed() assigns them a new velocity and resets their physics to falling. Will have to dig around more to see how to implement this, don't really want to go Karma, since tons of Karma objects bumping each other will probably make most players' computers (definitely mine) melt. Also, doesn't Karma need me to use a mesh for my projectiles? That'd be a performance hit too...


Anyone here familiar with the "super soaker" style of pressurized water gun? Well, I'm working on a Bio-Rifle replacement that works sort of like that. Primary fire will fire projectiles rapidly, with rather low damage per projectile. Secondary fire will fire faster still, but will launch in a wider spread, making it a powerful short-range weapon, and capable of covering a wide area while retreating, but not very effective at long range. So far, primary fire is implemented (both fires use it now). The projectiles so far have very simple physics to let them bounce/splash off of walls, and are icky green sprites for now. Eventually, I'm planning to have a particle emitter triggered while firing, and the projectiles will either be invisible or use the same texture as the particles. The particles will hopefully provide a decent liquid effect, while the projectiles take care of actually dealing damage.

previous project: TacticalDisplay[edit]


TacticalDisplay is on hold, and in a state I would pretty much call finished for now :-)


Problems solved, it seems. I do one run over AllActors when the Interaction initializes, and make a list of the static Actors that are of interest. I also save the array length... then, to render a frame, I use DynamicActors to append relevant dynamic Actors to that array, and then use the same render loop I had before, looping through my array instead of DynamicActors. When I get time, I'll look to see which of the tricks I've had to work out aren't documented, and write up pages for them. Kinda think maybe there should be a "recipes" area, although some of the stuff under Open Source is kind of along those lines. Have some feature ideas, not sure where I'm going next... I'm thinking of working on a way to let people who join a server configure the mutator, maybe the interaction can catch a key and pop up the standard configuration. In any case, it would be a great feature for the mod on servers, where client may connect who don't use it already - they could configure their own colors before joining the game. Also thinking of allowing more advanced zoom control, where players could use a "tdzoom" command with a parameter to zoom to a specific multiplier, or to a specific range, or zoom in or out by a specific factor. I'd probably still use the keybinding system I have now for it, so there wouldn't be an actual console command, but that doesn't really matter ;-)


Hmm, this looks um, not good. There are a bunch of ways I could get CTF flag bases to be visible, but I don't like any of them. I could split rendering of each object out into a function, with whatever the performance cost of all those function calls would be, I can iterate over AllActors instead of DynamicActors, which will again not be great for performance... I'm thinking maybe the best idea is to scan AllActors once, find the bases, and spawn a special actor there to mark them.

Screw this. Every way I try to tackle this either looks ugly or makes me worry about performance. I don't think I can decide how best to do this until I've done some testing to determine which way will work acceptably. First shot will be timing AllActors vs. DynamicActors.

Thinking about using CollidingActors to pick up most of the things I need to detect. Comments in Actor.uc say CollidingActors is "much faster" for Actors in "reasonably small radii". Highest allowed MaxDetectRange for the mute is 16000, which probably isn't "reasonably small", so I'll need to test if this is indeed faster at these sizes. Bonus is it seems that it will find static or dynamic Actors as long as their bCollideActors==True. Of the objects I'm looking for, this will work for:

  • Pawn
  • Projectile
  • GreedCoinPickup
  • GreedDropPoint
  • xBombFlag
  • xBombDelivery (instead of dynamic xBombDeliveryHole I watched before)
  • xDomPoint (instead of dynamic DomLetter I watched before)
  • CTFBase

Hey, perfect - that's everything ;-) Catch is I need to know about players who have flags regardless of radius, I'll use the level pawnlist for this, I'll just make a list of carried flags before I do the CollidingActors loop. Looks like something like this can very easily fit into my current code - if this works I'll be quite happy. Ooooooh, Grand Funk on radio, can't code now ;-)

Hrm. Lists page says pawn list isn't visible serverside, so I'd need to use DynamicActors anyways for that. And that VisibleCollidingActors is slow for radius>900, so I'd imagine CollidingActors is as well. So maybe I'm back to the mess I had before...


First wider public release == first bug report. Apparently the display never goes away, even if you start another game without the mutator. Oops, never tried removing the mute, or I would have caught this one. Apparently none of my friends who test have removed it, either. Added NotifyLevelChange to remove the interaction. Also added support for Greed (show coins and drop points), DXT compressed textures, rewrote build scripts - there are now source-stripped binary packages, nice and small, and separate source packages. Between source stripping and DXT textures, the .u is down from ~300K to ~60K.

Fix works, Greed support works, time for bed now.

Optimizing (I hope) some of my tests. Mostly sorting all the type checks based on my guesses at the likelihood of finding such objects, and putting the range check at the very end, under the assumption (hopefully correct) that computing VSize costs more than all of those type checks. Working on BR Goal and Dom Point display, that and flag bases and I'll have support for pretty much every gametype I ever play ;-)


Well, I'm pretty sure that, if not buggy, the code I've just written will work. I'm not 100% sure on structs and arrays of structs in UScript, so it's slightly iffy ;-) It compiles, at least, which is a start. I made a struct to store the relevant information about a flag/ball, and I maintain an array of those. When I'm scanning for objects to display, if I find a ball or flag, if it is not in the array, I add its information to the array instead of drawing it immediately. If I find a Pawn, I check its PRI.HasFlag. When I get the flag from a Pawn, however, I don't ignore it if its already in the array - I just update its coordinates to match those of th Pawn carrying it. There's also a check before the rest of the logic to mark an object carried by the player so that it will not be drawn. Since I wrote this one from work, it'll have to wait until I get home to test, but I think this should do the trick.

Wow, UScript is very anal about the Length property of dynamic arrays. It's writable, all right, but doesn't seem to like being set with ++ or += operators. Once I got that out of the way, though, it seems to work fine. Flags and balls still lag a bit in net games right after they're picked up, and I'm not sure that that can be fixed, but as soon as the carrier's PRI updates and shows that he's carrying, the flag icon locks right on top of the player icon.


I now show bombing run ball and CTF flags! I think this is pretty much as much as this will ever do... the only other thing I may do is alter it to draw the ball/flag icon on top of the carrying player when carried, instead of detecting the ball/flag as a separate item, since the lower netpriority of the flags can make their icons lag behind the carrier a bit. Heh, pulled out hair for a bit because I put the test to draw the new icon for flags inside the big "these objects are the only important things" test. Question, if anyone knows: since RadiusActors traverses all Actors, which would be faster, using RadiusActors, or using DynamicActors and checking radius myself? Anyways, also did some UI cleanup and beautification, and I'll repackage as soon as I've updated the ReadMe ;-)

After more playtesting, it looks like I'll have to definitely do separate carried-flag vs loose-flag tracking, the flag just doesn't follow its carrier nicely at all on the display. Also, it seems that when you pick up the flag or ball, it remains on the display wherever you picked it up. Best best is probably to make an array to stuff flag-or-ball objects into, and if I find both a player with attached flag, and a flag, use the player's position to draw the icon for that object (after finished scanning through everything). I'll probably try to arrange it so that if you player is carrying, they won't see the flag/ball icon at all - it would just sit still in the middle of the radar display anyways, and you'd have to be pretty confused to not know whether or not you were carrying ;-)


Bleh, woke up at 5ish this morning, after going to bed at 1ish this morning, and couldn't sleep. This should be an interesting day, good thing work on Sunday is slow. Anyways... being up, I decided to try some test code for something I've been thinking about. I was thinking it would be a neat option effect if Redeemer blasts caused an EMP effect that temporarily disabled the radar display, and would be even more neat if the display showed static until it came back up. Figuring that generating random noise in my script would be a bad, bad thing, I made up 5 different random static textures, and hacked in code to overlay a random selection of 2 of them on the display each frame. Looks like crap, it seems like I end up with the same final texture for most frames. I think maybe I need more noise textures, or else Rand is biased, which I hope isn't the case. The textures are 256x256, I'm not sure just how many I should add for an effect that's really just eye candy anyways - I don't want to make this mutator unusable on slower machines ;-) With any luck, I'm crashing after work, so maybe I'll mess with it more tomorrow. Oh, and here's the new KeyEvent I coded yesterday, which seems to work decently:

function bool KeyEvent(EInputKey Key, EInputAction Action, float Delta)
	local string tmp;
	if(Action == IST_Release && Zooming !=0 && Key == LastKey)
		return True;
	} else if (Action == IST_Press) {
		tmp = ViewportOwner.Actor.ConsoleCommand("KEYNAME"@Key);
		tmp = ViewportOwner.Actor.ConsoleCommand("KEYBINDING"@tmp);
		if (tmp == "tdzoomin")
			LastKey = Key;
			Zooming = -1;
			return True;
		} else if (tmp ~= "tdzoomout") {
			LastKey = Key;
			zooming = 1;
			return True;
	return False;

So now, I keep track of the last relevant keydown I had. If the same key goes back up, I stop the current zoom. A new keydown that is captured will replace the old zoom with a new one, and save the new key value. The only catch I've found so far is that if you his ESC while zooming, KeyEvent never catches the keyup, and the zoom will probably go all the way in or out before you get back to the game. Hitting any zoom key will clear the stuck condition though, so it's a minor nuisance at worst.

Also this morning: moved my ReadMe and .int into my Subversion repository, and rewrote my packaging script to insert the current svn revision into them - now the version listed in the ReadMe and in the mutator menu actually matches the version you get.

Sweet - I just talked to Goldenfire, he never did try the debugging build I gave him for his weird zooming issue, but the newest release build, r15, "just works".


Heheheh, that was an adventure. I found the page on SpawnNotify, and it seemed like a perfect way to get out of using a DynamicActors iterator every frame - each UT instance could have a SpawnNotify that traps all spawns and maintains a list of only Actors that are important to the mutator (currently Pawns and Projectiles). Spent half an hour coding it, oops, try to build and that's when I find out this class is gone in UT2k3. I guess for now I'm stuck with DynamicActors, but on the bright side, the "new" code was in things I haven't modified in a while, and I noticed some things I can fix while I'm in there - two chunks of dead code, one just dead, one quite harmful (causing very bizarre display of projectiles on TacticalDisplay).

I was also hoping that the Delta passed to KeyEvent was the time since the last KeyEvent, and that KeyEvent would get repeated calls while a key was held (there's an action IST_Hold, after all), but this seems to not be the case - some logging code shows one even at keydown, one at keyup, and Delta values which I haven't a clue about (all seemed to be negative integer values).

I also did some testing of StopWatch, supposedly for script timing, hoping that it would let me figure out if an idea I had was "too slow" to use, but it looks like I'll have to just put it in and try to "feel out" the speed impact - see StopWatch on the Global Function page for my findings. Anyways, the idea I'm thinking of is to check on KeyDown, by using ConsoleCommand calls, if the pressed key is currently bound to one of the 2 aliases my Interaction looks for. This would mean that changes to control configuration are instant, but I don't know what the speed cost might be. If ConsoleCommand executes reasonably quickly, probably acceptable. Testing time now :-)

That worked out pretty well, the two calls to ConsoleCommand in my KeyEvent handler don't seem to cause any game slowdown or noticeable delay in key handling.


Wow. The word I usually use to describe situations like this is "blecherous". The Input tab, as far as I can tell, doesn't load your key bindings from the defaults of some class stored in a .ini, like many other configurable options. It loops over integers 0-254, and calls PlayerOwner.ConsoleCommand to execute "keyname <i>", "localizedkeyname <i>", and "keybinding <keyname>" for each. For each key it finds that has an alias, it loops over its list of bindable commands to find one with that alias. My GUIUserKeyBinding subclass never gets any properties changed and stored in a .ini, so it looks like the only way to do this is to do the same thing. I'll assign an alias that won't be in use in the GUIUserKeyBinding, and have my Interaction look for the key bound to that command. Only problems I see here are the nonexistent alias causing trouble (I don't think it will), and the Interaction not knowing when its key bindings have been changed. I guess I can expect such troubles when doing things I'm not supposed to ;-)

Well, it works. I still haven't found a way for the Interaction to be notified when bindings change, so what I'm doing for now is to scan for keybindings when the object is created and on level changes.

Urk! One of my friends/playtest victims just got a chance to try the new version, and says the zoom feature is massively broken. Same game (Instant Action) I last tested it with. Will debug when I get home, this should be fun...


I'm currently messing with key bindings, and finding it surprisingly difficult to make them do what I want. It's very easy to use the GUIUserKeyBinding class so alias a key to something, but if your mod is a Mutator, and mainly works client-side, it's hard to do much with that. Exec functions don't work in many places (including Interactions), so you can't easily create new commands to alias to, unless things like PlayerInput or PlayerController, which doesn't really seem good for a little Mutator to grab two keys.

I'm getting user key input now via keys bound to mutate commands, but this isn't good on network. The Mutate function gets called on the server, which has to pass the data back (via an Inventory item) to modify the client-side Interaction. My new plan, if I can figure out a way, is to "find" the custom key bindings, and trap the keys they are bound to in the Interaction via KeyEvent. This would also be better, because I can set flags in the Interaction as to whether the keys are being held, and zoom smoothly and continuously in or out while a key is held. My other option would be to dig through the Input tab code, and figure out how to add a similar key binding GUI to my Mutator config.

before I started a journal...[edit]

I spent about two or three weeks working on a mutator before I started this journal. Probably the most useful thing I learned during that time was that Inventory objects are your friends, when you want to modify client-side objects from a Mutator. Just create a subclass of Inventory, and give it to everyone in a ModifyPlayer in your Mutator. A virtual function in your Inventory subclass can modify its owner, add Interactions to the player (which is what I'm using it for), and all sorts of other things that are difficult to accomplish from within a Mutator class.