Friday, September 23, 2016

project planning

Sorry for the missed update yesterday. I'm doing some project planning that isn't so easy to sum up in a blog post. I'm going on a small trip and probably won't update here again until sometime midweek.

Wednesday, September 21, 2016

windows buildshell fully operational

Today I got the windows version of my buildshell fully operational. It wasn't too bad, mainly because the buildshell just isn't that complicated. But of course there were still a few hangups. I'm embarrassed to admit that I spent a non-negligible amount of time getting the quotesfile working. The quotesfile is completely pointless (you get an interesting/amusing programming quote when starting the buildshell), but it makes me happy.

Tuesday, September 20, 2016

ubuntu mono env issues resolved (sort of)

Yesterday I found that I could no longer build and run my .net project on ubuntu, after upgrading to 16.04. On investigation this is because my mono environment was also upgraded (to a 4.xxx build). In 4.xxx versions, mono has discontinued support for .NET 3.5. That's awkward, since I'm stuck on 3.5 probably forever (a script upgrade to 4.6 still hasn't even gotten on the Unity technology roadmap).

I tried for most of the day to downgrade to mono 3.12.0. In principle this should be possible. The mono website contains a line about how to do this, which I tried and failed--I added the correct snapshot as my tracked xamarin repository, but I must have mono available in some ubuntu repo as well, because a simple install of mono-complete still added the latest version.

I also found a blog post purporting to explain how to do it. It involved pre-installing a certain set of dependencies, and then installing mono-complete with '-t' to indicate the old version. This also failed in at least two ways.

I wandered down some dark paths trying to find ways to install all the dependencies for old-mono on my machine. Eventually, I more or less gave up, removed all the mono packages, and then installed them back at the newest revision. When I idly tried rebuilding my .net project, it worked!

What seems to be happening is, even though mono 4.xxx no longer supports .net 3.5, it still ships with API stubs for backwards compatibility. Somehow I didn't get them when I did my OS upgrade from 15.10->16.04. But having reinstalled mono (several times, heh), these stubs showed up, letting me build against .NET 3.5, even though monodevelop lists this platform as "uninstalled". Running the unittests works, but it must be going against the 4.5 runtime (as that's all it has).

So I'm back in business, but I don't exactly have warm fuzzies about this. I'd really like to have cross-platform support for developing in this project, but if problems like this keep turning up, the cost may be too high.

Monday, September 19, 2016

laptop setup + xplatform build environment

The linux bug is a thing. There was already a post on the unity forms about it. That's good; I have a workaround so I can stop worrying about it for the moment.

