<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Nitzan Zada</title>
    <description>The latest articles on Forem by Nitzan Zada (@mastern2k3).</description>
    <link>https://forem.com/mastern2k3</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F345778%2Ff564c10d-5426-4548-82ec-9d9a34dd210f.jpg</url>
      <title>Forem: Nitzan Zada</title>
      <link>https://forem.com/mastern2k3</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/mastern2k3"/>
    <language>en</language>
    <item>
      <title>Error Monitoring in Godot using Sentry</title>
      <dc:creator>Nitzan Zada</dc:creator>
      <pubDate>Mon, 23 Mar 2020 09:25:23 +0000</pubDate>
      <link>https://forem.com/mastern2k3/error-monitoring-in-godot-using-sentry-1oio</link>
      <guid>https://forem.com/mastern2k3/error-monitoring-in-godot-using-sentry-1oio</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TJUnlQAh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mmo3rpltsv0emlbl4045.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TJUnlQAh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mmo3rpltsv0emlbl4045.png" alt="Godot and Sentry"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm a big fan of the Godot game engine, and lately, since players have been&lt;br&gt;
testing the game more often, I've decided to add some monitoring solution to&lt;br&gt;
get a better view of what's failing players as they try to play.&lt;/p&gt;

&lt;p&gt;In this post I'll show how to integrate Sentry's .Net SDK in Godot and use&lt;br&gt;
it to receive usage reports and error monitoring.&lt;/p&gt;
&lt;h2&gt;
  
  
  What's Sentry?
&lt;/h2&gt;

&lt;p&gt;Sentry is an open-source error monitoring tool I picked up on a while ago.&lt;/p&gt;

&lt;p&gt;I initially started using it because it was open-source and I was quite the&lt;br&gt;
cheapskate, but, it really is an &lt;strong&gt;awesome&lt;/strong&gt; and &lt;strong&gt;visually delightful&lt;/strong&gt; tool.&lt;/p&gt;

&lt;p&gt;Aside from collecting error reports and alerting you when the application fails,&lt;br&gt;
it makes it simple to integrate information and events &lt;strong&gt;you&lt;/strong&gt; care about in&lt;br&gt;
those reports. Also, it's fairly &lt;strong&gt;easy to integrate&lt;/strong&gt; and get started&lt;br&gt;
collecting data with, &lt;strong&gt;even if&lt;/strong&gt; you're not that much of a friend to coding.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--w00zswrM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/d68h8u3n8gdocato9q1n.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--w00zswrM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/d68h8u3n8gdocato9q1n.jpg" alt="Sentry"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, if you want a dashboard filled with reports about &lt;strong&gt;how your game crashed&lt;/strong&gt;,&lt;br&gt;
to &lt;strong&gt;who&lt;/strong&gt;, &lt;strong&gt;why&lt;/strong&gt; and what were they doing leading to the crash,&lt;br&gt;
&lt;strong&gt;keep reading.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Dependencies
&lt;/h2&gt;

