Tuesday, July 26, 2016
moving
Just worked on my apartment move today. I think I'm going to be unable to accomplish anything of use until this Sunday at the earliest. I will probably skip on updates until then.
Monday, July 25, 2016
core game classes
I started blocking out core game classes, and worked on the synchronization strategy for PlayerState (how it will update on the server with validation, and how it will roll back on validation failure).
Because of my upcoming move I sold my AC yesterday. It's been pretty muggy today--hard to adjust. Looking forward to going now.
Because of my upcoming move I sold my AC yesterday. It's been pretty muggy today--hard to adjust. Looking forward to going now.
Friday, July 22, 2016
PeekableStream, AsyncMemoryStream, NetConnection
Yesterday and today.
I've pretty much got my application transport layer functioning at levels acceptable for the prototype. I can hand off an object to my NetConnection object, and it will asynchronously serialize that object into its outgoing AsyncMemoryStream. The other side can then reconstitute it; the actual deserialization also happens on a worker thread, so all the main thread has to do is just pop off an object reference from a queue.
Yesterday things were not going well. Despite all my careful unit tests, when I did a fully assembled asynchronous test of sending objects, something was causing the stream to be garbage on the other end. Of course I was sure it must be a multithread problem--was I somehow kicking off two pool threads that were doing sends simultaneously? I fell asleep racking my brain about it.
This morning I woke up and had the answer. It wasn't a MT problem at all. I had misunderstood the expected behavior of a stream. If you tried to read 100 bytes from my AsyncMemoryStream, and there were 51 available, it would give you back 51 (the stream interface returns how many bytes are actually read). But that was wrong. You should only do a short read when you hit EndOfStream, and that's not the same as "oh there just aren't that many bytes right now".
I couldn't understand why I wasn't getting IOExceptions out of the BinaryReader that wrapped the stream, though, since that what happened when I did a trivial test, calling reader.Read(int32) with only 2 bytes in the stream. But it turns out the behavior of BinaryReader is inconsistent: if you read a string, or an int, you will get an IOException, but you try to read 'n' bytes, it will short read without error. This is explained in the MSDN docs, but I missed it. I have added in more unit tests around this.
I've pretty much got my application transport layer functioning at levels acceptable for the prototype. I can hand off an object to my NetConnection object, and it will asynchronously serialize that object into its outgoing AsyncMemoryStream. The other side can then reconstitute it; the actual deserialization also happens on a worker thread, so all the main thread has to do is just pop off an object reference from a queue.
Yesterday things were not going well. Despite all my careful unit tests, when I did a fully assembled asynchronous test of sending objects, something was causing the stream to be garbage on the other end. Of course I was sure it must be a multithread problem--was I somehow kicking off two pool threads that were doing sends simultaneously? I fell asleep racking my brain about it.
This morning I woke up and had the answer. It wasn't a MT problem at all. I had misunderstood the expected behavior of a stream. If you tried to read 100 bytes from my AsyncMemoryStream, and there were 51 available, it would give you back 51 (the stream interface returns how many bytes are actually read). But that was wrong. You should only do a short read when you hit EndOfStream, and that's not the same as "oh there just aren't that many bytes right now".
I couldn't understand why I wasn't getting IOExceptions out of the BinaryReader that wrapped the stream, though, since that what happened when I did a trivial test, calling reader.Read(int32) with only 2 bytes in the stream. But it turns out the behavior of BinaryReader is inconsistent: if you read a string, or an int, you will get an IOException, but you try to read 'n' bytes, it will short read without error. This is explained in the MSDN docs, but I missed it. I have added in more unit tests around this.
Wednesday, July 20, 2016
PeekableStream
Almost finished PeekableStream today. I think I'm one unit test away from completion. I thought this would be a 3 hour class, instead most of two days! Shows what I know.
Tuesday, July 19, 2016
NetConnection, PeekableStream
I was able to finish up my AsyncMemoryStream today, and with it get my NetConnection class working in unit test. Pretty neat to see my application transport layer shuttling objects around over streams. However when I tried sending a non-trivial compound object, I immediately got a failure: the Seek method of my AsyncMemoryStream was being called, and wasn't implemented.
I could implement that method, but then I remembered that I shouldn't; you can't seek on a NetStream, so no seeking on AsyncMemoryStreams either. Being able to Seek (at least enough to peek 4 bytes at the end of a stream) is a required feature for my serialization layer. I remember (months and months ago), I decided I'd implement a PeekableStream to accommodate this whenever I got to the level of actually using my serialization code.
Well, the day has come. Spent rest of day working on a PeekableStream. You compose it with non seeking streams, and it provides a limited ability to seek back from END (just enough to peek something like a BinTag off the end).
I could implement that method, but then I remembered that I shouldn't; you can't seek on a NetStream, so no seeking on AsyncMemoryStreams either. Being able to Seek (at least enough to peek 4 bytes at the end of a stream) is a required feature for my serialization layer. I remember (months and months ago), I decided I'd implement a PeekableStream to accommodate this whenever I got to the level of actually using my serialization code.
Well, the day has come. Spent rest of day working on a PeekableStream. You compose it with non seeking streams, and it provides a limited ability to seek back from END (just enough to peek something like a BinTag off the end).
Monday, July 18, 2016
AsyncMemoryStream
More fun with my MT memory-based stream. Threaded systems are pretty exciting to write, in a "riding a motorcycle naked the wrong direction down the highway" sort of way.
I finished the async Stream methods (BeginRead/BeginWrite) and wrote some good unit tests for them, although in retrospect I'm not even positive I'm going to use them.
I'm adding an accessor now that lets the user know if bytes are available to be read on the stream. Unfortunately I'm using a volatile bool. I understand volatile to be the spawn of beezlebub, but I'm not sure what a better approach would be. I can't just ask for the length of the stream, because that takes a monitor lock, and that could block for the whole duration of a Write--rather defeating the point.
I finished the async Stream methods (BeginRead/BeginWrite) and wrote some good unit tests for them, although in retrospect I'm not even positive I'm going to use them.
I'm adding an accessor now that lets the user know if bytes are available to be read on the stream. Unfortunately I'm using a volatile bool. I understand volatile to be the spawn of beezlebub, but I'm not sure what a better approach would be. I can't just ask for the length of the stream, because that takes a monitor lock, and that could block for the whole duration of a Write--rather defeating the point.
Sunday, July 17, 2016
AsyncMemoryStream
Well, that was fun. I haven't stayed up late hacking in a while.
The plan for the prototype is to be client-only, no persistence. But of course I can't help thinking about the future. I wanted to make a fairly "real" feeling application transport layer that operated on the Stream level. For now, the client's input and output streams will just be hooked up to a server module that is running in-process.
To make that work, though, I needed a thread-aware Stream that acted like FIFO byte queue, and I don't think there is anything like that out of the box in C#.
So here I am working on one. Most of the synchronous operations are in place, but I still have some unit test failures around cases where the internal ring buffer needs to grow. I'd really like to get the async Read/Write methods working asynchronously too (via deferring the work to the ThreadPool). I think that be a good "broom" for async bugs that might not otherwise show up until much later.
The plan for the prototype is to be client-only, no persistence. But of course I can't help thinking about the future. I wanted to make a fairly "real" feeling application transport layer that operated on the Stream level. For now, the client's input and output streams will just be hooked up to a server module that is running in-process.
To make that work, though, I needed a thread-aware Stream that acted like FIFO byte queue, and I don't think there is anything like that out of the box in C#.
So here I am working on one. Most of the synchronous operations are in place, but I still have some unit test failures around cases where the internal ring buffer needs to grow. I'd really like to get the async Read/Write methods working asynchronously too (via deferring the work to the ThreadPool). I think that be a good "broom" for async bugs that might not otherwise show up until much later.
Saturday, July 16, 2016
workspace layout, core classes
Mostly finished assembling the new project workspace for my prototype. Design work on using my mossbin serialization format in this project, and on what some core of the core NetRequest / NetResponse classes might look like (even though the prototype is client-only, the architecture is still client-server).
Friday, July 15, 2016
planning, enums
Sorry for the long silence; I was on vacation this week, returning to work today.
Today I finished implementing my solution for enums. I decided to go with semantically self-contained enums, which is an idea I've found attractive for a while. Basically, the enum is a 64-bit integer. The integer value is formed from packing 12 characters together using a special 5-bit encoding. That's a little better than DOS filenames, even! This ducks a lot of annoying questions that come up with enums, like how to prevent re-enumerating a value, and how to coordinate enum value assignment across multiple developers.
I worked on this now because I'm almost ready to start mocking up game data. Pretty excited about that.
Today I finished implementing my solution for enums. I decided to go with semantically self-contained enums, which is an idea I've found attractive for a while. Basically, the enum is a 64-bit integer. The integer value is formed from packing 12 characters together using a special 5-bit encoding. That's a little better than DOS filenames, even! This ducks a lot of annoying questions that come up with enums, like how to prevent re-enumerating a value, and how to coordinate enum value assignment across multiple developers.
I worked on this now because I'm almost ready to start mocking up game data. Pretty excited about that.
Thursday, July 7, 2016
mapviz
Continued working on map visualization in my current prototype project. Not a lot to show for today.
Wednesday, July 6, 2016
prototyping
I felt strongly enough about the state of my current writeup to start prototyping. In a slightly creepy way, it reminds me of the project at The Old Job (at least in that it has map, and would work well for async multiplayer and mobile). I guess you can never really escape your past.
I got the basic interaction in the map screen working, and I've drawn out a set of three UI screens that I'm going to try to build as part of the prototype. That should be enough to understand whether there's any fun to be had here.
I got the basic interaction in the map screen working, and I've drawn out a set of three UI screens that I'm going to try to build as part of the prototype. That should be enough to understand whether there's any fun to be had here.
Tuesday, July 5, 2016
scenario design, art
Yesterday and today, kept plugging away on scenario design, and spent a bit of energy working on a basic blockman to use for testing animation. While I like the scenario I've been writing up, and I think it's promising for the sort of narrative/puzzle game I wanted to work on my first time out, I'm worried that even on paper it might be too expansive. On the other hand, this is the third scenario I've worked on, and if I keep going like this I won't have much to show besides a large pile of half-written game summaries.
I will settle down on something eventually. Small is hard.
I will settle down on something eventually. Small is hard.
Friday, July 1, 2016
scenario design
Not too much to report for today. More notebook scribbling / scenario design work, mainly. I will try to get some good productivity in on Saturday to make up for it.
Subscribe to:
Posts (Atom)