
TerrariaClone – An incomprehensible hellscape of spaghetti code - warent
https://github.com/raxod502/TerrariaClone
======
Buttons840
This makes me miss my early days of programming, where no code was too verbose
or horrible to stop me from progressing towards my goal, no matter how
misguided I was. Nowadays I'm distracted by the first hint that there might be
some better way, and all progress stops. I think I'm just beginning to
recognize this, and maybe one of these years I'll learn to recognize when the
right abstraction is really important and when it's not worth sweating the
small stuff.

~~~
Iv
As I had to work more with teams and then supervising teams I changed the
abstractions I value from when I was programming solo: Now I care less about
my project's function than the structure of the team. There is a saying that
any complex project will end up mimicking the communication structure of your
organization. I must confess I thought it was silly until I realized it
happened to us.

I now favor code that has a lot of independent modules that can have hacky
inner code but that must have clear, explicit and preferably simple
interfaces. The project's manager role is to design these interfaces and has
the last work on their implementation.

This is a bit the Unix way. Every module has to do one thing (and optionally
do it well). This allows veteran programmers who know all the subtleties of
the programming language to collaborate with rookie programmers who may write
okay-ish modules that we may have to rewrite later but that work well enough.

It also allows programmers, these very territorial beasts, to have their own
little realms they control and where they are acknowledged. It helps non-tech
managers understand who has to be assigned on different issues and evolutions.

~~~
nickbauman
> allows programmers, these very territorial beasts, to have their own little
> realms they control

My 25 years of programming experience says otherwise. The only place where
this works is with good(ish) programmers who are assholes and must have their
huge, fragile egos stroked or they'll throw a diva fit. I don't hire or work
with those people anymore. Neither should you.

Joint code ownership produces better code because everyone wrote some of it
and nothing is mysterious.

~~~
shrimpx
There's a tension between "everyone writes some of it" and individuals having
autonomy to focus and make decisions. If everybody has autonomy in a shared
codebase, you end up with a heterogeneous spaghetti of unrelated design
decisions and styles overlapping everywhere. To solve this, you normally end
up with a hierarchy of authority, where most people have to have their work
vetted by seniors. In this process, people lose autonomy and can't fully act
on their own vision.

The alternative is to think up new architectures and team structures that
allow more people more freedom to work.

~~~
onion2k
_If everybody has autonomy in a shared codebase, you end up with a
heterogeneous spaghetti of unrelated design decisions and styles overlapping
everywhere._

Being free to do things your own way often means choosing _not_ to do
something if it's going to negatively impact other people. Once you realise
that you need to think about the way your decisions impact other people you
quickly realise that compromising on your choices for the benefit of the wider
team results in much better code.

~~~
watwut
The trouble is that in closely cooperating teams where I worked, people who
did what you suggest ended up in submissive position against people who just
do their thing ignoring others. If I proactive think about others and you
don't, you get to work however you like it oftentimes making my work more
difficult - while I am more restricted and have harder time to make my ideas
reality.

~~~
infinite8s
What you describe doesn't really sound like a "closely cooperating" team.

~~~
watwut
I meant team without clear responsibilities and "turfs" supposed to work
together :). Clear reasonable responsibilities are an awesome thing and kill
whole bunch of insecurities and resulting behavior.

------
userbinator
Maybe the introductory text primed me to expect much worse, but I actually
found the code quite readable although definitely underabstracted. I was
expecting the opposite, the sort of code I usually see from beginning Java
programmers: classes and methods everywhere, but almost no real work.

A long time ago, I (briefly) worked with Enterprise Java. The things I saw
were far worse than this. 100+ deep callstacks[1]. Dozens of layers upon
layers of do-nothing indirection. Dependency inversion and injection used for
just about everything. 50+ character-long identifiers. Tons of XML-based
configuration. The majority of the code consisted of nothing but methods that
only called other methods, perhaps with a trivial conversion or reordering of
the arguments.

This is perhaps an excellent example of how severe underabstraction is much
better than severe overabstraction. There's very long sections of code here
and some of it's very verbose, but it's all very _concrete_ and just about
every line is actually "doing something": the ratio of "actual computation" to
fluff is very high. If given the choice, I'd much prefer working with a
codebase like this than a lot of the Java/C# stuff out there.

I also echo the sentiment from others that the author is clearly very talented
and dedicated, and deserves much praise for even attempting to write something
like this and getting so far with it.