&lt;p&gt;First, let's grab the required binaries. Installing the Sentry SDK collects a&lt;br&gt;
few other assemblies so I added all of them to one &lt;code&gt;packages.config&lt;/code&gt; for&lt;br&gt;
convenience:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;packages&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;package&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"Sentry"&lt;/span&gt; &lt;span class="na"&gt;version=&lt;/span&gt;&lt;span class="s"&gt;"2.1.0"&lt;/span&gt; &lt;span class="na"&gt;targetFramework=&lt;/span&gt;&lt;span class="s"&gt;"net45"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;package&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"Sentry.Protocol"&lt;/span&gt; &lt;span class="na"&gt;version=&lt;/span&gt;&lt;span class="s"&gt;"2.1.0"&lt;/span&gt; &lt;span class="na"&gt;targetFramework=&lt;/span&gt;&lt;span class="s"&gt;"net45"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;package&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"Sentry.PlatformAbstractions"&lt;/span&gt; &lt;span class="na"&gt;version=&lt;/span&gt;&lt;span class="s"&gt;"1.1.0.0"&lt;/span&gt; &lt;span class="na"&gt;targetFramework=&lt;/span&gt;&lt;span class="s"&gt;"net45"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;package&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"System.Collections.Immutable"&lt;/span&gt; &lt;span class="na"&gt;version=&lt;/span&gt;&lt;span class="s"&gt;"1.5.0"&lt;/span&gt; &lt;span class="na"&gt;targetFramework=&lt;/span&gt;&lt;span class="s"&gt;"net45"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/packages&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Run &lt;strong&gt;NuGet&lt;/strong&gt; to fetch all those into your project's &lt;code&gt;./packages/&lt;/code&gt; folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;mono nuget.exe restore
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip&lt;/strong&gt;&lt;br&gt;
If you don't have &lt;strong&gt;NuGet&lt;/strong&gt; yet you can grab it &lt;a href="https://www.nuget.org/downloads"&gt;here&lt;/a&gt;.&lt;br&gt;
The &lt;strong&gt;Windows x86 Commandline&lt;/strong&gt; version is runnable using mono.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Add references to the Sentry assemblies to your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ItemGroup&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;Reference&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"Sentry, Version=2.1.0.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;HintPath&amp;gt;&lt;/span&gt;$(ProjectDir)/packages/Sentry.2.1.0/lib/net461/Sentry.dll&lt;span class="nt"&gt;&amp;lt;/HintPath&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Private&amp;gt;&lt;/span&gt;True&lt;span class="nt"&gt;&amp;lt;/Private&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/Reference&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;Reference&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"Sentry.Protocol, Version=2.1.0.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;HintPath&amp;gt;&lt;/span&gt;$(ProjectDir)/packages/Sentry.Protocol.2.1.0/lib/net46/Sentry.Protocol.dll&lt;span class="nt"&gt;&amp;lt;/HintPath&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Private&amp;gt;&lt;/span&gt;True&lt;span class="nt"&gt;&amp;lt;/Private&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/Reference&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;Reference&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"Sentry.PlatformAbstractions, Version=1.1.0.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;HintPath&amp;gt;&lt;/span&gt;$(ProjectDir)/packages/Sentry.PlatformAbstractions.1.1.0/lib/net471/Sentry.PlatformAbstractions.dll&lt;span class="nt"&gt;&amp;lt;/HintPath&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Private&amp;gt;&lt;/span&gt;True&lt;span class="nt"&gt;&amp;lt;/Private&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/Reference&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;Reference&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"System.Collections.Immutable, Version=1.2.3.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;HintPath&amp;gt;&lt;/span&gt;$(ProjectDir)/packages/System.Collections.Immutable.1.5.0/lib/portable-net45+win8+wp8+wpa81/System.Collections.Immutable.dll&lt;span class="nt"&gt;&amp;lt;/HintPath&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Private&amp;gt;&lt;/span&gt;True&lt;span class="nt"&gt;&amp;lt;/Private&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/Reference&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Initialization
&lt;/h2&gt;

&lt;p&gt;Using Godot we don't really have an initialization section so I created a&lt;br&gt;
dedicated node (here as &lt;code&gt;SentryController&lt;/code&gt;) to hold the Sentry initialization&lt;br&gt;
logic.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kI4Pvo82--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/12yueoxa4frfuxjmhm4u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kI4Pvo82--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/12yueoxa4frfuxjmhm4u.png" alt="Sentry Controller Node"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Warning&lt;/strong&gt;&lt;br&gt;
Pay close attention to the node placement in the scene tree.&lt;br&gt;
The Sentry controller node must come before any application nodes.&lt;br&gt;
Godot invokes their &lt;code&gt;_Ready()&lt;/code&gt; methods according to their ordering on the tree,&lt;br&gt;
and any exception thrown before SDK init will &lt;strong&gt;not be reported&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After creating an account and a project Sentry will suggest an initialization&lt;br&gt;
clause with your project's &lt;strong&gt;Dsn&lt;/strong&gt;, similar to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SentrySdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://451cf9b0fd9e4f0294a0d15b6c36bce2@sentry.io/5170198"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// App code&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip&lt;/strong&gt;&lt;br&gt;
After creating a project &lt;a href="https://docs.sentry.io/error-reporting/quickstart/?platform=csharp"&gt;this page&lt;/a&gt; will contain code examples with your project's Dsn in place.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So after adding it to your node it should look somewhat like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SentryController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Node&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;_Ready&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="n"&gt;SentrySdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dsn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Dsn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://451cf9b0fd9e4f0294a0d15b6c36bce2@sentry.io/5170198"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Error reporting
&lt;/h2&gt;

&lt;p&gt;Now that the client is set up, any unhandled exceptions thrown will get&lt;br&gt;
reported to the sentry API, and appear on your dashboard with a full trace.&lt;/p&gt;

&lt;p&gt;For example, lets set a button that throws an exception:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;App&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Node2D&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;_on_CrashButton_pressed&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Oh lord jesus it's a fire!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Which after getting pressed will cause an error to appear on your issue&lt;br&gt;
dashboard.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Xau5ejEK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/rcit8rgoxmwda5wlw2gg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Xau5ejEK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/rcit8rgoxmwda5wlw2gg.png" alt="Error Issue"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Breadcrumbs
&lt;/h2&gt;

&lt;p&gt;A neat feature of Sentry that I had to cover.&lt;/p&gt;

