20150630

Lobby for more mental energy

Last few weeks passed by leaving me feel like a zombie. When I got home, I could only play and watch series. (On a more uplifting note, I bought Abathur in Heroes of the Storm, and I love his playstyle.)

What little energy I had I used to rewrite the lobby, because the lobby code was a mess. Now I have a Lobby class that is responsible for communication with the server, and the Multiplayer GUI just communicates with this lobby class. It works just like the old one, but now I can understand my own code.


Now I don't know what should I work on. Either the Level editor, which seems simple (just click on a tile, and then click on a place on the map, and then overwrite that place with the selected tile in memory). However, I could just create a map by hand, or using Hexographer and just convert it. It would be good enough for testing.

Well, I guess I'll have another day to decide that, after I'm done feeling guilty of the lacking updates. Also, I'd like to thank Introversion software the inspiration to get my working energy back. (Prison Architect Alpha 34 came out today, and in the video, they talked about how the obligation of getting a new build out at the end of the month makes them able to work even when they really don't feel like it. I envy them.)

20150616

Sleep deprivation and server architecture

If I sleep about 4 hours for a few days, I become more concentrated (can get work done more easily), more creative (less energy for my mind to filter out ideas bubbling up from the unconscious), and less able to create mental constructions (so I won't come up with an elegant architecture). If I sleep less then 6 hours, and then I work 8 and a half hours, then I will be absolutely useless.

I also learned that my circadian rythm does everything it can to stop me from getting up in the morning and going to bed in the evening. When I'm working in night shift, I usually get up around noon, and go to bed around 4 AM. (Also, if I'm left to myself, I will usually sleep ~10 hours.) The best thing is that at night everything is quiet, so I can think. But when I have to work from 6 am to 14:30 pm, this tendency to not sleep enough takes its toll on my ability to work on my game. This is why I didn't do much in the past week.

Before that, a first draft of the game server was finished. The first problem I ran into was this: when a client connects, it sends its name and intended color to the server, then asks for the player list. If this was done in a quick succession, then it received a list of players without its own data updated. Why?

Let's take a look at how the server architecture looked like:



In a nutshell: clients connect to the server. The Listener thread listens to them, and spawns threads for each client (not depicted on the picture, think them as part of the Listener box). Those threads send and receive messages to and from MessageRouter, which forwards the messages to either CommandInterpreter (if it is a server-administrating command, starting with the "recon" prefix), or LogicDaemon (if it is a message to the game server itself). Then they both send requests to the ServerManager, containing modifications to the actual server data.

The problem is that I'm using Software Transactional Memory (STM), so any transactions I make to an object cannot be seen from outside until it is finished. It means that while these requests are not finished, one can still access the old state of said object. This is why the client got the message that - in spite of the client has told its name - it doesn't have name assigned to it. If it were to ask for the player data, say, half a second later, it would have correctly seen its name in the player list.

What I did was to merge four of the threads into one: MessageRouter, LogicDaemon, CommandInterpreter and ServerManager.



Results: now if the client sends the message too fast, the server doesn't even get it. Fail. But everything else works as it should, so I hope it's just a minor something that I have overlooked. (EDIT: Figured out the reason, it indeed was a problem with how the server parsed the incoming messages. Was a fault of my own laziness.)

This is a thesis on writing a game server in Erlang. it seems, most of the components of the server can be found in my server architecture as well (with some differencies). I guess I can be moderately proud of myself.

20150611

Unity and spies

So Unity 5.1.0f3 just came out. I updated. Wish I hadn't. Because now it crashes while it tries to show the splash screen. Reinstall, registry cleaning, removing every Unity-related folders I know of, installing in a different place (what if bad sectors are the problem) - nothing has helped. Maybe I'll just give up and revert to 5.0.1.

So while there are no updates code-wise, I thought I'd share my struggle with the spy unit. Initially, I thought the spy could be a scout-like unit and that's all. But it wasn't as exciting as I think a spy unit should be. Sun Tzu in Art of War distinguished five types of spies:

"Hence the use of spies, of whom there are five classes: (1) Local spies; (2) inward spies; (3) converted spies; (4) doomed spies; (5) surviving spies"

So what are these?

"Having local spies means employing the services of the inhabitants of a district."

The spy "system" in its current form doesn't let us do this. So how should we incorporate it in the game design? Bribe enemy towns, maybe? What should that result in? Could we see a few tiles around the town? Should the cost be defined per turns? What would deter somebody from just buying all towns? Is it a life-like scenario? (While we're at it, is this game life-like at all?)

"Having inward spies, making use of officials of the enemy."

 Bribe enemy spies? What would deter a player from just hiring all enemy spies?

"Having converted spies, getting hold of the enemy's spies and using them for our own purposes."

When we would kill a spy, should the game ask if we want to kill or convert into a double agent?

"Having doomed spies, doing certain things openly for purposes of deception, and allowing our spies to know of them and report them to the enemy."

This would be fairly straightforward: assuming one of our spies is a double agent, we could move our units in a way that makes the enemy do incorrect assumptions. This only requires the game mechanics that lets a spy to be a double agent. Which is the harder part.

"Surviving spies, finally, are those who bring back news from the enemy's camp."

It's just sending a scout into the enemy lines. The kind of spy the current system has.


