Saturday, March 7, 2020

Struggling with new Unity NetCode.

Before pouring out my frustration at the universe I have to say a few introductory words. 

For more than a year now the Unity team is in a process of complete technology stack overhaul. And as a part of this process they are also remastering their multiplayer game packages. They call this new technology stack the "DOTS" (Data-Oriented Technology Stack). Because now it is in an active state of development there is critical shortage of tutorials and documentation. But it is expected that in the near future the DOTS will totally replace old Unity technologies (including networking packages, which are already marked as deprecated).

Now to the sad part. One of the reasons why I switched to Unity from my self-made game-engine was to make Space Strategy into a multiplayer game. When I just started my venture into the Unity networking I thought: "Well, either way, I know nothing about Unity networking, so why should I bother with obsolete technologies? I will just jump right into the new DOTS networking! It is alright that there isn't a lot of documentation and packages are still raw. I will manage somehow".

With that decision made, I:
And even with all that in place I have miserably failed to reproduce the simplest NetCube sample project while following the official tutorial. "Why, oh why doesn't it work?!!! Why there are no error messages anywhere?!", I repeatedly asked myself while comparing my project with the sample one line by line using diff tools.

Long story short, the bug was that entities that were expected to be synchronized between clients and server were not displayed anywhere at all! And the reason turned out to be that I have not installed Hybrid Renderer package into my project as was requested at the very beginning of the NetCube tutorial. That was because when I started the tutorial I thought: "I'll go as simple as possible and concentrate on the networking. Why do I need all the fancy rendering stuff at all?". But who would have thought that this package was absolutely necessary?

Lessons learnt (or reinforced) today:
  1. If one is using someone else's materials and failing, then in 90% of cases the blame is on oneself.
  2. If everyone on the internet except you successfully finished a tutorial, then follow the tutorial more thoroughly.
  3. If tutorial says "Add the A, B, C, and D packages", then, please, add all of them as requested.
Last couple of days I was desperately struggling to reproduce this NetCube sample. I have done it at last. But have I wasted so much time on such a silly mistake. Don't be like me :). Learn on other's mistakes and follow my Unity Space Strategy project on GitHub.


Saturday, January 18, 2020

Hello, dear readers!

Today I would like to share with you some tips regarding debugging the so called "Collection Was Modified Exception".
Often, this problem arises when a collection is changed during its enumeration with a foreach statement. The debugging is quite straightforward:
1) get to the problematic foreach statement;
2) set breakpoints in all the places in a code where the enumerated collection is modified;
3) run through the foreach body.
4) find the place of an unexpected collection modification.

But what to do if the collection modification is not so obvious or if the collection is modified in a lot of places? In these situations I prefer temporarily switching the enumerated collection with a special wrapper that is created with a sole purpose of identifying such a situation.

Lets consider a common System.Collections.Generic.List<T>. To create a wrapper that would automatically identify the "Collection Was Modified" situation follow these steps:

1) Create a stub for a new class ChangedDuringEnumerationMonitoringList<T> : IList<T> with an inner List<T> instance:
1:  class CollectionChangedDuringEnumerationMonitoringList<T> : IList<T>  
2:  {  
3:      readonly List<T> _list = new List<T>();  
4:  }  

2) Automatically implement all the IList<T> members by delegating to the inner _list. For example:
1:  public void Add(T item) 
2:  { 
3:      _list.Add(item); 
4:  } 

3) Implement custom IEnumerator<T> that delegates all its functionality to an original enumerator of a list and tells whether it is in a state of enumeration:
1:  public class NotifyingEnumeratorWrapper : IEnumerator<T>, IEnumerator  
2:  {  
3:      // An original enumerator that is delegated to.  
4:      readonly IEnumerator<T> _typedEnumerator;  
5:    
6:      // Injecting an original enumerator instance in a constructor.  
7:      public NotifyingEnumeratorWrapper(IEnumerator<T> enumerator)  
8:      {  
9:          _typedEnumerator = enumerator;  
10:      }  
11:    
12:      // A property that marks that an enumeration is in a progress.  
13:      public bool IsEnumerating { get; private set; }  
14:    
15:      public void Dispose()  
16:      {  
17:          IsEnumerating = false;  
18:          _typedEnumerator?.Dispose();  
19:      }  
20:    
21:      public bool MoveNext()  
22:      {  
23:          IsEnumerating = true;  
24:          return _enumerator.MoveNext();  
25:      }  
26:    
27:      // The rest of the implementation.  
28:  }  
29:  