[1] Not mine, but for an example of this insanity:
[https://ptrthomas.wordpress.com/2006/06/06/java-call-
stack-f...](https://ptrthomas.wordpress.com/2006/06/06/java-call-stack-from-
http-upto-jdbc-as-a-picture/)

~~~
bendbro
I wholeheartedly agree.

I've been trying to work that kind of coding style into my job, but it is
difficult to do so without feeling embarrassed. My team also tends to jump on
me when I try

~~~
sytringy05
most stuff I look it is 95% boilerplate. At least this code does something :P

@Author - Must admit although I'm glad there was a 3d array, I'm a little
disappointed there were no object arrays. good job for getting it working,
even though it was probably should have been put to bed...

------
twic
Reminds me of a rather insightful comment from a Hackernews a few years ago
[1]:

> People write MLOC monstrosities in Java because they can. You get some
> boring financial topic and some sub-par programmers and they'll write as
> much garbage as the language can possibly sustain.

> These things are a testament to how safe and simple Java is as a language.

> Not having massive crappy code bases is a negative sign in terms of how
> reliable and easy to understand a language is.

[1]
[https://news.ycombinator.com/item?id=7653762](https://news.ycombinator.com/item?id=7653762)

~~~
egeozcan
I think that has a lot to do with the IDE as well. When I'm using Visual
Studio, I autocomplete and peek until I find something that even remotely does
what I need in the library and move on. I come back and optimize when I see
smoke coming out of the CPU or my project manager :) (Of course I'm
responsible with my code and this is an exaggeration but could this be called
"too mature optimization"? :) )

~~~
giancarlostoro
I'm guilty of this, matter of fact I'm sure a good number of us (developers)
are. Though lately I find myself looking up documentation aside so I can read
through examples and find more information. Some languages / libraries are
better documented than others, and sometimes Stack Overflow fills a niche. I
noticed one library that was not afraid to document things recorded on Stack
Overflow that they made into official documentation and made a reference back
to Stack Overflow which I thought was perfect since you get the context behind
that documentation, as well as it solved a real problem.

------
yathern
I love DoubleContainer:

