-
Notifications
You must be signed in to change notification settings - Fork 134
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Too much like the real Terraria source code. #2
Comments
Sorry. |
Well I appreciate the insight, horrifying as it may be :D |
Dear lord... |
Oh hi @PoroCYon! I'm glad to know that you've stumbled on this too. @raxod502 try and wrap your head around the decompiled version of Item.cs: https://raw.githubusercontent.com/Pryaxis/Sources/master/1.3.5.3/Terraria/Item.cs |
Holy shit and here I was thinking it was just the compiler mangling everything. |
And yet it's an extremely successful game that sold tens of millions of copies. So there's a lesson in there. It doesn't matter if your code is "pretty" or "efficient". What matters is that it works and the game it works for is good. Or maybe that's just wishful thinking of an awful programmer. |
As far as I remember, Minecraft used to use the same magic number system for tiles and items. It meant that whenever someone used console commands to spawn an item, it was as if they had god memory. This has been replaced now, you can type tile names rather than ids in console, but I think that internally it still works the same way. |
@otoomey internally they probably used enum values, though |
@UristMcDorf That's what you'd wish -- Terraria technically works, but it's a hell to work with, and it's extremely fragile (which shouldn't come as a surprise). It could've been coded in such a way that it'd run much faster (eg. because it currently allocates way too much every frame). To everyone: here's a bonus:
|
Now I want to read the comments in the original source code. |
@Restioson Nope. Enums were used for tool types (wood, stone, iron, gold, diamond), but not for blocks or items. IIRC, there was one big static code block that defined all the block IDs. If you wanted to e.g. set a certain location in the world to be cobblestone (block ID 4), you would say |
Now I really want to read some insights from the original Terraria devs - sounds veeery interesting 🙂 |
I request this to be tagged as "wontfix" |
https://www.reddit.com/r/ProgrammerDadJokes/comments/729qtl/comment/dnh9vds |
This is pure gold. |
Reddit has rediscovered this work of art https://www.reddit.com/r/badcode/comments/cl2vxt/anyone_who_looks_at_this_code_instantly_becomes/ |
Hi, I too work with Terraria modding, and I can confirm that the code is horrible. But I come from a different angle: I specialize in the multiplayer part of the game. I work on modded community servers and have worked extensively with the TShock framework. I can tell you a whole lot about Terraria's netcode protocol (guess what—it's bad, too): The server application is simply a copy of the desktop game but with the rendering code taken out through conditional compilation symbols or something of the sort. Differences between server and client are differentiated with if chains using the format Packets are sent with a scrapped-together binary TCP protocol. You send a packet with the method Once you get down to the binary protocol, you basically have a 2-byte type argument and then a massive switch statement for the sender and receiver classes that parses the payload manually. Lots of undocumented The concept of an "authoritative server" has no meaning in the Terraria codebase. When a player gets damaged, the client sends a PlayerDamage packet to the server, that then verifies the damage. I could go on. This, suffice to say, makes it a lot harder to combat cheating on large multiplayer servers. Despite all this, I still choose to contribute to this community and actually enjoy doing it somewhat. This is possibly due to the fact that I huddle myself behind a fortress of wrapper classes to shield me from the particularly bad stuff, or possibly it's because I have Stockholm Syndrome. There's also a sort of sick appeal to making a functional multiplayer server with such strict limitations, kind of like how people write binary calculators in Super Mario Maker. There's some level of respect you have for those people, but you also feel a little bad for them. |
@ZakFahey what's packet 13 😨 |
It's the "UpdatePlayer" packet type. |
Sshhh, that sounds too familiar to me. Thankfully, I moved on... to somewhere where I code assembly all day. |
I was a Terraria modder and a member of the tConfig and tAPI dev teams. (I also made another modding API for 1.3, but it didn't take off.), and I can say you didn't only try to clone the game, but also the code quality of Terraria:
Terraria does the exact same thing.
We (Terraria modders) had no such thing, so the table must be made manually (or rather, we used some code to generate it). Some methods exist (such as
Item.SetDefaults
) to give an Item's fields (not properties, but raw fields) the desired values. (There are no subclasses or anything, and no Item/... definition lookup tables/... .) It is an infinite sea ofif (type == foo) { init(); } ...
. Note that it usesif
withoutelse
orreturn
, drastically slowing it down, but it got changed to aswitch
in 1.2. (More onSetDefaults
later.) In 1.2, aTerraria.ID
namespace was added containing (static) classes containing constants for easy Item/... -> numerical ID lookup as well.Terraria entities also have a
netID
, which slightly differs from theirtype
: entities with the same type have the same texture, but they can have differing netIDs. The latter defines the actual properties (max life, damage, ...). Thus, separatenetDefaults
methods exist as well...Terraria didn't do this, but the compiler mangled the variable names enough, and the combination with huge methods and the usage of next to no non-primitive types resulted in lots of occurrences of locals called
num256
etc. (Yes, methods with >100 locals exist.)This is nothing compared to
Main
, spanning several 10 000s of lines of code. It containts the global game state, global loading/unloading, >75% of all the rendering code, sound handling, ...Item
,NPC
,Player
,Projectile
,WorldGen
... are huge as well.The compiler manages to live with extremely huge methods, but the decompiler chokes on them. (I don't know anything about the compilation of the original source code side of things, but some badness might happen there as well.)
Item.SetDefaults
is one of them, and it is split in 4 (!) separate methods, calledSetDefaults1
through 4, plus thenetDefaults
one. (This was done by the dev team. If this wasn't the case, we (the modders) would have to fix the binary usingMono.Cecil
ordnlib
and edit the raw MSIL (the C# equivalent of Java bytecode) programmatically...).NPC.AI
,WorldGen.generate
,Player.itemCheck
are insanely large as well. As of 1.3, Terraria explicitely invokes the JIT compiler on startup to make it compile everything at once, so no slowdown occurs during gameplay due to the JIT. (This does happen, however, when loading textures ingame...)FYI, decompilation alone takes hours while eating all of your CPU and RAM.
Those were all over the place, especially for tiles (which didn't even have a
SetDefaults
method). This only got worse in 1.2.Map data, localised strings, ... are all managed this way, but
Recipe.FillRecipes
(or something like that, my memory is a bit hazy) is the absolute worst in this regard.This is commonplace.
NPC.AI
,Player.ItemCheck
,Projectile.Update
,WorldGen.generate
, to name a few.There was zero debugging information in the Terraria binary... except for something that logged every single keypress to the console, annoying everyone who used
Console.WriteLine
for debugging mods.There is no (official) GUI framework for XNA (although third-party libs exist), and Terraria uses an "imgui", but without any sense of structure. It simply uses raw
SpriteBatch.Draw
calls etc, the current 'page' is also identified by a magic number. This got better in 1.2.3 (iirc, but it could as well be 1.2.0 or 1.3.0), though. Ingame inventory/... rendering is even worse.I could go on and on and on and on about this. See this or this (NOTE: I worked on this.) to get an idea of the hacks required to make modding possible, or grab a decompiler and let it run overnight to witness the horror yourself. (NOTE: I advise against all this if you still want to live a happy and carefree life.)
Sorry for giving you a braindump, but I need emotional relief. Working with this codebase gave me a PTSD of some sort.
(NOTE: I only had access to the decompiled source code, but MSIL->C# translation is quite accurate, so I can safely say that this applies to the original source code as well.)
The text was updated successfully, but these errors were encountered: