Tuesday, July 2, 2019

Cleaning up some technical debt

Well, there's been a growing problem that has finally been resolved with about 8 hours of work.  That problem is the GetComponent call, or more specifically bad early design resulting in the overuse of it.

So somewhere around 1/3 of the code in this game sits on two GameObjects, which are core to the function of the game.  There is the Player GameObject, which handles authentication, represents your character, and contains all of the client to zone server RPC's.  Then there is the Ship GameObject, of which there are various versions of it, representing of course the ships themselves.  Pretty much all of the code related to the ships is attached to these Ship objects (more code than you'd think).

The problem was that the main reference on the client to the Player GameObject was to the GameObject itself.  This created a problem because whenever something like a UI window needed to talk to the Player GameObject it needed to do something like this:

PlayerObject.GetComponent<Player>().DoSomethingCool();

I tried to limit the number of these calls, and cache the reference in other scripts sometimes, but these GetComponet calls were still all over the place.  To make maters worse, even the scripts on the Player object itself when needing to talk to other scripts on the same object would usually use GetComponet as well.  This was all done early on for expediency of development, but since GetComponent is a relatively expensive call compared to using a cached reference, this is a performance problem.

Even worse though was the Player script maintains a reference to the player's Ship GameObject the same way.  Now there are a ton of scripts attached to the ships, and several months ago I created a ShipComponents.cs script which has references to all the other scripts on the ship, and every ship script has a referernce to ShipComponents, so there was no problem there.  But since your ship can sink or be swapped out in a city, I can't just cache a reference to components on the ship.  I have to check all the time if the ship has changed in various scripts and then update cached references.  This gets expensive.

Stuff like this was happening, and sometimes a lot worse:

PlayerObject.GetComponent<Player>().ShipObject.GetComponent<ShipComponents>().ShipMovementComponent.TurnOrSomething();

So long story short, I went and added references in Player.cs to all other Player object components, and the reverse as well.  I then changed the main reference to the Player GameObject maintained to a reference directly to Player.cs.  Then I changed the ShipObject reference that is maintained in Player.cs to a reference to its ShipComponents.cs script.  This cut down around 95% of the GetComponent calls related to these two GameObjects.

This resulted in close to a thousand lines of code rewritten carefully to avoid breaking any existing functionality to fix this issue. 

Yeah!!! :p

No comments:

Post a Comment