[https://github.com/raxod502/TerrariaClone/blob/master/src/Do...](https://github.com/raxod502/TerrariaClone/blob/master/src/DoubleContainer.java)

which is fortunately only used in a comment here:
[https://github.com/raxod502/TerrariaClone/blob/9ea04b15add48...](https://github.com/raxod502/TerrariaClone/blob/9ea04b15add48141dbcb905af8fc906d423d854d/src/World.java#L725)

~~~
bcbrown
I really like this method:
[https://github.com/raxod502/TerrariaClone/blob/fd1ff8b8b0e78...](https://github.com/raxod502/TerrariaClone/blob/fd1ff8b8b0e78e6bcc6fc3aa0c1e204d5b84475e/src/Inventory.java#L1666)

~~~
danbruc
That is probably (x + 1) % 10 assuming x is non-negative. That kind of code is
responsible for quite a bit of the verbosity, the author was obviously not
aware of many of the little tricks usually used in this kind of code.

~~~
raxod502
Original author here.

It's actually a method to convert from the index of an inventory hotkey slot
into the keystroke used to access it -- there were ten hotkey slots, which
were numbered 1–9 and 0 at the end.

But I like all the other interesting interpretations here :P (They all assume
way more knowledge than I had at the time.)

------
avenoir
The best thing about this is the open issue claiming it's "Too much like the
real Terraria source code." [1] :)

This bring back a lot of memories. Way, way back in the day i wrote a clone of
Battle City [2] in XNA with a half-decent AI. I had intentions to learn and
use some OOP patterns. I ended up with a handful of monstrous classes and
generally a clusterfuck of spaghetti code. But... i learned a lot about AI and
path searching algorithms and, best of all, it worked. I think i still have
this code sitting on a disk somewhere. This makes me want to throw it on
Github.

Thanks for sharing!

[1]
[https://github.com/raxod502/TerrariaClone/issues/2](https://github.com/raxod502/TerrariaClone/issues/2)

[2]
[https://en.wikipedia.org/wiki/Battle_City_(video_game)](https://en.wikipedia.org/wiki/Battle_City_\(video_game\))

~~~
TeMPOraL
Holy shit.

Be sure to read the issue. It turns out it's not really a joke - someone in
the know points out that Terraria's code is basically the same quality, if not
worse...

~~~
sciolistse
You used to be able to decompile Terraria into perfectly readable code, since
its c# and they didnt use an obfuscator. The code base was atrocious, but it
is impressive that they got something working, and pretty fun, together as
quickly as they did.

These days there are a fair amount of production Unity games out that you can
extract full sources for.. Can make for a fun read sometimes.

~~~
Kuraj
If I remember correctly, the author of Terraria was _also_ just learning C# as
he went on with this project.

It's a huge success story in my book.

------
mcdirty
I did a 3 month contract working on porting Terraria (the actual game) from
XNA to Unity and updating things like UI from sprite batching etc.

Coincidentally and fwiw, the actual source code to Terraria was also a
hellscape of spaghetti code.

~~~
doesnt_know
> porting Terraria (the actual game) from XNA to Unity

Can you talk about this? What was involved? Why do it? Major roadblocks? Do
you feel it was it worth it?

~~~
MBCook
XNA is limited to MS platforms isn’t it? Is imagine it was so they could
port/sell to iOS, PlayStation, Mac, etc.

~~~
doesnt_know
Monogame is practically a drop in replacement which has multi-platform
support/targets. FNA is also effectively the same, with a slightly more
"purist" approach.

I honestly just assume that anyone that says XNA in the context of development
in the last 5 years actually means one of the modern mono implementations.

------
beala
I think true spaghetti code requires teamwork. I mean that seriously. You need
at least 3 people all with different incomplete and incorrect mental models
trying to modify the same codebase at the same time.

~~~
eric_h
I disagree. I inherited an app that I'm maintaining that was written by one
person over ~12 years. When requirements were added, he just cloned the app
and started making the changes so the new app would meet the requirements.
Repeat 2 more times, and you get to now, where there are 4 similar but not
identical versions of the same code base, with inconsistently applied fixes to
various bugs. All 4 still need to work for the organization to function.

It's old school PHP, with sql queries mixed in with markup mixed in with php
business logic - if that's not spaghetti code, I don't know what is.

(I'm replacing it, but it's a very slow process).

~~~
harrisonjackson
I'd say one person over ~12 years is basically multiple developers working on
it. I look back on code after a couple months and it often feels like someone
else wrote it.

~~~
eric_h
Yep, and in particular, one person over 12 years with one to three month
breaks between sessions of working on it. He had no choice but to "monkey see,
monkey do" what his past self did, and the resultant product is ... difficult
to maintain, to put it nicely.

[Edit: I don't blame him - I understand how it happened, and also why he
wanted to get out ;)]

------
indescions_2017
I'd actually try to recruit raxod502 at the high-school senior level. It
certainly shows passion and commitment. You just need to grok the higher level
abstractions. And may in the end even find your "spaghetti" version is
actually more performant at run time ;)

The thing is you sort of need to write like this for the first draft of your
first game. And Terraria is pretty ambitious. Considering most people struggle
with BlackJack or Pong or Snake!

~~~
apo
Writing code in spare time, not to mention 11,000 lines of it, already sets
any high schooler (or any beginning programmer) apart from the majority of
peers. It's shocking how little students in "AP" computer science courses
actually end up doing, and how few do anything outside of class.

Given the choice between interviewing a student who had produced nothing but
verbiage and one who had produced TerrariaClone, I would go with the latter
without even thinking about it.

~~~
criley2
I had a rather unique AP Computer Science high school experience a number of
years ago.

The AP class was mainly a self or group study class inside of a lower level
programming class.

We didn't get as much directed study, but we basically were allowed to chose
projects that interested us and spent a lot of time developing them and
getting help, iterating, figuring it out.

We ended up doing only OK on the AP exam, but we had built a pretty impressive
little java app by the end. A scrolling tile based map, enough network code to
run a chat and let users join, and we had started building some game logic on
top of our multiplayer game room. Very cool and informative, but not exactly
what the AP exam was looking for.

~~~
johnvonneumann
Comments like this kill me a little on the inside, I can't stand having real
work devalued for the sake of contrived assessment criteria.

~~~
jackmott
well the AP comp sci test stuff is not all contrived. it is also useful to
know (mostly)

------
danbruc
That actually doesn't look too bad to me. Sure, it's verbose, repetitive, and
deeply nested, but just from skimming it, it looks quite comprehensible. Load
all the data from files instead of filling huge arrays and maps in code,
abstract similar code into methods, tame the usual mess when dealing with
grids with some helper functions taking care of clamping or wrapping around
coordinates, replace all the parallel arrays with structures, and you should
be able to have some reasonable good code in no time. Might be a nice exercise
in refactoring.

~~~
yathern
Truthfully - I wouldn't call it spaghetti code. I think of spaghetti code as
way to many abstractions (AbstractEntityFactoryFactory). This code has the
opposite problem - needing more abstractions - which is the easier direction
to move.

~~~
flatline
Global state causes code to be spaghettified. Having worked on several code
bases that qualify as spaghetti code, the hallmark trait is that the execution
flow is wound back around itself many times, like noodles in a bowl of
spaghetti, in a way that's not easy to trace. You may have nice abstractions
or none. You may have deeply nested type hierarchies or a seemingly nice flat
structure. You may be using an IoC container with neatly separated services.
None of it matters, you can get spaghetti code with all of them.

Just use global state! Then you can have something where Module A depends on
Module B. Now, at one point Module A calls into Module B which fires off an
event that's handled in Module C that then calls back into Module A. If that
event is going through a pub/sub notifier, bam, hidden global state. Good luck
tracing that subtle bug down when you swapped out implementations of Module C
thinking the new one explicitly filled the contract of the old one, or worse
yet not realizing Module B indirectly depended on C in the first place, and
that A's response to the call from C may repeat the cycle several times. Soon
you realize everything depends on everything else and your tooling does you no
good. That's spaghetti code, just as bad or worse than the gotos sprinkled
through some ugly C code that an undergrad wrote in the 80s.

~~~
MBCook
That’s sort of what I thought of. Is soon as I read a bit about having global
variables at the top of every file I am mediately remembered how I used to
program BASIC when I was first trying to learn it.

------
Scaevolus
The real Terraria code isn't much better. Here's their 3MB [decompiled]
NPC.cs:
[https://raw.githubusercontent.com/csnxs/Terraria/67de21a27e1...](https://raw.githubusercontent.com/csnxs/Terraria/67de21a27e1947ee334ac8dc80d9adb3973cd708/Terraria/NPC.cs)

They had serious problems implementing multiplayer because they had to
synchronize objects with 50KB of state every frame.

~~~
maxton
Important to note is that this code is not the source code, but rather was
generated by dotPeek, a C# decompiler, as mentioned in the repo's README:
[https://github.com/csnxs/Terraria/](https://github.com/csnxs/Terraria/)

~~~
Scaevolus
Variable names and comments are lost, but the overall control flow structure
of decompiled Java and C# code closely matches the original.

~~~
danbruc
Even variable names are usually not lost.

------
Sir_Cmpwn
I have an implementation of Minecraft I'm pretty proud of:
[https://truecraft.io](https://truecraft.io)

However, it is the evolution of several much more embarassing projects. In
order from oldest to newest:

[https://libminecraft.codeplex.com/](https://libminecraft.codeplex.com/)

[https://github.com/sircmpwn/Craft.Net](https://github.com/sircmpwn/Craft.Net)

[https://github.com/SirCmpwn/PartyCraft](https://github.com/SirCmpwn/PartyCraft)

[https://github.com/SirCmpwn/TrueCraft](https://github.com/SirCmpwn/TrueCraft)

I _still_ hate the client code of TrueCraft and it's due to be ripped out and
rewritten from scratch. There were also projects earlier than LibMinecraft
which, thankfully, have disappeared from the internet.

~~~
Posibyte
So I see you everywhere on HN. You usually have the not-so-consensus opinion
that I usually agree with. First off, so we have a baseline. I never thought
to check your profile and look for projects or blogs or anything.

But wow, you have written some super neat things I had no idea about.

Though apart from just posting to comment praise, more to the topic, I love
seeing developer's old work when they were new. It's almost.. humanizing?
Like, I swear EVERYONE at one point has were they said "I'm going to learn
programming and make the coolest game, better than the other stuff, because
I'm creative with ideas."

And then you try it and you realize how not simple and straightforward that
is. But you keep on it, you gain a passion for it. And as you posted here, you
can see the evolution of skill and pragmatism.

But apart from the topic again, Truecraft is super cool. Sway is super cool
and I didn't know about it. I'm going to play with both of them tonight, so
thank you for writing two awesome programs for me to spend my day off with :)

~~~
Sir_Cmpwn
Thanks for the kind words :)

------
writeslowly
This reminds me of the C# source code for DRAGON. Its code was actually much
worse, because the creator wasn't aware of things like loops or method
definitions (the main game loop and class appear to have been generated by a
framework).

The C# code is here, and it works well enough that you can buy it on Steam,
apparently:
[https://gist.githubusercontent.com/alessonforposterity/832da...](https://gist.githubusercontent.com/alessonforposterity/832da4fab11e10609dad/raw/258df12378399919ae088ba8731a7571d9c2c947/drgn.txt)

~~~
serhei
The ability to buy something on Steam is sadly no longer a guarantee that it
works.

~~~
jackmott
I played it. it worked.

------
S_A_P
As Ive gotten older, I have severely relaxed my dogma on coding standards. I
agree that code should be maintainable, legible and logically formed.
Sometimes though, you just need to get things done, and architecting a large
solution of abstractions and frameworks, just doesn't seem like a good use of
time.

~~~
hinkley
For me it feels more like a zero sum game.

Some things I care about a lot less, others I care about more. The biggest
problem I have is with obscure code, and my understanding of obscure has
shifted over time.

Basically, I prefer code that gets you to ask the right questions. I'm still
trying to put my finger on what qualities those are.

I still care about code that looks one way but does something else, and I care
about code that conceals what it's doing and how it accomplishes it by using
convoluted delegation.

But a function with a single purpose and clearly named? If it's loaded with
kruft I only care if it's on a flame chart or I have to keep stepping through
it while debugging another issue. So I care more about functions in the middle
or the top of the call tree and less about the leaf node ones.

I still push back on "It's not that hard to figure out this code" on the
grounds that when an odd bug happens I'm going to be scanning dozens of
functions trying to spot an issue. If every one is chock full of code smells,
that process takes forever. In fact it discourages people from doing the right
thing and instead they slap more workarounds on top instead of trying to find
the real cause.

------
XR0CSWV3h3kZWg
And here is someone that is trying to rewrite it in scala:

[https://github.com/BusyByte/TerraFrame/tree/convert-to-
scala](https://github.com/BusyByte/TerraFrame/tree/convert-to-scala)

------
1001101
I had to see for myself. Yep, that's bad. What's not bad is the author's
attitude about learning and improving. It also looks like this was a stop on
the way to Harvey Mudd CS. [1] So, a happy ending, perhaps.

[1] [https://github.com/raxod502](https://github.com/raxod502)

~~~
iaw
With one exception I've never looked back at code I've written and thought
"well that's well designed."

Typically every few months I've improved enough to notice the quality
difference.

------
vilius
Not sure if this is a common story for most programmers or maybe me and the
author have same personality traits. Back in the Delphi 6 days I was 16, with
no internet access I started learning about programming. It all began by
reading an article of how to write assembly code in Delphi. Had no idea what
it meant, but it was interesting. So I've started.

12 months forward I had made my first "commercial" product - Power Crypt. A
Windows application allowing to encrypt / decrypt files. It as written in
Delphi, had a single class of ±5000 LOC and used open source cryptography
library.

Main selling point was that it encrypted a file not by using a single
algorithm, but with all (about 10 or even more) the algorithms the OS library
had implemented. Thus making it more secure :-)

------
fancyPantsZero
This makes me sad. Not because of the code quality, but because it makes me
think of all the games I used to write back in middle school that are now lost
to the swirling sands of time. The youngins don't know how good they have it
with github!

~~~
sgs1370
Your comment reminded me of a game (maybe the only one) I wrote in middle
school, on a TRS-80 Color Computer (I think 4K, although maybe I had the 16K
upgrade by the time I wrote the game). I wrote it in basic & saved it on some
cassette tape... random blocks of one color on the screen, and you are a block
that starts at the bottom and you use arrow keys to avoid the blocks as you
are thrust upward. (I guess it was basic in more ways than one). I might have
added a 3rd color block that gave you points if you hit those.

I wonder if I could even write it now - even at low resolution? My limited
scripting is now systems-oriented, the tiny bit of UI stuff takes me forever &
I find HTML & JS way more complex than basic ever was. (Don't misunderstand, I
think my python scripts that interact with various AWS services, postgres, etc
are just fine and don't take me long to write or maintain, its just the whole
graphics world I never latched onto...)

------
tgb
When I first started programming (this was in C++), I decided that the obvious
optimisation was to declare all these redundant local indices i,j,k as
globals. Then the program won't need to make all this redundant crap! Of
course that led to absurdly subtle bugs that only occasionally showed up since
whenever I called a function which had a loop in it from inside of another
loop, I would use i as the index for both loops. Error! I learned several
important lessons when I figured that one out.

But now the author here says they're doing that same thing! How has this not
inevitably led to problems? Or am I misunderstanding the scoping in Java?

~~~
raxod502
Original author here.

The fact that all the methods were so ridiculously large made declaring loop
indices globally less of a problem. But trust me, it caused plenty of bugs...
:P

------
zokier
> The TerrariaClone.init() method, which is over 1,300 lines long, actually
> grew so large that the Java compiler started running out of memory trying to
> compile it!

Seems surprising, 1.3kloc doesn't feel that big in the scale of things. I
wouldn't be surprised if some of the methods at $work would be on the same
scale, and it compiles just fine (relatively speaking..). And based on quick
scroll-through, there isn't really anything especially egregious in there that
would point towards why the compiler fails.

~~~
jcl
Given the relative size of the function and typical memory, I suspect that the
issue the author ran into was actually the JVM's 64KB limit on the bytecode
size of a compiled function.

[https://stackoverflow.com/questions/17422480/maximum-size-
of...](https://stackoverflow.com/questions/17422480/maximum-size-of-a-method-
in-java-7-and-8)

------
mwexler
The ability and willingness to slag your own defective work is rare,
especially in public. Compliments to the dev, who recognized how much he's
changed and was able to point out flaws with no holds barred and some humour.

------
chris_wot
The Terraria clone is apparently very much like the original:

[https://github.com/raxod502/TerrariaClone/issues/2](https://github.com/raxod502/TerrariaClone/issues/2)

------
mickronome
Done 15 years as a consultant, and that code looked much better than some of
the code I've worked with. Even right now I work with code that looks worse in
many aspects, although in a slightly different way. The code of the game is
very obviously written by someone which at the time had much more passion than
knowledge, but who tried his/her best anyway. It's a lot easier to deal with
that, than with 3000 line methods of complete and utter madness written by
people who really should know better, people who actually get paid.

------
aryehof
I think this is a good example of what has become standard thinking for much
of general programming. That the way to write a complex application is an
"agile" approach of hack it 'till it works. The result too often is that
slowly over time, the result increasingly approaches being a big ball of mud
as seen here.

I find in interviews that nearly all programmers only have an approach for two
types of applications. The first being a run-to-completion program that
produces an output based on inputs. The second being a program where concepts
are modeled as data entities, manipulated by behavior (typically just
add/edit/delete) in an application/service/controller layer organized using
functional decomposition. For problems that don't fit these two, all that is
left is that agile hack-it approach.

My hope is that some additional lessons were learned about how to apply
appropriate program _design_ to produce a result that won't just result in a
different mess next time.

------
tbodt
A perfect example of "it's so bad it's good."

------
hinkley
I would love if we could get together as a community, take a project like
this, and use it as an example for what a little refactoring can do.

As a cooperative endeavor it should be doable, but a competition would be more
fun, though I can't imagine how you'd judge such a thing.

~~~
raxod502
See
[https://github.com/BusyByte/TerraFrame/pull/1](https://github.com/BusyByte/TerraFrame/pull/1).

------
kevan
It's beautiful. I have a sudoku solver that's almost as bad (but not as
impressive as yours) written in Scheme when I was first learning how to code.
It's good to look back on your past work every once in a while and see how far
you've come.

------
arianvanp
This reminds me of the original RuneScape codebase. It's a 16k line God class,
with some utility classes for networking and graphics. Decompiled code floats
around on the web under the name "runescape 317 deob" if you want to check it
out.

it's a real "beauty" and hacking around in it to create bots was my first
experience with programming.

Edit here it is: [https://github.com/Rabrg/refactored-
client/blob/master/src/c...](https://github.com/Rabrg/refactored-
client/blob/master/src/com/jagex/runescape/Game.java)

------
stuaxo
I've seen way worse code than this in my time, some in the last year.

------
yellowapple
Reminds me when I first stumbled upon a book on BASIC at my elementary school
library, then got ambitious and tried to write my own Galaxian-ish game.
Started with a whole screen with all the enemies and stuff, prompted for an
input, and started trying to map out every single possibility.

Needless to say, I gave up very quickly and convinced myself that this
"programming" thing was way too hard. Didn't even start to dabble in it again
until high school (and that was mostly a bunch of mucking about with VB6 in
Word/Excel).

------
beager
I did the same trying to write a Minecraft clone back in 2012:
[https://github.com/beager/craftalike](https://github.com/beager/craftalike)

I'm very much not proud of the code, it's sloppy, incomplete, quite copy-
pasta. But it helped me learn a lot of concepts about game dev that a web dev
wouldn't know, and it was tremendously exciting to create something in code
that you could compile and play around with. No regrets.

~~~
k__
I did one too.

We basically gave up after the networking stuff grew over our heads.

------
jason_slack
The fact you took the time to follow your idea is great. Kudos.

Also, the fact you "think" your code is spaghetti shows you have grown as a
developer. Kudos.

Love the part about codeToLarge()

------
DubiousPusher
A little more egregious than usual but some of this is not that far from code
I've seen in multiple AAA games. Some of which you've probably played.

------
partycoder
I have seen way worse. At least this code is indented, it executes, etc.

I have seen code that is absolutely devoid of reason, logic, formatting, that
doesn't even execute... an evented mess with 40 levels of nested callbacks
with methods 6000 lines long made by people that just got fired after an
incident with comments in some foreign language slang.

------
BearOso
This isn’t too bad. Check out the source code for qb64, it’s hilarious:

[https://github.com/Galleondragon/qb64/blob/master/internal/c...](https://github.com/Galleondragon/qb64/blob/master/internal/c/libqb.cpp)

------
flavio81
Beauty. I see beauty. I see God in one 6000-line class (TerrariaClone.java),
overflowing with constant data / tables embedded in the code.

Awesome!

PS: "Abandon all hope..."

PS/2 * : I saw it and i suspected this was code generated by other tool; then
somebody commented that this was based on dissasembled .NET bytecode. This
explains it all!

* (c) IBM

------
zackify
Looks just like the Freepbx codebase, but that's php
[https://github.com/FreePBX/core/blob/release/13.0/Core.class...](https://github.com/FreePBX/core/blob/release/13.0/Core.class.php)

------
danschumann
When technical debt gets so large that you go bankrupt ( quit the project ). I
did this with an actionscript game. Then an html editor. I did not know what I
was doing. I looked back at the code and decided that starting from scratch
would be much faster than refactoring what existed there.

------
smithkl42
I'd hire in a second anybody who's thought this hard about how to critique
their own code.

------
keithpeter
[http://sohcahtoa.org.uk/kepler/tmoon.c](http://sohcahtoa.org.uk/kepler/tmoon.c)

Grunge C and huge comment block at start, compiles and works though. One day,
I'll revisit this and have a think about data structures.

~~~
Retr0spectrum
Wow, that indentation...

~~~
keithpeter
Yup. Was written about 20 years ago. I'm an amateur.

------
gigatexal
Props to you man for making a game clone as a way to learn: even if it sucks
that’s more than I’ve done to date (making useful utilities in python isn’t as
cool as a game). I think it’s good to ever remember the past and learn from it
so that you don’t repeat it.

------
codingdave
Normally when I hear people disparage their early attempts at code, I think to
myself, "Oh, come on... how bad can it be?" Well, this is bad. Really, really
bad.

On the other hand, there was nowhere to go from here but up. Gotta start
somewhere, right?

------
andrewstuart
I like that people have the courage to start the process of learning and
improving.

------
imron
I remember when I first started programming, and I couldn't figure out the
obscure error message preventing the Turbo Pascal game I was making from
compiling.

Turned out having over 65k of global variables was too much :-D

------
BlakeCam
I wonder how hard it would be to write a program to automatically refactor
code like this into something reasonably clean. My intuition thinks it should
be difficult but possible... and extremely useful.

~~~
jeremyjh
There are linters which do a bit of this, but they only cover the lints they
have rules for. I'm pretty sure no one has a rule for "all loop indices
declared as class members" because no one writing code of this quality has yet
used a linter. Many issues in this code-base are not tractable at all for
automated repair: how are you going to rework thousands of line long methods
into well-factored classes and methods?

~~~
dbremner
ReSharper (and presumably IntelliJ) supports expression-based search and
replace.

Here are some commits where I used it to remove boilerplate from some test
cases. The code was written long before MSTest added support for
Assert.ThrowsException.

[https://github.com/dbremner/PowerCollections/commit/a364a154...](https://github.com/dbremner/PowerCollections/commit/a364a1548e7ba0e8e57ec63f4cd09aab04c09cda)

[https://github.com/dbremner/PowerCollections/commit/1de2f916...](https://github.com/dbremner/PowerCollections/commit/1de2f916faacea4c62403edb4916363711c5a0e9)

[https://github.com/dbremner/PowerCollections/commit/183e3c7c...](https://github.com/dbremner/PowerCollections/commit/183e3c7c345c667c575a046af348dd6444a24895)

------
amatecha
I can barely even read the README.md ... too scary. This is perfectly in time
for Halloween season! :'D

------
nuclx
The code doesn't look much worse than some of the production code bases I
encountered.

------
smrtinsert
6560 loc in TerrariaClone.java. Closed tab, will never look again.

~~~
hinkley
A lot of that file is data.

Some of it is just plain data (arrays), a lot of the rest is a bunch of
setters one after another.

------
azr79
O(N^2)is hell of a drug

------
kdazzle
You are so brave

------
Zekio
I forgot this existed, high quality code right there

------
d--b

                        if (left) {
                            if (right) {
                                if (up) {
                                    if (down) {
                                        blockds[y][x] = 0;
                                    }
                                    else {
                                        if (upleft) {
                                            if (upright) {
                                                blockds[y][x] = 1;
                                            }
                                            else {
                                                blockds[y][x] = 2;
                                            }
                                        }
                                        else {
                                            if (upright) {
                                                blockds[y][x] = 3;
                                            }
                                            else {
                                                blockds[y][x] = 4;
                                            }
                                        }
                                    }
                                }
                                else {
                                    if (down) {
                                        if (downright) {
                                            if (downleft) {
                                                blockds[y][x] = 5;
                                            }
                                            else {
                                                blockds[y][x] = 6;
                                            }
                                        }
                                        else {
                                            if (downleft) {
                                                blockds[y][x] = 7;
                                            }
                                            else {
                                                blockds[y][x] = 8;
                                            }
                                        }
                                    }
                                    else {
                                        blockds[y][x] = 9;
                                    }
                                }
                            }
                            else {
                                if (up) {
                                    if (down) {
                                        if (downleft) {
                                            if (upleft) {
                                                blockds[y][x] = 10;
                                            }
                                            else {
                                                blockds[y][x] = 11;
                                            }
                                        }
                                        else {
                                            if (upleft) {
                                                blockds[y][x] = 12;
                                            }
                                            else {
                                                blockds[y][x] = 13;
                                            }
                                        }
                                    }
                                    else {
                                        if (upleft) {
                                            blockds[y][x] = 14;
                                        }
                                        else {
                                            blockds[y][x] = 15;
                                        }
                                    }
                                }
                                else {
                                    if (down) {
                                        if (downleft) {
                                            blockds[y][x] = 16;
                                        }
                                        else {
                                            blockds[y][x] = 17;
                                        }
                                    }
                                    else {
                                        blockds[y][x] = 18;
                                    }
                                }
                            }
                        }
                        else {
                            if (right) {
                                if (up) {
                                    if (down) {
                                        if (upright) {
                                            if (downright) {
                                                blockds[y][x] = 19;
                                            }
                                            else {
                                                blockds[y][x] = 20;
                                            }
                                        }
                                        else {
                                            if (downright) {
                                                blockds[y][x] = 21;
                                            }
                                            else {
                                                blockds[y][x] = 22;
                                            }
                                        }
                                    }
                                    else {
                                        if (upright) {
                                            blockds[y][x] = 23;
                                        }
                                        else {
                                            blockds[y][x] = 24;
                                        }
                                    }
                                }
                                else {
                                    if (down) {
                                        if (downright) {
                                            blockds[y][x] = 25;
                                        }
                                        else {
                                            blockds[y][x] = 26;
                                        }
                                    }
                                    else {
                                        blockds[y][x] = 27;
                                    }
                                }
                            }
                            else {
                                if (up) {
                                    if (down) {
                                        blockds[y][x] = 28;
                                    }
                                    else {
                                        blockds[y][x] = 29;
                                    }
                                }
                                else {
                                    if (down) {
                                        blockds[y][x] = 30;
                                    }
                                    else {
                                        blockds[y][x] = 31;
                                    }
                                }
                            }
                        }

------
louithethrid
Open the Git Repository. Eyes glaze over. Just like the Robotsourcecode, you
get to see every day, if you work in automation. Close the Git Repository.

Dear Author, at least you know while and for.. it can be worser.