The concept of bribing seems to come up regulary at the spy types. If I were to implement it, how should it work?
  • Should the player capture a spy before it can be bribed? Not a good idea: the other player - seeing the spy had been captured - could just kill the spy and hire a new one.
  • Let the player bribe any spy anytime? (At least those who are visible to them.) Not a lot of players would use spies then - they could be seen accidentally, and then they are better off dead.
  • Hire the spies with some user-given cost, and let the other player bribe any visible spy at any time, with a custom cost, and if the cost is higher then it is converted? In this case, the players should not know if the spy is still theirs, because then they just raise the cost, and then they are OK. But how we make sure none of the players know if it is actually still their spy or not?
    • Place random units instead of what's actually there. I don't like this idea, as I'm not a huge fan of randomness. This game is all about a minimalistic warfare simulator, without any random chance whatsoever. It would also be somewhat hard to implement.
    • Doesn't update the fields that only the spy can see. It might actually be a usable idea. For some reason it still doesn't feel like it is, but I can't tell what is my problem with it. Just as with the spy-betting system: I sense there is something wrong with it, but can't tell what
 These are the ideas that I had so far. I'm not sold on either of them so far. It might be a decision that needs playtesting to figure out which is right, or maybe I got some other idea. For now, I'm going to go with the "spy-as-a-scout" plan, and then work out the details when it's time.

20150603

Static typing vs dynamic typing

Static typing all day every day!

I'm working on the server for the game.Previously I have mentioned Google App Engine, and the fact I'm using Python. Now that has changed. I am not using Google App Engine for now. (I'm rather thinking about getting a free plan on OpenShift.)

I could use Frege (Haskell-like language on the JVM) on the JVM with GAE, but why limit myself to GAE's restrictions, when I can have a free OpenShift account that doesn't have them? (I haven't researched the topic extensively, so I might stumble upon some factor that makes me rethink this, but I will eventually need an offline, local server, when I want to support LAN, so either way, I have to write it.)

What was my problem with Python?

When I wrote a few lines of code, then I fired up the client to test it, it caught some error - maybe I wanted to call a method on the None object, because I didn't check for the object being None (this was the most common type of error). I fixed it, ran the client again, and oops, another error. This time I tried to concatenate a string and a number together. Fixed that. Next run, I forgot to write the "else" part of an "if" statement - since that I always write out the "else" part explicitly, and then have a "pass" in it, if nothing else. I have avoided a few problems thanks to this habit. Ran the client, and it went fine.

Three runs for a few lines of code, half an hour wasted, and have no guarantee whatsoever about my code correctness. That would require unit tests, static code-analysis tools, etc.

What about Haskell?

After I switched back to Haskell (which I've been coding in for a few years now), I started by laying out the types of the functions I knew I wanted to have. Most functions' body was empty. It gave me a structure that could be filled with code - most times the solution was straightforward, thanks to the types, I hardly had to do any thinking. Of course, the initial, upfront design had to be thought out carefully, but after the types were in place, it was just compiling for typechecking, and fixing the type errors.

I coded for 4 days without ever running the code - mostly because there were missing body functions that I haven't written yet. But I had confidence that once I'll run the code, it will Just Work(TM). After I wrote every necessary functions, I have started the code, and it ran...

...with hitches. It turns out, that once the main thread finishes execution, all the other threads die instantly. So I just inserted a placeholder thread that just runs without doing anything, and the server is now working correctly (at least the connection handling, but I don't expect any big problems with the other parts). I could quickly add a logging capability as well.

What causes this difference?

Types. Let me explain.

What kind of troubles I ran into with Python?
  • - Null types - with Haskell, you can make any type into a nullable type by using Maybe. (Or you can just roll up your own Nullable datatype.) You want a nullable Int? You can have Maybe Int. You want a nullable EmployerStruct? Maybe EmployerStruct. You want a nullable function with side effect giving you back some value? Maybe (IO a). If you are a masochistic mad scientist, you can make nulable types nullable: Maybe (Maybe Int) (though this usually has no usability, so don't bother). The catch is: it is stated explicitly. If you are eypecting a nullable type, the type checker makes sure you are aware of it. If you are not expecting nullable type, the type checker makes sure you can't give that function a nullable type.
  • - Missing "else" caluses - in Haskell, an "if" MUST have an "else" clause. You have to return something. If your function returns a number, you have to return a number. (And "undefined" is a number. In fact, "undefined" is kind of a Null pointer. Although you are better off with some other error-handling, if you really need to halt and catch fire. If you just don't always want to return something, make the return type a Maybe, or some other kind of multi-value type.) Most of the time, however, this is not even uncomfortable. Sometimes it is, but you should know that it is for your own good.
  • - Concatenate a string with a number - if Python would have a compiler with types, that would've caught this. Without type-checking, that particular code branch has to run to catch this error. There are no tests in the world that can guarantee 100% coverage. (Of course, static typing could not get 100% coverage, either. But silly things like this? It does catch 'em quite well.)

As was written in Why haskell just works, there are three types of mistakes, and a static type system can catch two of them. Dynamic type systems are not so good at it. All in all, types are there to protect the programmer from shooting itself in the foot.

And, as Carmack said: "Anything that is semantically legal will end up in your codebase." - static types will make that "semantically legal" space smaller - which filters out a huge number of bugs.

Of course, the drawback is that it is less comfortable to adhere to the type system. But in the long run, the benefits are so much bigger than this discomfort. Think about it.