Now I'm working on getting my new laptop set up. I've gotten Unity and subversion install and sync'd down my project. The buildshell that sets things up needs some effort to get fully xplatform, so I'm working on that now. While I worked on that this evening, I discovered that I had broken my ability to build the shared dlls in linux when I upgraded to 16.04. I am now working on straightening that out (it's broken references to the System assembly--even though the assembly exists, right where mono expected it to be).

Friday, September 16, 2016

environment setup + unity bug

In order to further test the Unity bug I saw, I upgraded my local xubuntu install from 15.10 to 16.4. I also upgraded Unity from 5.3.5 to 5.4.1f1. I was still able to reproduce the bug. However, having played around with it some more, I honed in a bit tighter on what exactly I was doing. To add the prefab into the scene, I was dragging it from the Project view, across the Scene view, and into the Hierarchy.

I think somehow when you do this, you get one copy of the prefab added via the Hierarchy, and one that gets added accidentally because of your mouse dragging over the 3d view. Now that I know about this I can work around it.

In other news, my new laptop came today. I have been using a chromebook running crouton/ubuntu as my only transportable development machine (yes, really). It worked surprisingly well for backend programming, but I didn't even consider trying to put Unity on it. My plan is to keep running xubuntu on my desktop, and run Windows 10 on the new laptop. That way I should be able to keep my cross-platform development environment truly cross-platform.

Thursday, September 15, 2016

zero day

Nothing to report today. The plan is to continue sorting out whether the Unity problem I'm facing is Linux specific and whether I need to move development back to Windows. However (without any particular excuse), I didn't get anything done.

Instead of an update, please enjoy a photo-diary of the Chernobyl disaster instead.

Wednesday, September 14, 2016

finished callback pattern, and...unity problems?

First part of the day (the productive part): figured out what was wrong with my unit tests after moving to the new MossDelegate pattern (of course, it was the single-shot change; I hadn't written the unit tests with that in mind and it caused problems that should have been predictable).

Second part of the day: returned to trying to hook up my UI to code in Unity. Only, weird things were happening. I was getting an UnassignedReferenceError on a field in a prefab that totally was filled out (with a GameObject inside the prefab's own dependency tree). I could also see that the GameObject existed in the instantiated prefab, and it showed up in the script's parameters as properly filled out.

Something wasn't adding up, so I started deleting stuff. Eventually I got down to a completely empty scene--not even a camera--and the error was still being thrown. That is to say, a script on a prefab was running and erroring, when--not only wasn't that prefab instantiated, nothing was instantiated.

That seems pretty wrong.

I'm running 5.3.5 on Ubuntu 15 and this is the first time I'm seriously worried I shot myself in the foot by running on an unsupported platform. Things were working so well I got a little complacent. But maybe fun time's over--if this proves to be a linux-specific issue then I think it's back to Windows for me. I will try reproducing with 5.4, and if it still repro's I will try reproducing with the same project on Windows.

I haven't had to fight any real Unity battles yet, so I guess I'm due.


Tuesday, September 13, 2016

new callback pattern

I wound up needing to build out my callback pattern a bit before continuing with UI. The simplest approach (have the game code publish delegates), had so many problems at The Old Company that I was afraid to apply it here. Instead I wound up implementing something similiar to a solution I made at TOC: a generic interface-based substitution for the C# delegate type.

Since I didn't have legacy code to support, I went one step further and made my custom delegate type single-shot--that is, after it calls its callbacks, it blanks its own callback list.

This serves both for stop-loss (leaked memory can't last past the next invocation of the delegate), and also creates nice patterns for the common case where you're registering for something that is only going to happen once (or at least once per time you want to register for it). The obvious example is logging in--you want to start the login process and then hear that it's done, and that's it; you don't have to write deregistration code and then reason about it to make sure it will be called.

Of course you need a way to handle events that you want to continuously listen for. My solution for that is to have the callback reregister with MossDelegate in a finally block (MossDelegate already needed to be re-entrant safe anyway). Because registering is O(1) without generating any allocations, this seems like a reasonable tradeoff.

Monday, September 12, 2016

wiring and assembly

I'm finally at the stage of wiring up the buy UI to events and static data. Tomorrow I think I should have it actually working.

Saturday, September 10, 2016

buy/sell UIX continues

Still hard at work on the Buy Panel. I've drilled down to the BuyEntryDetail dropdown and am slowly filling it out. There's a lot I love about the core idea of this game, but I have to admit it's very data-heavy, requiring these really intense UIs.

Friday, September 9, 2016

UIX Continues

Well, I didn't get as far as I wanted. I think I've mostly solved the "how to use Unity UI tools" problems. Now I'm onto the much more daunting problem domain of "how to make a good UI that holds a lot of information".

Here is what I have so far for my "buy" UI. The goal of this UI is to let you pick goods to take on an Itinerary (a route (possibly multi-city) that you have previously set as a travel plan). The goal is to give all the information necessary to let the player balance risk vs reward ("how much am I prepared to invest? What chance of losing the load to bandits is acceptable?") and also experiment with different route/loadout good combinations. The functional idea is that you get a list of all the things the town sells in a scroll view (the magenta colored area), sorted by sell price value. If you actually want to buy something, you click on the item, and a dropdown appears below it with more information, as well as "Order" and "Cancel" buttons. You can play with your hypothetical loadout as much as you like, and then when you're happy, click "Buy Goods".



Thursday, September 8, 2016

UIX continues

Continued working on the Buy/Sell UI. I felt like I really got some traction today, as most of the Unity UI concepts finally started to sink in. Optimistic I will get a fully working version of the prototype done tomorrow. I will post a screenshot with whatever I have.

Wednesday, September 7, 2016

UIX continues

Nothing much to report today. Kept working on UI design. Repeat all of rant from yesterday.

Tuesday, September 6, 2016

UIX design

I had been putting it off, but it's officially become hard to avoid working on the game UI, particularly the crucial buy/sell panel. I have to admit, UIX problems aren't my favorite. They are intrinsically messy, and whatever answer you come up with, there's a decent chance most people will be unhappy with it. That said, there's no avoiding it--even to get my core game loop going, I need a pretty developed UI. I've been diving into the Unity docs and begun tinkering, but I still have a ways to go before I can build a dynamic UI with the sophistication I require. First pass of this UI may eat up the rest of this week (with me painfully learning the ropes as I go). Hopefully next UI will be much easier.

Friday, September 2, 2016

front-end + back-end integration complete

I finished the 3.5 downgrade of my backend and got it fully working in Unity. The game client and game server are both hosted on a MonoBehaviour on a GameObject; when you log in, the server spins up on a different thread and the client module automatically logs in to it, returning a PlayerState (there's no persistence, so it's just a newly-created PlayerState every time).

StaticData is likewise working (though still not loading from file)--and hooked up to the MapVisualizer.

This was a big step--all the major pieces are working together now. The next step will be to work on the UI for buying/selling, and the interaction for setting a destination. Those pieces encompass the core gameloop.

Thursday, September 1, 2016

downgrading shared dlls to 3.5

Well, I'm dumb. When I started this project I was pulling shared dlls from some earlier work. That earlier solution was building in .NET 4.5. I thought at the time I might have to downgrade someday to 3.5 for compatibility with Unity, but then I forgot all about it. Queue to today, when I actually tried integrating my dlls into my Unity project. Oh yeah, 4.5!

So today was a found-work day. I have a bunch of non-trivial code that relies on 4.5 features, and it took a fair amount of effort to refactor it. In particular, I was using dynamic all over the place in my serialization layer (as followers of this blog from early days might know). I always knew I would have to replace that for iOS compatibility, but I just didn't think I'd have to do it right now.

I was using 'dynamic' because I didn't know how else to handle this problem during deserialization:

  1. Create container type via Activator.CreateInstance (let's say it's a HashSet<int>).
  2. Now I have 'object container'. 
  3. I deserialize the first entry in the HashSet, giving my 'object entry'. 
  4. How do I add 'entry' to 'container' ?
I can't cast 'container' to ICollection<object>, because this interface is not contravariant. That means I can't substitute in types higher in the type hierarchy for the generic parameter. This only makes sense; if I could do that then I could violate the type safety of the container, and add, say, a NetworkSocket to my HashSet of ints. 

There is a trick for this, though, as I discovered today. You can cast to just plain non-generic ICollection. That doesn't care what you do. 

Leveraging that, I was able to scrub out all references to 'dynamic' from my code. On the down-side, my ContainerSerializers class, which was already one of the scarier classes in my code base, has gotten still worse. I started from a noble desire to share as much common serialization logic between container objects as possible, but this has led to some pretty weird entanglements. 

I've also had to resort to some kind of hair-raising reflection to unpack the objects, e.g.:

else if( i_gtype == typeof(Queue<>) ) { stype.GetMethod("Enqueue").Invoke(i_collection, i_obj ); }

--because ICollection has no Add(object)--I can't just cast all these ICollection containers to their common type and then do an add. I have to get weird. Hope that works on iOS.