4) And finally, modify your custom IList<T> implementation to check whether a collection is modified during an enumeration:
1:  class CollectionChangedDuringEnumerationMonitoringList<T> : IList<T>  
2:  {  
3:      NotifyingEnumeratorWrapper _enumerator;  
4:    
5:      public IEnumerator<T> GetEnumerator()  
6:      {  
7:          _enumerator = new NotifyingEnumeratorWrapper(_list.GetEnumerator());  
8:          return _enumerator;  
9:      }  
10:    
11:      public void Add(T item)  
12:      {  
13:          // Add this call for every IList<T> member that modifies a collection.  
14:          OnCollectionChangedDuringEnumeration();  
15:          _list.Add(item);  
16:      }  
17:    
18:      void OnCollectionChangedDuringEnumeration()  
19:      {  
20:          if (_enumerator != null) {  
21:              if (_enumerator.IsEnumerating) {  
22:                  // Setting a breakpoint here will stop a program exactly at the moment  
23:                  // that collection is modified during an enumeration.
24:                  System.Diagnostics.Debugger.Break();  
25:              }  
26:          }  
27:      }  
28:    
29:      // The rest of the implementation.   
30:  }  
31:    

Now you are all set to go. Switch the List type of your collection that has troubles enumerating for this new custom ChangedDuringEnumerationMonitoringList. Then run your application as usual to reproduce the "Collection Was Modified Exception". And the moment your collection is modified during enumeration your application will stop at the breakpoint. Now you can simply observe the stack trace and get straight to fixing your bug!

Having a custom list such as this in your toolbox makes detecting the source of "Collection Was Modified" problem as easy as two Copy/Paste to replace the collection type and one application run to reproduce the bug.

Feel free to take a look at the full implementation of the ChangedDuringEnumerationMonitoringList on my SpaceStrategy GitHub repository.

What are the techniques you are using to find the cause of the "Collection Was Modified Exception"? Please share them here in comments.

Sunday, January 12, 2020

Now on GitHub!

Hello, everyone!

A few days ago I have published the source code of the SpaceStrategy on GitHub. Feel free to take a look and leave some comments!

I've published the code on GitHub mainly to sharpen my GitHub skills. But don't expect much as the code is pretty old, and now even I am terrified looking at some parts of it. But let's be positive and get some benefits from this situation! It is a great chance to practice some heavy code refactoring and restyling.

First of all, I have decided to bring a code formatting and style into an order:

  • newlines and spaces;
  • ordering of members;
  • naming and typos;
  • etc.

The solution being 130+ files with a style all over the place it is a tough task to accomplish by hand. So I decided to try out some tools.

At first I wanted to try out something new and selected the most recent and the most downloadable tool of the Visual Studio Marketplace for the task. It happened to be the CodeMaid. It was easy to configure and produced good formatting results. The "automatic cleanup on save" feature proved to be quite useful. But in the end, I wasn't able to configure automatic formatting to my liking. Personally, the most troubling was the formatting of properties.

Being a little bit disappointed, I turned back to the Resharper. It not only allowed me minutely configure almost every imaginable setting for automatic code formatting, but also provided a lot of features for manual code refactoring: spellchecking, quick-fixes, recommendations and more. It helped me to automate an enormous amount of tedious work, and I was able to cleanup my code in a matter of hours. Just take a look at recent commits in my SpaceStrategy repository on GitHub and see the results for yourself.

Stay tuned and I will try to provide some new exciting materials about programming my game.