&lt;p&gt;This allows you to log the user's behavior, potentially, leading to the error.&lt;br&gt;
Giving you a better view into what exactly happened before the crash.&lt;/p&gt;

&lt;p&gt;The code is fairly simple, for example, lets log a button click &lt;em&gt;(exciting, I&lt;br&gt;
know :P)&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;App&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Node2D&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="p"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;_on_AwesomeButton_pressed&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;SentrySdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddBreadcrumb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Awesome button clicked"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After a few clicks on this button, and then, a hit to the ol' crashing button,&lt;br&gt;
we'll get this neat report:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qfSum2HV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/3bvo2o91oi60cijrxoiq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qfSum2HV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/3bvo2o91oi60cijrxoiq.png" alt="Sentry breadcrumbs"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Example Project
&lt;/h2&gt;

&lt;p&gt;I've prepared an example project demonstrating the Sentry integration here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/mastern2k3/godot-sentry-example"&gt;https://github.com/mastern2k3/godot-sentry-example&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is a small caveat for people looking to export for Android, read ahead.&lt;/p&gt;
&lt;h2&gt;
  
  
  Android
&lt;/h2&gt;

&lt;p&gt;Although making all this goodness to work on Android should've been an export&lt;br&gt;
prest away, things turned out to be trickier.&lt;/p&gt;

&lt;p&gt;The Android prest kept failing the mono assembly preparation phase because of&lt;br&gt;
an apparent missing assembly named &lt;code&gt;System.Web&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ERROR: get_assembly_dependencies: Cannot load assembly (refonly): 'System.Web'.
   At: modules/mono/editor/godotsharp_export.cpp:93.
ERROR: get_assembly_dependencies: Cannot load one of the dependencies for the assembly: 'Sentry'.
   At: modules/mono/editor/godotsharp_export.cpp:98.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Finding the answer to this little bugger took me a good two days of research,&lt;br&gt;
trial and error, so I'll cut to the chase.&lt;/p&gt;

&lt;p&gt;After digging through the &lt;a href="https://github.com/getsentry/sentry-dotnet"&gt;.Net Sentry SDK&lt;/a&gt; I found out that the &lt;code&gt;System.Web&lt;/code&gt;&lt;br&gt;
assembly (required by the &lt;code&gt;net461&lt;/code&gt; variant of the &lt;code&gt;Sentry.dll&lt;/code&gt; assembly) is not&lt;br&gt;
a strict requirement, and that on other framework outputs its reference is&lt;br&gt;
omitted.&lt;/p&gt;

&lt;p&gt;So, on the last trial, I ended up &lt;a href="https://github.com/mastern2k3/sentry-dotnet"&gt;forking the SDK&lt;/a&gt; in an attempt to produce a&lt;br&gt;
&lt;code&gt;Sentry.dll&lt;/code&gt; that did not reference &lt;code&gt;System.Web&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can download a compiled version of it &lt;a href="https://github.com/mastern2k3/sentry-dotnet/releases/tag/2.1.0-godot"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Important: The example project references the compiled fork version so it&lt;br&gt;
appears as such in the &lt;code&gt;.csproj&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Reference&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"Sentry, Version=2.1.0.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;HintPath&amp;gt;&lt;/span&gt;$(ProjectDir)/../forks/sentry-dotnet/src/Sentry/bin/Release/net461/Sentry.dll&lt;span class="nt"&gt;&amp;lt;/HintPath&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- &amp;lt;HintPath&amp;gt;$(ProjectDir)/packages/Sentry.2.1.0/lib/net461/Sentry.dll&amp;lt;/HintPath&amp;gt; --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;Private&amp;gt;&lt;/span&gt;True&lt;span class="nt"&gt;&amp;lt;/Private&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Reference&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If you're not interested in any of this Android nonsense you can comment /&lt;br&gt;
uncomment whichever line fits your needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other Sentry related stuff you should check out
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.sentry.io/enriching-error-data/scopes/?platform=csharp"&gt;Sentry Scopes&lt;/a&gt; - these enable you to add more info (like user identification)&lt;br&gt;
as application usage progresses.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.sentry.io/server/"&gt;Self hosting Sentry&lt;/a&gt; - yeah, you can do that.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>godot</category>
      <category>sentry</category>
      <category>csharp</category>
      <category>gamedev</category>
    </item>
    <item>
      <title>Three Months In</title>
      <dc:creator>Nitzan Zada</dc:creator>
      <pubDate>Fri, 13 Mar 2020 22:57:31 +0000</pubDate>
      <link>https://forem.com/mastern2k3/three-months-in-1822</link>
      <guid>https://forem.com/mastern2k3/three-months-in-1822</guid>
      <description>&lt;p&gt;I figured it's time to start recording what I'm up to with &lt;strong&gt;Throne of Mithrill&lt;/strong&gt;, so, here it goes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZlGXXRMJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/f58htht206ry2k0ha9kf.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZlGXXRMJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/f58htht206ry2k0ha9kf.gif" alt="ToM basics"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Although C# has been giving me a lot of trouble I've managed to design things stable enough to start putting in some of the basic mechanics, although I might need to port everything to either Rust or Go.&lt;/p&gt;

&lt;p&gt;First were the movement and engagement "orders" (as they once were called) got implemented.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5LP_S_NR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/o961tvcy1dfm4ipj57xm.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5LP_S_NR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/o961tvcy1dfm4ipj57xm.gif" alt="Move and attack order"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, the server and aggression system, allowing enemy mobs to strike back when a player entered proximity.&lt;br&gt;&lt;br&gt;
If you're observant enough you'll notice the exclamation effect over the enemy knight guy's head as he approaches the player and a focusing circle on the triggering player.&lt;/p&gt;

&lt;p&gt;The exclamation mark came in as an indication I put in to test the message was being processed correctly, I added the rotating circle later to emphasize and alarm the player.&lt;/p&gt;

&lt;p&gt;It was important for me that the game would be built designed around the&lt;br&gt;
multiplayer experience, so, synchronization and match authorization came almost immediately.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kt-fuL-3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6c6ckvk3tfcog83d1gx1.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kt-fuL-3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6c6ckvk3tfcog83d1gx1.gif" alt="Multiplayer and ownership"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since at this point the characters' ownership is given semi-randomly by the server, I found it helpful to add &lt;strong&gt;ownership indicators&lt;/strong&gt;, however crude.&lt;/p&gt;

&lt;p&gt;You can also notice the movement, auto-attack and auto-heal command interface.&lt;br&gt;&lt;br&gt;
The like will snap and change colors according to the default offensive / supportive ability of a character (in case they have one) or blue for simple movement.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--K-GvJWgQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mk4jqy2jhamqqskqiuwp.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--K-GvJWgQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mk4jqy2jhamqqskqiuwp.gif" alt="AOE abilities"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Aside from the default offensive / supportive auto-abilities (which could later be selected by the player), characters can also use actionable abilities.&lt;br&gt;&lt;br&gt;
I started with a simple circular AOE as a proof of concept but more will come.&lt;/p&gt;

&lt;p&gt;A casting system is also in place, enforcing a vulnerability when casting.&lt;/p&gt;

&lt;h2&gt;
  
  
  More things in the works
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Aggro system&lt;/strong&gt; - Although it's hard to notice there is an aggro system I'm&lt;br&gt;
work-shopping.&lt;br&gt;&lt;br&gt;
Damage afflictions and heals cause enemies to redirect their&lt;br&gt;
attention. It is very sensitive at the moment, causing redirections too often.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Looting system&lt;/strong&gt; - You might have noticed enemies dropping coins when they die&lt;br&gt;
or the coins in the middle of the screen, those are collectible and a recent&lt;br&gt;
refactoring caused the characters to stop collecting them.&lt;br&gt;
Later enemies will drop other kinds of loot and one-time usables.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Enemy playbooks&lt;/strong&gt; - When engaged, enemies execute a "playbook" -&lt;br&gt;
a highly customizable and pluggable state machine.&lt;br&gt;&lt;br&gt;
Currently said state machines are very simple, enemies start auto-attacking&lt;br&gt;
their aggressor and use an ability periodically, but, soon I want to add enemy&lt;br&gt;
healers which will put my design to the test.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Trajectory
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Platforms&lt;/strong&gt; - I still have a lot to figure out regarding &lt;strong&gt;Godot&lt;/strong&gt;. C# has&lt;br&gt;
been giving me trouble, so I'm looking into utilizing the GDNative bindings with&lt;br&gt;
either Go or Rust.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Complex playbooks&lt;/strong&gt; - Enemies are not really threatening at the moment, so I&lt;br&gt;
want to introduce a support-type enemy and an enrage mechanic.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Buff system&lt;/strong&gt; - As part of introducing an enrage mechanic I'll be adding a&lt;br&gt;
basic buff system, allowing me to apply effects for variable periods of time.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bosses&lt;/strong&gt; - Once the buff system and new playbooks are in place I'll start&lt;br&gt;
experimenting with more complex maps and bosses.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I am set to build a team-oriented game and I want bosses to play an important&lt;br&gt;
  role, soon I'll be posting some drafts for the first boss encounter.&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>mmorpg</category>
      <category>godot</category>
      <category>go</category>
    </item>
  </channel>
</rss>
