<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://qbb84.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://qbb84.github.io/" rel="alternate" type="text/html" /><updated>2026-04-13T12:24:06+00:00</updated><id>https://qbb84.github.io/feed.xml</id><title type="html">qbb84</title><subtitle>Driven by a peculiar fascination with patterns, I find myself at the intersection of creativity and code. Exploring the intricacies of algorithms and the artistry of design, I embark on a journey where patterns aren&apos;t just observed; they are woven into the fabric of my work.
&lt;p style=&quot;font-size: 12px;&quot;&gt;&lt;i&gt; Please note: due to safety and contractual considerations, some of my work and projects cannot be made public.&lt;/p&gt;
</subtitle><author><name>qbb84</name></author><entry><title type="html">Hytale Rhythm</title><link href="https://qbb84.github.io/hytale-rhythm" rel="alternate" type="text/html" title="Hytale Rhythm" /><published>2026-02-01T00:00:00+00:00</published><updated>2026-02-01T00:00:00+00:00</updated><id>https://qbb84.github.io/hytale-rhythm</id><content type="html" xml:base="https://qbb84.github.io/hytale-rhythm"><![CDATA[<p><em>A dev log covering rhythm, codenamed: Pulse — a Hytale server plugin that performs offline audio analysis to produce a beat map, then drives beat-synchronised in-world visual effects at runtime using Hytale’s server API.</em></p>

<h2 id="the-problem">The Problem</h2>

<p>Hytale has no concept of music-driven world state. Sound events play, the world does its thing, and the two are entirely decoupled. The goal of Pulse was to bridge that gap — to make the game world <em>react</em> to music in real time, with effects timed precisely to beats, onsets, section changes, and even individual words.</p>

<p>The constraint that shaped everything: Hytale’s server runs on the main game thread. Any heavy computation done at runtime would introduce lag. Audio analysis — spectral decomposition, onset detection, ML-based transcription — is expensive. It cannot happen live.</p>

<p>The solution is a two-stage pipeline:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[Offline]  Audio file → Python analyser → Beat map JSON
[Runtime]  Beat map JSON → Pulse event dispatcher → World effects
</code></pre></div></div>

<p>The hard work happens offline, once per song. Runtime is just reading timestamps from a file and dispatching events.</p>

<hr />

<h2 id="stage-1--the-python-analyser">Stage 1 — The Python Analyser</h2>

<p>The analyser (<code class="language-plaintext highlighter-rouge">analyze.py</code>) takes an audio file and produces a JSON beat map containing everything the plugin needs to drive effects. It uses <code class="language-plaintext highlighter-rouge">librosa</code> for audio analysis and optionally <code class="language-plaintext highlighter-rouge">whisperx</code> or <code class="language-plaintext highlighter-rouge">whisper</code> for lyric alignment.</p>

<h3 id="tempo-detection">Tempo Detection</h3>

<p>Reliable tempo detection is harder than it sounds — especially for hip-hop and electronic music where the perceived BPM can be half or double the detected value. I implemented a voting system across five independent methods:</p>

<ul>
  <li>Standard onset envelope tempo estimation</li>
  <li>Percussive component with hip-hop prior</li>
  <li>Low-frequency (kick drum) autocorrelation</li>
  <li>Fourier tempogram peak detection</li>
  <li>Standard <code class="language-plaintext highlighter-rouge">beat_track</code> fallback</li>
</ul>

<p>Candidates are binned into a histogram and the median of the peak cluster is returned. A manual BPM override is also supported for cases where the voting system drifts.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">get_tempo_with_voting</span><span class="p">(</span><span class="n">y</span><span class="p">,</span> <span class="n">sr</span><span class="p">,</span> <span class="n">hop_length</span><span class="p">,</span> <span class="n">y_percussive</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
    <span class="n">candidates</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="c1"># ... five independent estimates ...
</span>    <span class="n">hist</span><span class="p">,</span> <span class="n">bin_edges</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">histogram</span><span class="p">(</span><span class="n">candidates</span><span class="p">,</span> <span class="n">bins</span><span class="o">=</span><span class="n">np</span><span class="p">.</span><span class="n">arange</span><span class="p">(</span><span class="mi">60</span><span class="p">,</span> <span class="mi">180</span><span class="p">,</span> <span class="mi">5</span><span class="p">))</span>
    <span class="n">peak_bin</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">argmax</span><span class="p">(</span><span class="n">hist</span><span class="p">)</span>
    <span class="n">bin_center</span> <span class="o">=</span> <span class="p">(</span><span class="n">bin_edges</span><span class="p">[</span><span class="n">peak_bin</span><span class="p">]</span> <span class="o">+</span> <span class="n">bin_edges</span><span class="p">[</span><span class="n">peak_bin</span> <span class="o">+</span> <span class="mi">1</span><span class="p">])</span> <span class="o">/</span> <span class="mi">2</span>
    <span class="n">near_peak</span> <span class="o">=</span> <span class="n">candidates</span><span class="p">[</span><span class="n">np</span><span class="p">.</span><span class="nb">abs</span><span class="p">(</span><span class="n">candidates</span> <span class="o">-</span> <span class="n">bin_center</span><span class="p">)</span> <span class="o">&lt;</span> <span class="mi">10</span><span class="p">]</span>
    <span class="k">return</span> <span class="nb">float</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">median</span><span class="p">(</span><span class="n">near_peak</span><span class="p">))</span>
</code></pre></div></div>

<h3 id="frequency-separated-onset-detection">Frequency-Separated Onset Detection</h3>

<p>Rather than treating the audio as a single signal, the analyser separates it into frequency bands — bass (kick drum), mids (snare, melodic), highs (hi-hats, cymbals), and vocals — and detects onsets independently in each:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">y_bass</span>  <span class="o">=</span> <span class="n">bandpass_filter</span><span class="p">(</span><span class="n">y_percussive</span><span class="p">,</span> <span class="n">sr</span><span class="p">,</span> <span class="mi">20</span><span class="p">,</span> <span class="mi">150</span><span class="p">,</span> <span class="n">hop_length</span><span class="p">)</span>
<span class="n">y_mids</span>  <span class="o">=</span> <span class="n">bandpass_filter</span><span class="p">(</span><span class="n">y</span><span class="p">,</span> <span class="n">sr</span><span class="p">,</span> <span class="mi">500</span><span class="p">,</span> <span class="mi">2000</span><span class="p">,</span> <span class="n">hop_length</span><span class="p">)</span>
<span class="n">y_highs</span> <span class="o">=</span> <span class="n">bandpass_filter</span><span class="p">(</span><span class="n">y</span><span class="p">,</span> <span class="n">sr</span><span class="p">,</span> <span class="mi">4000</span><span class="p">,</span> <span class="mi">16000</span><span class="p">,</span> <span class="n">hop_length</span><span class="p">)</span>
<span class="n">y_vocals</span> <span class="o">=</span> <span class="n">bandpass_filter</span><span class="p">(</span><span class="n">y_harmonic</span><span class="p">,</span> <span class="n">sr</span><span class="p">,</span> <span class="mi">300</span><span class="p">,</span> <span class="mi">3500</span><span class="p">,</span> <span class="n">hop_length</span><span class="p">)</span>
</code></pre></div></div>

<p>This means the plugin can drive different effects for different frequency events — bass onsets trigger ground-level effects, hi-hat onsets trigger rapid upper-register effects, vocal onsets trigger word-aligned effects.</p>

<h3 id="continuous-curves">Continuous Curves</h3>

<p>Beyond discrete events, the beat map also contains continuous curves sampled at regular intervals:</p>

<ul>
  <li><strong>Energy curve</strong> — normalised RMS envelope, 50ms samples</li>
  <li><strong>Spectral flux</strong> — rate of change in the frequency spectrum</li>
  <li><strong>Pitch contour</strong> — normalised pitch (0–1) with direction (rising/falling/stable)</li>
  <li><strong>Frequency bands</strong> — per-band energy (sub, bass, lowMid, mid, highMid, high) for equaliser-style effects</li>
</ul>

<p>These enable smooth interpolation between states rather than sharp on/off transitions.</p>

<h3 id="section-detection--structural-analysis">Section Detection &amp; Structural Analysis</h3>

<p>The analyser uses <code class="language-plaintext highlighter-rouge">librosa.segment.agglomerative</code> on combined MFCC and chroma features to find structural boundaries, then classifies each section:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">features</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">vstack</span><span class="p">([</span>
    <span class="n">librosa</span><span class="p">.</span><span class="n">util</span><span class="p">.</span><span class="n">normalize</span><span class="p">(</span><span class="n">mfcc</span><span class="p">,</span> <span class="n">axis</span><span class="o">=</span><span class="mi">1</span><span class="p">),</span>
    <span class="n">librosa</span><span class="p">.</span><span class="n">util</span><span class="p">.</span><span class="n">normalize</span><span class="p">(</span><span class="n">chroma</span><span class="p">,</span> <span class="n">axis</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="p">])</span>
<span class="n">bounds</span> <span class="o">=</span> <span class="n">librosa</span><span class="p">.</span><span class="n">segment</span><span class="p">.</span><span class="n">agglomerative</span><span class="p">(</span><span class="n">features</span><span class="p">,</span> <span class="n">k</span><span class="o">=</span><span class="n">num_sections</span><span class="p">)</span>
</code></pre></div></div>

<p>A recurrence matrix identifies which sections repeat — chorus sections appear multiple times and get flagged accordingly. Each section is classified as intro, verse, chorus, hook, bridge, buildup, drop, breakdown, or outro, with a mood label (energetic, aggressive, melancholic, peaceful, dark, happy, etc.) derived from energy, brightness, and tempo.</p>

<h3 id="lyric-alignment">Lyric Alignment</h3>

<p>If lyrics are provided — either as a file or fetched from the Genius API — the analyser uses WhisperX for forced alignment:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">result</span> <span class="o">=</span> <span class="n">whisperx</span><span class="p">.</span><span class="n">align</span><span class="p">(</span>
    <span class="n">result</span><span class="p">[</span><span class="s">"segments"</span><span class="p">],</span> <span class="n">model_a</span><span class="p">,</span> <span class="n">metadata</span><span class="p">,</span> <span class="n">audio</span><span class="p">,</span> <span class="n">device</span><span class="p">,</span>
    <span class="n">return_char_alignments</span><span class="o">=</span><span class="bp">False</span>
<span class="p">)</span>
</code></pre></div></div>

<p>The key insight in the alignment system: we trust our lyrics for the <em>text</em>, but use the transcription for the <em>timing</em>. A fuzzy matching pass maps known correct words to their nearest transcribed timestamp, handling the minor errors Whisper inevitably makes. The result is word-level timestamps with 100% textual accuracy.</p>

<p>The analyser is compiled into a platform-specific binary (Windows/Mac/Linux) via PyInstaller and called from the plugin as a subprocess:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">ProcessBuilder</span> <span class="n">pb</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ProcessBuilder</span><span class="o">(</span>
    <span class="n">getAnalyzerPath</span><span class="o">(),</span>
    <span class="n">audioFile</span><span class="o">.</span><span class="na">getAbsolutePath</span><span class="o">(),</span>
    <span class="n">outputFile</span><span class="o">.</span><span class="na">getAbsolutePath</span><span class="o">(),</span>
    <span class="s">"--bpm"</span><span class="o">,</span> <span class="nc">String</span><span class="o">.</span><span class="na">valueOf</span><span class="o">(</span><span class="n">bpm</span><span class="o">),</span>
    <span class="s">"--song"</span><span class="o">,</span> <span class="n">songTitle</span><span class="o">,</span>
    <span class="s">"--artist"</span><span class="o">,</span> <span class="n">artist</span>
<span class="o">);</span>
</code></pre></div></div>

<hr />

<h2 id="stage-2--the-hytale-plugin">Stage 2 — The Hytale Plugin</h2>

<h3 id="the-beat-map">The Beat Map</h3>

<p><code class="language-plaintext highlighter-rouge">SongBeatMap</code> is a flat POJO that mirrors the JSON output exactly:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">SongBeatMap</span> <span class="o">{</span>
    <span class="kd">public</span> <span class="kt">double</span> <span class="n">bpm</span><span class="o">;</span>
    <span class="kd">public</span> <span class="kt">double</span> <span class="n">duration</span><span class="o">;</span>
    <span class="kd">public</span> <span class="nc">String</span> <span class="n">mood</span><span class="o">;</span>
    <span class="kd">public</span> <span class="kt">double</span><span class="o">[]</span> <span class="n">beatTimestamps</span><span class="o">;</span>
    <span class="kd">public</span> <span class="kt">double</span><span class="o">[]</span> <span class="n">downbeats</span><span class="o">;</span>
    <span class="kd">public</span> <span class="kt">double</span><span class="o">[]</span> <span class="n">eighthNotes</span><span class="o">;</span>
    <span class="kd">public</span> <span class="kt">double</span><span class="o">[]</span> <span class="n">sixteenthNotes</span><span class="o">;</span>
    <span class="kd">public</span> <span class="nc">Onset</span><span class="o">[]</span> <span class="n">bass</span><span class="o">;</span>
    <span class="kd">public</span> <span class="nc">Onset</span><span class="o">[]</span> <span class="n">mids</span><span class="o">;</span>
    <span class="kd">public</span> <span class="nc">Onset</span><span class="o">[]</span> <span class="n">highs</span><span class="o">;</span>
    <span class="kd">public</span> <span class="nc">Section</span><span class="o">[]</span> <span class="n">sections</span><span class="o">;</span>
    <span class="kd">public</span> <span class="nc">Buildup</span><span class="o">[]</span> <span class="n">buildups</span><span class="o">;</span>
    <span class="kd">public</span> <span class="nc">Drop</span><span class="o">[]</span> <span class="n">drops</span><span class="o">;</span>
    <span class="kd">public</span> <span class="nc">EnergySample</span><span class="o">[]</span> <span class="n">energyCurve</span><span class="o">;</span>
    <span class="kd">public</span> <span class="nc">PitchSample</span><span class="o">[]</span> <span class="n">pitchContour</span><span class="o">;</span>
    <span class="kd">public</span> <span class="nc">Word</span><span class="o">[]</span> <span class="n">words</span><span class="o">;</span>
    <span class="c1">// ...</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Gson deserialises the JSON into this structure once at song load. Runtime access is just array indexing.</p>

<h3 id="the-event-system">The Event System</h3>

<p>Each musical event type maps to a Hytale <code class="language-plaintext highlighter-rouge">IEvent</code> implementation:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">PulseMainBeatEvent</span>  <span class="kd">extends</span> <span class="nc">PulseEvent</span> <span class="kd">implements</span> <span class="nc">IEvent</span><span class="o">&lt;</span><span class="nc">Void</span><span class="o">&gt;</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">PulseDownbeatEvent</span>  <span class="kd">extends</span> <span class="nc">PulseEvent</span> <span class="kd">implements</span> <span class="nc">IEvent</span><span class="o">&lt;</span><span class="nc">Void</span><span class="o">&gt;</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">PulseOnsetEvent</span>     <span class="kd">extends</span> <span class="nc">PulseEvent</span> <span class="kd">implements</span> <span class="nc">IEvent</span><span class="o">&lt;</span><span class="nc">Void</span><span class="o">&gt;</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">PulseSectionEvent</span>   <span class="kd">extends</span> <span class="nc">PulseEvent</span> <span class="kd">implements</span> <span class="nc">IEvent</span><span class="o">&lt;</span><span class="nc">Void</span><span class="o">&gt;</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">PulseSongStartEvent</span> <span class="kd">extends</span> <span class="nc">PulseEvent</span> <span class="kd">implements</span> <span class="nc">IEvent</span><span class="o">&lt;</span><span class="nc">Void</span><span class="o">&gt;</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">PulseSongEndEvent</span>   <span class="kd">extends</span> <span class="nc">PulseEvent</span> <span class="kd">implements</span> <span class="nc">IEvent</span><span class="o">&lt;</span><span class="nc">Void</span><span class="o">&gt;</span>
</code></pre></div></div>

<p>All inherit from <code class="language-plaintext highlighter-rouge">PulseEvent</code>, which carries a <code class="language-plaintext highlighter-rouge">SongContext</code> record — BPM, average energy, duration, beats per bar, and mood — so every listener has full song context without needing to query a shared state object:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="n">record</span> <span class="nf">SongContext</span><span class="o">(</span>
    <span class="kt">double</span> <span class="no">BPM</span><span class="o">,</span>
    <span class="kt">double</span> <span class="n">averageEnergy</span><span class="o">,</span>
    <span class="kt">double</span> <span class="n">duration</span><span class="o">,</span>
    <span class="kt">double</span> <span class="n">beatsPerBar</span><span class="o">,</span>
    <span class="nc">String</span> <span class="n">mood</span>
<span class="o">)</span> <span class="o">{}</span>
</code></pre></div></div>

<p>The dispatcher reads the beat map’s timestamp arrays, schedules events ahead of time using <code class="language-plaintext highlighter-rouge">HytaleServer.SCHEDULED_EXECUTOR</code>, and fires them as the song progresses. All scheduling happens on a background thread — the main game thread only runs the actual world mutations triggered by the event listeners.</p>

<h3 id="visual-effects">Visual Effects</h3>

<p><code class="language-plaintext highlighter-rouge">PulseEffects</code> implements the world-space effects. A few highlights:</p>

<p><strong>Equaliser</strong> — a row of block columns that rise and fall in a sine wave pattern on each beat, timed with staggered delays for a ripple effect:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">double</span> <span class="n">wave</span> <span class="o">=</span> <span class="nc">Math</span><span class="o">.</span><span class="na">sin</span><span class="o">(</span><span class="nc">Math</span><span class="o">.</span><span class="na">PI</span> <span class="o">*</span> <span class="n">i</span> <span class="o">/</span> <span class="o">(</span><span class="n">barCount</span> <span class="o">-</span> <span class="mi">1</span><span class="o">));</span>
<span class="kd">final</span> <span class="kt">int</span> <span class="n">height</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">+</span> <span class="o">(</span><span class="kt">int</span><span class="o">)(</span><span class="n">wave</span> <span class="o">*</span> <span class="o">(</span><span class="n">maxHeight</span> <span class="o">-</span> <span class="mi">1</span><span class="o">));</span>
<span class="kd">final</span> <span class="kt">int</span> <span class="n">staggerDelay</span> <span class="o">=</span> <span class="n">i</span> <span class="o">*</span> <span class="mi">20</span><span class="o">;</span> <span class="c1">// ripple left to right</span>
</code></pre></div></div>

<p><strong>Circular pillar wave</strong> — pillars arranged in a ring, rising sequentially around the circumference so the wave propagates spatially:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">double</span> <span class="n">angle</span> <span class="o">=</span> <span class="o">(</span><span class="mi">2</span> <span class="o">*</span> <span class="nc">Math</span><span class="o">.</span><span class="na">PI</span> <span class="o">/</span> <span class="n">pillarCount</span><span class="o">)</span> <span class="o">*</span> <span class="n">i</span><span class="o">;</span>
<span class="kd">final</span> <span class="kt">int</span> <span class="n">bx</span> <span class="o">=</span> <span class="o">(</span><span class="kt">int</span><span class="o">)(</span><span class="n">center</span><span class="o">.</span><span class="na">x</span> <span class="o">+</span> <span class="nc">Math</span><span class="o">.</span><span class="na">cos</span><span class="o">(</span><span class="n">angle</span><span class="o">)</span> <span class="o">*</span> <span class="n">distance</span><span class="o">);</span>
<span class="kd">final</span> <span class="kt">int</span> <span class="n">bz</span> <span class="o">=</span> <span class="o">(</span><span class="kt">int</span><span class="o">)(</span><span class="n">center</span><span class="o">.</span><span class="na">z</span> <span class="o">+</span> <span class="nc">Math</span><span class="o">.</span><span class="na">sin</span><span class="o">(</span><span class="n">angle</span><span class="o">)</span> <span class="o">*</span> <span class="n">distance</span><span class="o">);</span>
</code></pre></div></div>

<p><strong>Bloom pulse</strong> — the post-processing bloom intensity is driven directly via <code class="language-plaintext highlighter-rouge">UpdatePostFxSettings</code>, allowing the screen to pulse with the beat without any world geometry changing:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">UpdatePostFxSettings</span> <span class="n">pulsePacket</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">UpdatePostFxSettings</span><span class="o">(</span>
    <span class="n">intensity</span><span class="o">,</span> <span class="mf">8.0f</span><span class="o">,</span> <span class="mf">4.0f</span><span class="o">,</span> <span class="mf">0.25f</span><span class="o">,</span> <span class="mf">0.3f</span>
<span class="o">);</span>
<span class="n">player</span><span class="o">.</span><span class="na">getPacketHandler</span><span class="o">().</span><span class="na">writePacket</span><span class="o">(</span><span class="n">pulsePacket</span><span class="o">,</span> <span class="kc">true</span><span class="o">);</span>
</code></pre></div></div>

<p><strong>Camera shake</strong> — on strong hits above a threshold, <code class="language-plaintext highlighter-rouge">CameraShakeEffect</code> is sent directly to the player’s packet handler:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="o">(</span><span class="n">intensity</span> <span class="o">&gt;</span> <span class="mf">0.8f</span><span class="o">)</span> <span class="o">{</span>
    <span class="n">playerRef</span><span class="o">.</span><span class="na">getPacketHandler</span><span class="o">().</span><span class="na">writePacket</span><span class="o">(</span>
        <span class="k">new</span> <span class="nf">CameraShakeEffect</span><span class="o">(</span><span class="mi">1</span><span class="o">,</span> <span class="n">intensity</span> <span class="o">*</span> <span class="mf">0.3f</span><span class="o">,</span> <span class="nc">AccumulationMode</span><span class="o">.</span><span class="na">Average</span><span class="o">),</span> <span class="kc">true</span>
    <span class="o">);</span>
<span class="o">}</span>
</code></pre></div></div>

<p><strong>Mood-mapped colours</strong> — section mood drives the colour palette for all effects:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">private</span> <span class="nc">Color</span> <span class="nf">getMoodColor</span><span class="o">(</span><span class="nc">String</span> <span class="n">mood</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">return</span> <span class="nf">switch</span> <span class="o">(</span><span class="n">mood</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">case</span> <span class="s">"energetic"</span>  <span class="o">-&gt;</span> <span class="nc">Color</span><span class="o">.</span><span class="na">YELLOW</span><span class="o">;</span>
        <span class="k">case</span> <span class="s">"aggressive"</span> <span class="o">-&gt;</span> <span class="nc">Color</span><span class="o">.</span><span class="na">RED</span><span class="o">;</span>
        <span class="k">case</span> <span class="s">"melancholic"</span><span class="o">-&gt;</span> <span class="nc">Color</span><span class="o">.</span><span class="na">BLUE</span><span class="o">;</span>
        <span class="k">case</span> <span class="s">"peaceful"</span>   <span class="o">-&gt;</span> <span class="nc">Color</span><span class="o">.</span><span class="na">CYAN</span><span class="o">;</span>
        <span class="k">case</span> <span class="s">"dark"</span>       <span class="o">-&gt;</span> <span class="nc">Color</span><span class="o">.</span><span class="na">MAGENTA</span><span class="o">;</span>
        <span class="k">case</span> <span class="s">"happy"</span>      <span class="o">-&gt;</span> <span class="nc">Color</span><span class="o">.</span><span class="na">PINK</span><span class="o">;</span>
        <span class="k">default</span>           <span class="o">-&gt;</span> <span class="nc">Color</span><span class="o">.</span><span class="na">WHITE</span><span class="o">;</span>
    <span class="o">};</span>
<span class="o">}</span>
</code></pre></div></div>

<h3 id="the-spline">The Spline</h3>

<p><code class="language-plaintext highlighter-rouge">PulseSpline</code> wraps Hytale’s <code class="language-plaintext highlighter-rouge">IPath</code> API to expose a <code class="language-plaintext highlighter-rouge">getPositionAt(double t)</code> method — given a normalised time value (0–1), it returns the corresponding world-space position along a designer-placed path. This is how effects are anchored to the world spatially: the progress of the song maps directly to position along a spline, so a four-minute song traverses the entire path exactly once:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="nc">Vector3d</span> <span class="nf">getPositionAt</span><span class="o">(</span><span class="kt">double</span> <span class="n">t</span><span class="o">)</span> <span class="o">{</span>
    <span class="n">t</span> <span class="o">=</span> <span class="nc">Math</span><span class="o">.</span><span class="na">max</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="nc">Math</span><span class="o">.</span><span class="na">min</span><span class="o">(</span><span class="mi">1</span><span class="o">,</span> <span class="n">t</span><span class="o">));</span>
    <span class="kt">int</span> <span class="n">segments</span> <span class="o">=</span> <span class="n">points</span><span class="o">.</span><span class="na">size</span><span class="o">()</span> <span class="o">-</span> <span class="mi">1</span><span class="o">;</span>
    <span class="kt">double</span> <span class="n">scaledT</span> <span class="o">=</span> <span class="n">t</span> <span class="o">*</span> <span class="n">segments</span><span class="o">;</span>
    <span class="kt">int</span> <span class="n">segment</span> <span class="o">=</span> <span class="nc">Math</span><span class="o">.</span><span class="na">min</span><span class="o">((</span><span class="kt">int</span><span class="o">)</span> <span class="n">scaledT</span><span class="o">,</span> <span class="n">segments</span> <span class="o">-</span> <span class="mi">1</span><span class="o">);</span>
    <span class="kt">double</span> <span class="n">localT</span> <span class="o">=</span> <span class="n">scaledT</span> <span class="o">-</span> <span class="n">segment</span><span class="o">;</span>
    <span class="c1">// linear interpolation between adjacent waypoints</span>
    <span class="o">...</span>
<span class="o">}</span>
</code></pre></div></div>

<hr />

<h2 id="architecture-summary">Architecture Summary</h2>

<p>The two-stage design is the key architectural decision. Hytale servers handle real-time game state for many concurrent players — introducing a Python audio analysis pipeline into the hot path would be catastrophic. By doing all analysis offline and reducing runtime to scheduled event dispatch from a pre-computed data structure, Pulse adds zero measurable overhead to the server tick.</p>

<p>The event system mirrors Hytale’s own <code class="language-plaintext highlighter-rouge">IEvent</code> pattern, meaning Pulse effects integrate naturally with any other plugin listening to the same bus. A game designer could respond to <code class="language-plaintext highlighter-rouge">PulseMainBeatEvent</code> the same way they’d respond to any other server event — no special integration required.</p>

<p><a href="https://github.com/qbb84/Hytale-Rhythm">View Repo</a></p>]]></content><author><name>qbb84</name></author><category term="Java" /><category term="Hytale" /><category term="Python" /><category term="Audio Analysis" /><category term="Game Development" /><category term="ML" /><summary type="html"><![CDATA[A dev log covering rhythm, codenamed: Pulse — a Hytale server plugin that performs offline audio analysis to produce a beat map, then drives beat-synchronised in-world visual effects at runtime using Hytale’s server API.]]></summary></entry><entry><title type="html">Mcprisonpets Tycoon</title><link href="https://qbb84.github.io/mcprisonpets-tycoon" rel="alternate" type="text/html" title="Mcprisonpets Tycoon" /><published>2025-04-05T00:00:00+00:00</published><updated>2025-04-05T00:00:00+00:00</updated><id>https://qbb84.github.io/MCPrisonPets-Tycoon</id><content type="html" xml:base="https://qbb84.github.io/mcprisonpets-tycoon"><![CDATA[<p><em>A concise dev log covering PrisonPets — a Spigot minigame combining a prison mining loop, tiered pet collection, player economy, and MMO-inspired raid mechanics driven by pet abilities.</em></p>

<h2 id="the-concept">The Concept</h2>

<p>The core loop is simple: mine, collect pets, upgrade, raid. Each layer feeds the next — mining surfaces pets and resources, pets power raid encounters, raids yield rare rewards that feed back into the economy. The design is deliberately inspired by idle tycoon and collection mechanics, adapted for a Minecraft server environment where the interaction model is spatial and real-time rather than menu-driven.</p>

<p>The constraint I worked to: every system should be readable to a new player in under a minute. Minecraft players have limited tolerance for UI complexity.</p>

<h2 id="pet-rarity-system">Pet Rarity System</h2>

<p>Eight rarity tiers — <code class="language-plaintext highlighter-rouge">COMMON</code> through <code class="language-plaintext highlighter-rouge">PRISMATIC</code> — each with a weighted drop chance and a colour used consistently across all UI surfaces:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">enum</span> <span class="nc">PetRarity</span> <span class="o">{</span>
    <span class="no">COMMON</span><span class="o">(</span><span class="nc">ChatColor</span><span class="o">.</span><span class="na">GRAY</span><span class="o">,</span> <span class="s">"Common"</span><span class="o">,</span> <span class="mf">50.0</span><span class="o">),</span>
    <span class="no">UNCOMMON</span><span class="o">(</span><span class="nc">ChatColor</span><span class="o">.</span><span class="na">GREEN</span><span class="o">,</span> <span class="s">"Uncommon"</span><span class="o">,</span> <span class="mf">30.0</span><span class="o">),</span>
    <span class="no">RARE</span><span class="o">(</span><span class="nc">ChatColor</span><span class="o">.</span><span class="na">BLUE</span><span class="o">,</span> <span class="s">"Rare"</span><span class="o">,</span> <span class="mf">15.0</span><span class="o">),</span>
    <span class="no">EPIC</span><span class="o">(</span><span class="nc">ChatColor</span><span class="o">.</span><span class="na">DARK_PURPLE</span><span class="o">,</span> <span class="s">"Epic"</span><span class="o">,</span> <span class="mf">4.0</span><span class="o">),</span>
    <span class="no">LEGENDARY</span><span class="o">(</span><span class="nc">ChatColor</span><span class="o">.</span><span class="na">GOLD</span><span class="o">,</span> <span class="s">"Legendary"</span><span class="o">,</span> <span class="mf">0.8</span><span class="o">),</span>
    <span class="no">MYTHICAL</span><span class="o">(</span><span class="nc">ChatColor</span><span class="o">.</span><span class="na">RED</span><span class="o">,</span> <span class="s">"Mythical"</span><span class="o">,</span> <span class="mf">0.15</span><span class="o">),</span>
    <span class="no">CELESTIAL</span><span class="o">(</span><span class="nc">ChatColor</span><span class="o">.</span><span class="na">AQUA</span><span class="o">,</span> <span class="s">"Celestial"</span><span class="o">,</span> <span class="mf">0.04</span><span class="o">),</span>
    <span class="no">PRISMATIC</span><span class="o">(</span><span class="nc">ChatColor</span><span class="o">.</span><span class="na">LIGHT_PURPLE</span><span class="o">,</span> <span class="s">"Prismatic"</span><span class="o">,</span> <span class="mf">0.01</span><span class="o">);</span>
    <span class="o">...</span>
<span class="o">}</span>
</code></pre></div></div>

<p>The drop chances sum to 100.0. Rolling a pet calls <code class="language-plaintext highlighter-rouge">getRandomRarity()</code>, which accumulates probability mass across tiers until the random value is exceeded — standard weighted random selection.</p>

<p>The more interesting variant is <code class="language-plaintext highlighter-rouge">getRandomRarity(double luckMultiplier)</code>, which takes a luck value from the player’s equipped pet stats and scales the probability distribution toward higher tiers:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">rarities</span><span class="o">.</span><span class="na">length</span><span class="o">;</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span>
    <span class="kt">double</span> <span class="n">tierBonus</span> <span class="o">=</span> <span class="mf">1.0</span> <span class="o">+</span> <span class="o">(</span><span class="n">i</span> <span class="o">*</span> <span class="mf">0.2</span><span class="o">);</span>
    <span class="n">adjustedChances</span><span class="o">[</span><span class="n">i</span><span class="o">]</span> <span class="o">=</span> <span class="n">rarities</span><span class="o">[</span><span class="n">i</span><span class="o">].</span><span class="na">getDropChance</span><span class="o">()</span> <span class="o">*</span> <span class="nc">Math</span><span class="o">.</span><span class="na">pow</span><span class="o">(</span><span class="n">luckMultiplier</span><span class="o">,</span> <span class="n">tierBonus</span><span class="o">);</span>
    <span class="n">totalChance</span> <span class="o">+=</span> <span class="n">adjustedChances</span><span class="o">[</span><span class="n">i</span><span class="o">];</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Higher-tier rarities get a larger exponent applied to the luck multiplier — meaning luck has a compounding effect on rare drops rather than a flat shift. A lucky pet meaningfully changes your odds of finding a Prismatic without trivialising the rarity curve at the Common/Uncommon end.</p>

<h2 id="pet-architecture">Pet Architecture</h2>

<p>Each <code class="language-plaintext highlighter-rouge">Pet</code> instance holds its own stat map, ability list, level, XP, evolution ID, mining power, and arena bonus. Stats are initialised from the pet’s type and rarity at construction, then scaled with level:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kt">int</span> <span class="nf">getRequiredXPForNextLevel</span><span class="o">()</span> <span class="o">{</span>
    <span class="k">return</span> <span class="o">(</span><span class="kt">int</span><span class="o">)</span> <span class="o">(</span><span class="mi">100</span> <span class="o">*</span> <span class="nc">Math</span><span class="o">.</span><span class="na">pow</span><span class="o">(</span><span class="n">level</span><span class="o">,</span> <span class="mf">1.5</span><span class="o">));</span>
<span class="o">}</span>
</code></pre></div></div>

<p>The polynomial XP curve means early levels are fast and later levels slow down meaningfully — the same pattern used in most MMO progression systems. Level is capped at 100.</p>

<p>Type determines the pet’s role in the minigame loop:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">ATTACK</code> — +2% arena bonus base, scales into raid damage</li>
  <li><code class="language-plaintext highlighter-rouge">MINING</code> — +2 base mining power, surfaces more pets per session</li>
  <li><code class="language-plaintext highlighter-rouge">SUPPORT</code> / <code class="language-plaintext highlighter-rouge">TANK</code> / <code class="language-plaintext highlighter-rouge">SPEED</code> — utility roles with distinct stat profiles</li>
</ul>

<p>Each pet exposes <code class="language-plaintext highlighter-rouge">getEffectiveMiningPower()</code> and <code class="language-plaintext highlighter-rouge">getEffectiveArenaBonus()</code> — derived values that fold in the level bonus — so the rest of the codebase never has to re-derive these:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kt">int</span> <span class="nf">getEffectiveMiningPower</span><span class="o">()</span> <span class="o">{</span>
    <span class="k">return</span> <span class="o">(</span><span class="kt">int</span><span class="o">)</span> <span class="o">(</span><span class="n">miningPower</span> <span class="o">*</span> <span class="o">(</span><span class="mi">1</span> <span class="o">+</span> <span class="o">(</span><span class="n">level</span> <span class="o">-</span> <span class="mi">1</span><span class="o">)</span> <span class="o">*</span> <span class="mf">0.05</span><span class="o">));</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Pets are serialised and deserialised via <code class="language-plaintext highlighter-rouge">saveToConfig</code> / <code class="language-plaintext highlighter-rouge">loadFromConfig</code> using Bukkit’s <code class="language-plaintext highlighter-rouge">ConfigurationSection</code> API, keeping persistence straightforward without a database dependency at this scale.</p>

<h2 id="pettemplate">PetTemplate</h2>

<p><code class="language-plaintext highlighter-rouge">PetTemplate</code> decouples the definition of a pet species from the instance of a player’s specific pet. Templates define the archetype — name, rarity, type, base stats, abilities, evolution chain — and <code class="language-plaintext highlighter-rouge">createPet()</code> stamps out a fresh <code class="language-plaintext highlighter-rouge">Pet</code> instance from the template. This is the standard Prototype pattern applied to game object instantiation.</p>

<h2 id="the-raid-system">The Raid System</h2>

<p>Raids are the endgame cooperative loop. An <code class="language-plaintext highlighter-rouge">ActiveRaid</code> holds the live state of an in-progress encounter:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">ActiveRaid</span> <span class="o">{</span>
    <span class="kd">private</span> <span class="kd">final</span> <span class="nc">Set</span><span class="o">&lt;</span><span class="no">UUID</span><span class="o">&gt;</span> <span class="n">participants</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">HashSet</span><span class="o">&lt;&gt;();</span>
    <span class="kd">private</span> <span class="kd">final</span> <span class="nc">Map</span><span class="o">&lt;</span><span class="no">UUID</span><span class="o">,</span> <span class="nc">Integer</span><span class="o">&gt;</span> <span class="n">participantDamage</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">HashMap</span><span class="o">&lt;&gt;();</span>
    <span class="kd">private</span> <span class="nc">RaidState</span> <span class="n">state</span> <span class="o">=</span> <span class="nc">RaidState</span><span class="o">.</span><span class="na">WAITING</span><span class="o">;</span>
    <span class="kd">private</span> <span class="nc">RaidBoss</span> <span class="n">boss</span><span class="o">;</span>
    <span class="o">...</span>
<span class="o">}</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">RaidState</code> progresses through <code class="language-plaintext highlighter-rouge">WAITING → READY → IN_PROGRESS → COMPLETED / FAILED</code>. The state machine is simple and explicit — no ambiguity about what a raid instance is doing at any point.</p>

<p>Damage tracking is per-participant, which enables a top damage leaderboard at completion:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="nc">List</span><span class="o">&lt;</span><span class="no">UUID</span><span class="o">&gt;</span> <span class="nf">getTopDamageDealers</span><span class="o">(</span><span class="kt">int</span> <span class="n">count</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">return</span> <span class="n">participantDamage</span><span class="o">.</span><span class="na">entrySet</span><span class="o">().</span><span class="na">stream</span><span class="o">()</span>
        <span class="o">.</span><span class="na">sorted</span><span class="o">(</span><span class="nc">Map</span><span class="o">.</span><span class="na">Entry</span><span class="o">.</span><span class="na">comparingByValue</span><span class="o">(</span><span class="nc">Comparator</span><span class="o">.</span><span class="na">reverseOrder</span><span class="o">()))</span>
        <span class="o">.</span><span class="na">limit</span><span class="o">(</span><span class="n">count</span><span class="o">)</span>
        <span class="o">.</span><span class="na">map</span><span class="o">(</span><span class="nc">Map</span><span class="o">.</span><span class="na">Entry</span><span class="o">::</span><span class="n">getKey</span><span class="o">)</span>
        <span class="o">.</span><span class="na">collect</span><span class="o">(</span><span class="nc">Collectors</span><span class="o">.</span><span class="na">toList</span><span class="o">());</span>
<span class="o">}</span>
</code></pre></div></div>

<p>This feeds the reward distribution — top contributors receive better loot tiers, incentivising active participation over passive presence.</p>

<p><code class="language-plaintext highlighter-rouge">RaidBoss</code> carries its own rarity — a boss’s rarity tier gates which pet eggs can drop as completion rewards, creating a direct link between the difficulty of the encounter and the quality of the loot pool.</p>

<p>Damage to the boss is clamped to current health so overkill is always handled gracefully:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kt">int</span> <span class="nf">takeDamage</span><span class="o">(</span><span class="kt">int</span> <span class="n">damage</span><span class="o">)</span> <span class="o">{</span>
    <span class="kt">int</span> <span class="n">actualDamage</span> <span class="o">=</span> <span class="nc">Math</span><span class="o">.</span><span class="na">min</span><span class="o">(</span><span class="n">currentHealth</span><span class="o">,</span> <span class="n">damage</span><span class="o">);</span>
    <span class="n">currentHealth</span> <span class="o">-=</span> <span class="n">actualDamage</span><span class="o">;</span>
    <span class="k">return</span> <span class="n">actualDamage</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>

<h2 id="mine-regions">Mine Regions</h2>

<p>Mines are defined as bounded world-space regions — <code class="language-plaintext highlighter-rouge">MineRegion</code> holds a min/max <code class="language-plaintext highlighter-rouge">Location</code> pair and exposes a <code class="language-plaintext highlighter-rouge">contains(Location)</code> check used to determine when a player is actively mining within a valid zone:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">return</span> <span class="n">location</span><span class="o">.</span><span class="na">getX</span><span class="o">()</span> <span class="o">&gt;=</span> <span class="n">min</span><span class="o">.</span><span class="na">getX</span><span class="o">()</span> <span class="o">&amp;&amp;</span> <span class="n">location</span><span class="o">.</span><span class="na">getX</span><span class="o">()</span> <span class="o">&lt;=</span> <span class="n">max</span><span class="o">.</span><span class="na">getX</span><span class="o">()</span> <span class="o">&amp;&amp;</span>
       <span class="n">location</span><span class="o">.</span><span class="na">getY</span><span class="o">()</span> <span class="o">&gt;=</span> <span class="n">min</span><span class="o">.</span><span class="na">getY</span><span class="o">()</span> <span class="o">&amp;&amp;</span> <span class="n">location</span><span class="o">.</span><span class="na">getY</span><span class="o">()</span> <span class="o">&lt;=</span> <span class="n">max</span><span class="o">.</span><span class="na">getY</span><span class="o">()</span> <span class="o">&amp;&amp;</span>
       <span class="n">location</span><span class="o">.</span><span class="na">getZ</span><span class="o">()</span> <span class="o">&gt;=</span> <span class="n">min</span><span class="o">.</span><span class="na">getZ</span><span class="o">()</span> <span class="o">&amp;&amp;</span> <span class="n">location</span><span class="o">.</span><span class="na">getZ</span><span class="o">()</span> <span class="o">&lt;=</span> <span class="n">max</span><span class="o">.</span><span class="na">getZ</span><span class="o">();</span>
</code></pre></div></div>

<p>Regions auto-reset on a 5-minute timer (<code class="language-plaintext highlighter-rouge">needsReset()</code> checks <code class="language-plaintext highlighter-rouge">System.currentTimeMillis()</code> against <code class="language-plaintext highlighter-rouge">lastResetTime</code>), keeping mines populated without manual intervention.</p>

<h2 id="trading">Trading</h2>

<p>The <code class="language-plaintext highlighter-rouge">Trade</code> class supports bidirectional exchange of pets, items, coins, and gems — each tracked separately per player. Both parties must explicitly call <code class="language-plaintext highlighter-rouge">setAccepted(true)</code> before any transfer occurs. The <code class="language-plaintext highlighter-rouge">TradeManager</code> holds all active trades keyed by participant UUID, with a <code class="language-plaintext highlighter-rouge">TradeRequest</code> intermediary for the invitation flow before a trade session opens.</p>

<p>Pets are deep-copied via <code class="language-plaintext highlighter-rouge">Pet.copy()</code> before being placed into a trade — ensuring the original is never mutated until the trade settles. This prevents a race condition where a pet’s state changes between being offered and the trade completing.</p>

<p><a href="https://github.com/qbb84/PrisonPets">View Repo</a></p>]]></content><author><name>qbb84</name></author><category term="Java" /><category term="Spigot" /><category term="Minecraft" /><category term="Minigames" /><category term="Game Design" /><summary type="html"><![CDATA[A concise dev log covering PrisonPets — a Spigot minigame combining a prison mining loop, tiered pet collection, player economy, and MMO-inspired raid mechanics driven by pet abilities.]]></summary></entry><entry><title type="html">Nebula Minecraft Server</title><link href="https://qbb84.github.io/nebula-minecraft-server" rel="alternate" type="text/html" title="Nebula Minecraft Server" /><published>2025-01-20T00:00:00+00:00</published><updated>2025-01-20T00:00:00+00:00</updated><id>https://qbb84.github.io/nebula-minecraft-server</id><content type="html" xml:base="https://qbb84.github.io/nebula-minecraft-server"><![CDATA[<p><em>This is a technical dev log covering Nebula — a Minecraft server implementation written from scratch in Rust, including the full authentication handshake, packet codec, and a custom proc-macro crate for packet serialisation.</em></p>

<h2 id="why-rust-and-why-from-scratch">Why Rust, and Why From Scratch</h2>

<p>Most Minecraft server development happens on top of Spigot or Paper — abstractions that handle the protocol layer entirely. You write plugins, respond to events, and never think about what’s happening on the wire. That’s the right approach for building games. But I wanted to understand the protocol at a level that Spigot doesn’t expose.</p>

<p>Rust was the natural choice. The Minecraft protocol is fundamentally a binary serialisation problem over a TCP stream — exactly the kind of problem Rust handles elegantly, with zero-cost abstractions, explicit memory ownership, and no garbage collector introducing latency. Writing a game server in a language that competes with C for raw throughput is the right call when you’re thinking about hundreds of thousands of concurrent connections.</p>

<h2 id="the-minecraft-protocol">The Minecraft Protocol</h2>

<p>Before writing a line of code, I spent time with <a href="https://wiki.vg">wiki.vg</a> — the community-maintained Minecraft protocol documentation. The protocol has four states: <strong>Handshaking</strong>, <strong>Status</strong>, <strong>Login</strong>, and <strong>Play</strong>. Each state defines a set of packets, each with a specific format.</p>

<p>Packets are structured as:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[Length: VarInt] [Packet ID: VarInt] [Data: ...]
</code></pre></div></div>

<p>A VarInt is a variable-length integer encoding — the same format used in Protocol Buffers. Each byte uses 7 bits for data and 1 bit as a continuation flag. Small numbers take 1 byte, larger ones take up to 5.</p>

<p>Reading and writing VarInts correctly is the first thing you implement, and the first thing that breaks when you get it wrong.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">fn</span> <span class="nf">read_varint</span><span class="p">(</span><span class="n">buf</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="n">Cursor</span><span class="o">&lt;&amp;</span><span class="p">[</span><span class="nb">u8</span><span class="p">]</span><span class="o">&gt;</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">Result</span><span class="o">&lt;</span><span class="nb">i32</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">result</span> <span class="o">=</span> <span class="mi">0i32</span><span class="p">;</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">shift</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="k">loop</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">byte</span> <span class="o">=</span> <span class="n">buf</span><span class="nf">.read_u8</span><span class="p">()</span><span class="o">?</span><span class="p">;</span>
        <span class="n">result</span> <span class="p">|</span><span class="o">=</span> <span class="p">((</span><span class="n">byte</span> <span class="o">&amp;</span> <span class="mi">0x7F</span><span class="p">)</span> <span class="k">as</span> <span class="nb">i32</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="n">shift</span><span class="p">;</span>
        <span class="k">if</span> <span class="n">byte</span> <span class="o">&amp;</span> <span class="mi">0x80</span> <span class="o">==</span> <span class="mi">0</span> <span class="p">{</span>
            <span class="k">break</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="n">shift</span> <span class="o">+=</span> <span class="mi">7</span><span class="p">;</span>
        <span class="k">if</span> <span class="n">shift</span> <span class="o">&gt;=</span> <span class="mi">35</span> <span class="p">{</span>
            <span class="k">return</span> <span class="nf">Err</span><span class="p">(</span><span class="nd">anyhow!</span><span class="p">(</span><span class="s">"VarInt too long"</span><span class="p">));</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="nf">Ok</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="the-authentication-handshake">The Authentication Handshake</h2>

<p>This is the part that separates a toy implementation from something real. Online mode Minecraft uses a three-step authentication process involving RSA encryption, AES stream cipher, and Mojang’s session server.</p>

<h3 id="step-1--encryption-request">Step 1 — Encryption Request</h3>

<p>The server generates an RSA key pair and sends the client a public key alongside a random 4-byte verify token:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">rsa</span> <span class="o">=</span> <span class="nn">Rsa</span><span class="p">::</span><span class="nf">generate</span><span class="p">(</span><span class="mi">1024</span><span class="p">)</span><span class="o">?</span><span class="p">;</span>
<span class="k">let</span> <span class="n">public_key_der</span> <span class="o">=</span> <span class="n">rsa</span><span class="nf">.public_key_to_der</span><span class="p">()</span><span class="o">?</span><span class="p">;</span>

<span class="c1">// Send Encryption Request packet</span>
<span class="c1">// [Public Key Length: VarInt] [Public Key: Bytes]</span>
<span class="c1">// [Verify Token Length: VarInt] [Verify Token: Bytes]</span>
</code></pre></div></div>

<h3 id="step-2--encryption-response">Step 2 — Encryption Response</h3>

<p>The client responds with two values, both RSA-encrypted with the server’s public key:</p>

<ul>
  <li>A 16-byte shared secret — this becomes the AES key</li>
  <li>The verify token, echoed back to prove the client decrypted it correctly</li>
</ul>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">shared_secret</span> <span class="o">=</span> <span class="n">rsa</span><span class="nf">.private_decrypt</span><span class="p">(</span><span class="o">&amp;</span><span class="n">encrypted_secret</span><span class="p">,</span> <span class="nn">Padding</span><span class="p">::</span><span class="n">PKCS1</span><span class="p">)</span><span class="o">?</span><span class="p">;</span>
<span class="k">let</span> <span class="n">decrypted_token</span> <span class="o">=</span> <span class="n">rsa</span><span class="nf">.private_decrypt</span><span class="p">(</span><span class="o">&amp;</span><span class="n">encrypted_token</span><span class="p">,</span> <span class="nn">Padding</span><span class="p">::</span><span class="n">PKCS1</span><span class="p">)</span><span class="o">?</span><span class="p">;</span>

<span class="nd">assert_eq!</span><span class="p">(</span><span class="n">decrypted_token</span><span class="p">,</span> <span class="n">verify_token</span><span class="p">);</span>
</code></pre></div></div>

<h3 id="step-3--session-authentication">Step 3 — Session Authentication</h3>

<p>Before enabling encryption, the server must verify the client is who they claim to be. This involves computing a SHA1 hash — called the “server hash” — derived from the server ID (an empty string in modern versions), the shared secret, and the public key:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">server_hash</span> <span class="o">=</span> <span class="nf">compute_server_hash</span><span class="p">(</span><span class="s">""</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">shared_secret</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">public_key_der</span><span class="p">);</span>
</code></pre></div></div>

<p>The server hash has a peculiarity: it can be negative. Java’s <code class="language-plaintext highlighter-rouge">BigInteger.toString(16)</code> produces a two’s complement hex representation, which means negative values are prefixed with a minus sign. Rust’s standard library doesn’t do this natively — getting this wrong means authentication will always fail and it took a while to track down.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">fn</span> <span class="nf">compute_server_hash</span><span class="p">(</span><span class="n">server_id</span><span class="p">:</span> <span class="o">&amp;</span><span class="nb">str</span><span class="p">,</span> <span class="n">shared_secret</span><span class="p">:</span> <span class="o">&amp;</span><span class="p">[</span><span class="nb">u8</span><span class="p">],</span> <span class="n">public_key</span><span class="p">:</span> <span class="o">&amp;</span><span class="p">[</span><span class="nb">u8</span><span class="p">])</span> <span class="k">-&gt;</span> <span class="nb">String</span> <span class="p">{</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">hasher</span> <span class="o">=</span> <span class="nn">Sha1</span><span class="p">::</span><span class="nf">new</span><span class="p">();</span>
    <span class="n">hasher</span><span class="nf">.update</span><span class="p">(</span><span class="n">server_id</span><span class="nf">.as_bytes</span><span class="p">());</span>
    <span class="n">hasher</span><span class="nf">.update</span><span class="p">(</span><span class="n">shared_secret</span><span class="p">);</span>
    <span class="n">hasher</span><span class="nf">.update</span><span class="p">(</span><span class="n">public_key</span><span class="p">);</span>
    <span class="k">let</span> <span class="n">hash</span> <span class="o">=</span> <span class="n">hasher</span><span class="nf">.finalize</span><span class="p">();</span>

    <span class="c1">// Java BigInteger two's complement hex formatting</span>
    <span class="k">let</span> <span class="n">bigint</span> <span class="o">=</span> <span class="nn">BigInt</span><span class="p">::</span><span class="nf">from_signed_bytes_be</span><span class="p">(</span><span class="o">&amp;</span><span class="n">hash</span><span class="p">);</span>
    <span class="nd">format!</span><span class="p">(</span><span class="s">"{:x}"</span><span class="p">,</span> <span class="n">bigint</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The server then calls Mojang’s session server to verify the player:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET https://sessionserver.mojang.com/session/minecraft/hasJoined
    ?username=&lt;name&gt;&amp;serverId=&lt;hash&gt;
</code></pre></div></div>

<p>A 200 response with a profile JSON means the player is authenticated. Anything else and you disconnect them.</p>

<h3 id="step-4--aes-cfb8">Step 4 — AES-CFB8</h3>

<p>Once authentication passes, all subsequent communication is encrypted using AES in CFB8 mode with the shared secret as both the key and the IV:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">use</span> <span class="nn">aes</span><span class="p">::</span><span class="n">Aes128</span><span class="p">;</span>
<span class="k">use</span> <span class="nn">cfb8</span><span class="p">::</span><span class="n">Cfb8</span><span class="p">;</span>
<span class="k">use</span> <span class="nn">cfb8</span><span class="p">::</span><span class="nn">cipher</span><span class="p">::{</span><span class="n">AsyncStreamCipher</span><span class="p">,</span> <span class="n">NewCipher</span><span class="p">};</span>

<span class="k">type</span> <span class="n">AesCfb8</span> <span class="o">=</span> <span class="n">Cfb8</span><span class="o">&lt;</span><span class="n">Aes128</span><span class="o">&gt;</span><span class="p">;</span>

<span class="k">let</span> <span class="n">encryptor</span> <span class="o">=</span> <span class="nn">AesCfb8</span><span class="p">::</span><span class="nf">new_from_slices</span><span class="p">(</span><span class="o">&amp;</span><span class="n">shared_secret</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">shared_secret</span><span class="p">)</span><span class="o">?</span><span class="p">;</span>
<span class="k">let</span> <span class="n">decryptor</span> <span class="o">=</span> <span class="nn">AesCfb8</span><span class="p">::</span><span class="nf">new_from_slices</span><span class="p">(</span><span class="o">&amp;</span><span class="n">shared_secret</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">shared_secret</span><span class="p">)</span><span class="o">?</span><span class="p">;</span>
</code></pre></div></div>

<p>Every byte sent and received after this point passes through the cipher. The stream is symmetric — both sides encrypt with the same key and IV, decrypting on receipt.</p>

<h2 id="the-packet-macro-system">The Packet Macro System</h2>

<p>Implementing packets manually is tedious and error-prone. Each packet is just a struct with a specific serialisation format — read fields in order, write fields in order. This is exactly the kind of boilerplate that proc-macros eliminate.</p>

<p>I built <code class="language-plaintext highlighter-rouge">packet_macro</code> and <code class="language-plaintext highlighter-rouge">packet_codec</code> as separate crates. The macro derives <code class="language-plaintext highlighter-rouge">Encode</code> and <code class="language-plaintext highlighter-rouge">Decode</code> traits for any struct annotated with <code class="language-plaintext highlighter-rouge">#[derive(Packet)]</code>:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">#[derive(Packet)]</span>
<span class="k">pub</span> <span class="k">struct</span> <span class="n">LoginSuccess</span> <span class="p">{</span>
    <span class="k">pub</span> <span class="n">uuid</span><span class="p">:</span> <span class="n">Uuid</span><span class="p">,</span>
    <span class="k">pub</span> <span class="n">username</span><span class="p">:</span> <span class="nb">String</span><span class="p">,</span>
    <span class="k">pub</span> <span class="n">properties</span><span class="p">:</span> <span class="nb">Vec</span><span class="o">&lt;</span><span class="n">Property</span><span class="o">&gt;</span><span class="p">,</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The macro expands this to:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">impl</span> <span class="n">Encode</span> <span class="k">for</span> <span class="n">LoginSuccess</span> <span class="p">{</span>
    <span class="k">fn</span> <span class="nf">encode</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="p">,</span> <span class="n">buf</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="n">BytesMut</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">self</span><span class="py">.uuid</span><span class="nf">.encode</span><span class="p">(</span><span class="n">buf</span><span class="p">);</span>
        <span class="k">self</span><span class="py">.username</span><span class="nf">.encode</span><span class="p">(</span><span class="n">buf</span><span class="p">);</span>
        <span class="k">self</span><span class="py">.properties</span><span class="nf">.encode</span><span class="p">(</span><span class="n">buf</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">impl</span> <span class="n">Decode</span> <span class="k">for</span> <span class="n">LoginSuccess</span> <span class="p">{</span>
    <span class="k">fn</span> <span class="nf">decode</span><span class="p">(</span><span class="n">buf</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="n">Cursor</span><span class="o">&lt;&amp;</span><span class="p">[</span><span class="nb">u8</span><span class="p">]</span><span class="o">&gt;</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">Result</span><span class="o">&lt;</span><span class="k">Self</span><span class="o">&gt;</span> <span class="p">{</span>
        <span class="nf">Ok</span><span class="p">(</span><span class="k">Self</span> <span class="p">{</span>
            <span class="n">uuid</span><span class="p">:</span> <span class="nn">Uuid</span><span class="p">::</span><span class="nf">decode</span><span class="p">(</span><span class="n">buf</span><span class="p">)</span><span class="o">?</span><span class="p">,</span>
            <span class="n">username</span><span class="p">:</span> <span class="nn">String</span><span class="p">::</span><span class="nf">decode</span><span class="p">(</span><span class="n">buf</span><span class="p">)</span><span class="o">?</span><span class="p">,</span>
            <span class="n">properties</span><span class="p">:</span> <span class="nn">Vec</span><span class="p">::</span><span class="o">&lt;</span><span class="n">Property</span><span class="o">&gt;</span><span class="p">::</span><span class="nf">decode</span><span class="p">(</span><span class="n">buf</span><span class="p">)</span><span class="o">?</span><span class="p">,</span>
        <span class="p">})</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Adding a new packet is now a single struct definition. The macro handles everything else. This was one of the more satisfying parts of the project — the first time a new packet compiled and worked correctly without writing any serialisation code manually.</p>

<h2 id="async-architecture">Async Architecture</h2>

<p>The server runs on Tokio — Rust’s async runtime. Each client connection spawns a task that owns a read half and a write half of the TCP stream:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="p">(</span><span class="n">reader</span><span class="p">,</span> <span class="n">writer</span><span class="p">)</span> <span class="o">=</span> <span class="n">stream</span><span class="nf">.split</span><span class="p">();</span>

<span class="nn">tokio</span><span class="p">::</span><span class="nf">spawn</span><span class="p">(</span><span class="k">async</span> <span class="k">move</span> <span class="p">{</span>
    <span class="nf">handle_client</span><span class="p">(</span><span class="n">reader</span><span class="p">,</span> <span class="n">writer</span><span class="p">,</span> <span class="n">server_state</span><span class="p">)</span><span class="k">.await</span><span class="p">;</span>
<span class="p">});</span>
</code></pre></div></div>

<p>Tokio’s task scheduler handles thousands of concurrent connections efficiently across a thread pool sized to the machine’s CPU count. There’s no thread-per-connection overhead — the async model means a connection waiting on a network read consumes virtually no resources.</p>

<h2 id="dependencies">Dependencies</h2>

<p>The <code class="language-plaintext highlighter-rouge">Cargo.toml</code> tells the full story of what’s involved:</p>

<div class="language-toml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">[dependencies]</span>
<span class="nn">tokio</span>       <span class="o">=</span> <span class="p">{</span> <span class="py">version</span> <span class="p">=</span> <span class="s">"1"</span><span class="p">,</span> <span class="py">features</span> <span class="p">=</span> <span class="nn">["full"]</span> <span class="p">}</span>
<span class="nn">serde</span>       <span class="o">=</span> <span class="p">{</span> <span class="py">version</span> <span class="p">=</span> <span class="s">"1.0"</span><span class="p">,</span> <span class="py">features</span> <span class="p">=</span> <span class="nn">["derive"]</span> <span class="p">}</span>
<span class="nn">bytes</span>       <span class="o">=</span> <span class="p">{</span> <span class="py">version</span> <span class="p">=</span> <span class="s">"1"</span><span class="p">,</span> <span class="py">features</span> <span class="p">=</span> <span class="nn">["serde"]</span> <span class="p">}</span>
<span class="py">rsa</span>         <span class="p">=</span> <span class="s">"0.9.7"</span>
<span class="py">rand</span>        <span class="p">=</span> <span class="s">"0.8.5"</span>
<span class="py">sha1</span>        <span class="p">=</span> <span class="s">"0.10.6"</span>
<span class="py">aes</span>         <span class="p">=</span> <span class="s">"0.8.4"</span>
<span class="py">cfb8</span>        <span class="p">=</span> <span class="s">"0.8.1"</span>
<span class="py">cipher</span>      <span class="p">=</span> <span class="s">"0.4.4"</span>
<span class="py">num-bigint</span>  <span class="p">=</span> <span class="s">"0.4.6"</span>
<span class="nn">reqwest</span>     <span class="o">=</span> <span class="p">{</span> <span class="py">version</span> <span class="p">=</span> <span class="s">"0.12.9"</span><span class="p">,</span> <span class="py">features</span> <span class="p">=</span> <span class="nn">["json"]</span> <span class="p">}</span>
<span class="nn">packet_macro</span> <span class="o">=</span> <span class="p">{</span> <span class="py">path</span> <span class="p">=</span> <span class="s">"../packet_macro"</span> <span class="p">}</span>
<span class="nn">packet_codec</span> <span class="o">=</span> <span class="p">{</span> <span class="py">path</span> <span class="p">=</span> <span class="s">"../packet_codec"</span> <span class="p">}</span>
</code></pre></div></div>

<p>Each dependency has a specific purpose. Nothing is included without a reason.</p>

<h2 id="what-i-learned">What I Learned</h2>

<p>The Minecraft protocol is well-documented but unforgiving. The SHA1 two’s complement formatting, the CFB8 IV being the same as the key, the precise ordering of fields in every packet — any deviation produces a client disconnect with no useful error message. You learn to read packet captures.</p>

<p>More broadly: implementing a protocol from scratch teaches you things that working above an abstraction layer never does. After Nebula, reading Spigot’s NMS internals feels familiar rather than opaque. The abstraction makes more sense when you understand what it’s abstracting.</p>

<p>The packet macro system was the architectural highlight. Building a proc-macro that generates correct serialisation code for arbitrary structs — and then watching it just work across every packet type — is the kind of leverage that makes Rust genuinely exciting to work in.</p>

<h2 id="whats-next">What’s Next</h2>

<p>The current build covers Handshaking, Status, and Login states in full. Play state packets follow the same patterns — the macro system makes adding them straightforward. The foundation is the hard part. The rest is implementation.</p>

<p><a href="https://github.com/qbb84/Nebula">View Repo</a></p>]]></content><author><name>qbb84</name></author><category term="Rust" /><category term="Minecraft" /><category term="Networking" /><category term="Protocols" /><category term="Game Development" /><summary type="html"><![CDATA[This is a technical dev log covering Nebula — a Minecraft server implementation written from scratch in Rust, including the full authentication handshake, packet codec, and a custom proc-macro crate for packet serialisation.]]></summary></entry><entry><title type="html">Brain Games</title><link href="https://qbb84.github.io/brain-games" rel="alternate" type="text/html" title="Brain Games" /><published>2024-01-19T00:00:00+00:00</published><updated>2024-01-19T00:00:00+00:00</updated><id>https://qbb84.github.io/Brain-Games</id><content type="html" xml:base="https://qbb84.github.io/brain-games"><![CDATA[<p>Incorporating cognitive games into Minecraft serves as an engaging initiative to enhance players’ cognitive control. The goal is to provide an enjoyable yet beneficial experience within the Minecraft environment. By integrating brain games like Dual N-Back, Corsi Block Tapping, Mental Math, and others, players can actively participate in activities designed to improve working memory, processing speed, and overall cognitive function.</p>

<p>The intention is to offer a unique and fun way for players to challenge themselves intellectually, fostering cognitive growth while enjoying the immersive world of Minecraft. The games are crafted with Java and Spigot, utilizing GUI interfaces similar to server gadgets, ensuring accessibility and a seamless integration into the Minecraft gaming experience.</p>

<h2 id="dual-n-back">Dual N-Back:</h2>

<p>In Dual N-Back, players are required to remember the sequence of visual and auditory stimuli and identify when the current stimuli matches the one presented 'n' trials ago.</p>
<p><i> Study:</i> The original study by Susanne M. Jaeggi and Martin Buschkuehl (2008) demonstrated that training with Dual N-Back
can lead to improvements in fluid intelligence. </p>

<p><img src="/images/dualnback2.gif" /></p>

<h2 id="cwm-complex-working-memory">CWM (Complex Working Memory):</h2>

<p>WM involves challenging working memory tasks that require the simultaneous processing and storage of complex information. </p>
<p><i> Study:</i> Klingberg et al. (2005) conducted a study showing that computerized training of working memory, including complex working memory tasks, can lead to improvements in fluid intelligence.</p>

<p><img src="/images/cwm.gif" /></p>

<h2 id="mental-math">Mental Math:</h2>

<p>Mental math exercises involve performing calculations in your head without the use of external aids. </p>
<p><i> Study:</i> While specific studies on mental math games may be limited, general cognitive training involving arithmetic tasks has been associated with improved mathematical and fluid intelligence skills (Dahlin et al., 2008). </p>

<h2 id="corsi-block-tapping">Corsi Block Tapping:</h2>

<p>Description: Corsi Block Tapping assesses visuospatial working memory by requiring participants to reproduce a sequence of block taps. </p>
<p><i> Study:</i> Kessels, van den Berg, Ruis, and Brands (2008) found that Corsi Block Tapping performance was associated with individual differences in fluid intelligence. </p>

<h2 id="memory-span">Memory Span:</h2>

<p>Memory span tasks involve recalling a sequence of items in the same order as presented. </p>
<p><i> Study:</i> Engle et al. (1999) demonstrated that working memory capacity, including memory span, is related to fluid intelligence. </p>

<h2 id="pasat-paced-auditory-serial-addition-test">PASAT (Paced Auditory Serial Addition Test):</h2>

<p>PASAT assesses information processing speed and working memory by requiring participants to add a series of numbers presented at a fixed rate. </p>
<p><i> Study:</i> Stuss, Stethem, and Poirier (1987) found that performance on the PASAT is related to executive functions and working memory, which are components of fluid intelligence. </p>]]></content><author><name>qbb84</name></author><category term="Brain" /><category term="Games" /><category term="Memory" /><summary type="html"><![CDATA[Incorporating cognitive games into Minecraft serves as an engaging initiative to enhance players’ cognitive control. The goal is to provide an enjoyable yet beneficial experience within the Minecraft environment. By integrating brain games like Dual N-Back, Corsi Block Tapping, Mental Math, and others, players can actively participate in activities designed to improve working memory, processing speed, and overall cognitive function.]]></summary></entry><entry><title type="html">Efficient Chess Move Generation With Bitboards</title><link href="https://qbb84.github.io/efficient-chess-move-generation-with-bitboards" rel="alternate" type="text/html" title="Efficient Chess Move Generation With Bitboards" /><published>2023-12-18T00:00:00+00:00</published><updated>2023-12-18T00:00:00+00:00</updated><id>https://qbb84.github.io/Efficient-Chess-Move-Generation-With-Bitboards</id><content type="html" xml:base="https://qbb84.github.io/efficient-chess-move-generation-with-bitboards"><![CDATA[<p>Chess, often considered the king of strategy games, has captivated minds for centuries. Behind the scenes of every formidable chess engine lies a sophisticated representation of the chessboard and its pieces. In the realm of chess engine development, one powerful technique stands out: bitboards.</p>

<p>In this article, I’ll explore the concept of bitboards and delve into the intricacies of move generation for each chess piece. This also serves as an informative guide, and collection of ideas, incase I need to come back in the future for recollection.</p>

<p><i>Note: Although I try to explain the moves concisely, to understand some of the code, you will likely need basic knowledge of bitwise operations, and/or boolean algebra. </i></p>

<h2 id="a-bit-about-bitboards">A “bit” About Bitboards</h2>

<p>A bitboard is a compact data structure that represents the state of a chessboard using a series of 64-bit integers. Each bit in the integer corresponds to a square on the chessboard, and its state (0 or 1) represents the presence or absence of a piece on that square. Bitboards provide an efficient way to perform bitwise operations, enabling rapid computation of various chess-related tasks.</p>

<p>The foundations of bitboards lies in their efficiency, especially when it comes to bitwise operations. This efficiency arises from the binary nature of computation, allowing for rapid manipulation of chess-related tasks. Bitwise AND, OR, XOR, and shifting operations become powerful tools in the hands of developers when dealing with these data structures.</p>

<p><img src="/images/bitboards.png" /></p>

<h2 id="calculating-move-generation">Calculating Move Generation</h2>

<p>Each chess piece can be represented by a separate bitboard, simplifying move generation. The logical operations between these bitboards efficiently compute possible moves, legal positions, and attack vectors.</p>

<p>The following code snippets are provided for informational purposes and to illustrate the concepts of move generation in chess. It is important to note that these code snippets may need to be adapted and integrated into a broader chess engine implementation. Consider consulting official documentation and thoroughly testing any code in a suitable development environment.</p>

<h2 id="the-pawn">The Pawn</h2>

<h4 id="color-definition">Color Definition</h4>

<ul>
  <li>Assigns numeric values (0 for WHITE, 1 for BLACK) representing the colors of chess pieces.</li>
</ul>

<h4 id="single-move-forward">Single Move Forward</h4>

<ul>
  <li>Calculates the target square for a single move forward based on the piece’s color.
Checks if the target square is within the chessboard boundaries and unoccupied.</li>
</ul>

<h4 id="double-move-forward-on-the-first-pawn-move">Double Move Forward (on the first pawn move)</h4>

<ul>
  <li>Considers the piece’s starting rank (second for white, seventh for black).
If applicable, calculates the double move square and checks its validity.</li>
</ul>

<h4 id="capture-diagonally">Capture Diagonally</h4>

<ul>
  <li>Determines squares diagonally adjacent to the piece for potential captures.
Checks if the capture squares are within the board, occupied by an opponent’s piece, and not blocked by friendly pieces.</li>
</ul>

<h4 id="return-value">Return value</h4>

<ul>
  <li>Returns a long integer (bitboard) with bits set for all valid pawn moves from the given square, considering single and double moves as well as captures.</li>
</ul>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="kt">int</span> <span class="no">WHITE</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="kt">int</span> <span class="no">BLACK</span> <span class="o">=</span> <span class="mi">1</span><span class="o">;</span>

    <span class="kd">public</span> <span class="kd">static</span> <span class="kt">long</span> <span class="nf">generatePawnMoves</span><span class="o">(</span><span class="kt">int</span> <span class="n">square</span><span class="o">,</span> <span class="kt">int</span> <span class="n">color</span><span class="o">,</span> <span class="kt">long</span> <span class="n">occupied</span><span class="o">,</span> <span class="kt">long</span> <span class="n">enemyPieces</span><span class="o">)</span> <span class="o">{</span>
        <span class="kt">long</span> <span class="n">moves</span> <span class="o">=</span> <span class="mi">0L</span><span class="o">;</span>

        <span class="kt">int</span> <span class="n">targetSquare</span> <span class="o">=</span> <span class="n">square</span> <span class="o">+</span> <span class="o">((</span><span class="n">color</span> <span class="o">==</span> <span class="no">WHITE</span><span class="o">)</span> <span class="o">?</span> <span class="mi">8</span> <span class="o">:</span> <span class="o">-</span><span class="mi">8</span><span class="o">);</span>
        <span class="k">if</span> <span class="o">((</span><span class="n">targetSquare</span> <span class="o">&gt;=</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">targetSquare</span> <span class="o">&lt;</span> <span class="mi">64</span><span class="o">)</span> <span class="o">&amp;&amp;</span> <span class="o">((</span><span class="n">occupied</span> <span class="o">&amp;</span> <span class="o">(</span><span class="mi">1L</span> <span class="o">&lt;&lt;</span> <span class="n">targetSquare</span><span class="o">))</span> <span class="o">==</span> <span class="mi">0</span><span class="o">))</span> <span class="o">{</span>
            <span class="n">moves</span> <span class="o">|=</span> <span class="o">(</span><span class="mi">1L</span> <span class="o">&lt;&lt;</span> <span class="n">targetSquare</span><span class="o">);</span>

            <span class="k">if</span> <span class="o">(((</span><span class="n">color</span> <span class="o">==</span> <span class="no">WHITE</span><span class="o">)</span> <span class="o">&amp;&amp;</span> <span class="o">(</span><span class="n">square</span> <span class="o">/</span> <span class="mi">8</span> <span class="o">==</span> <span class="mi">1</span><span class="o">))</span> <span class="o">||</span> <span class="o">((</span><span class="n">color</span> <span class="o">==</span> <span class="no">BLACK</span><span class="o">)</span> <span class="o">&amp;&amp;</span> <span class="o">(</span><span class="n">square</span> <span class="o">/</span> <span class="mi">8</span> <span class="o">==</span> <span class="mi">6</span><span class="o">)))</span> <span class="o">{</span>
                <span class="kt">int</span> <span class="n">doubleMoveSquare</span> <span class="o">=</span> <span class="n">square</span> <span class="o">+</span> <span class="o">((</span><span class="n">color</span> <span class="o">==</span> <span class="no">WHITE</span><span class="o">)</span> <span class="o">?</span> <span class="mi">16</span> <span class="o">:</span> <span class="o">-</span><span class="mi">16</span><span class="o">);</span>
                <span class="k">if</span> <span class="o">((</span><span class="n">doubleMoveSquare</span> <span class="o">&gt;=</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">doubleMoveSquare</span> <span class="o">&lt;</span> <span class="mi">64</span><span class="o">)</span> <span class="o">&amp;&amp;</span>
                        <span class="o">((</span><span class="n">occupied</span> <span class="o">&amp;</span> <span class="o">(</span><span class="mi">1L</span> <span class="o">&lt;&lt;</span> <span class="n">doubleMoveSquare</span><span class="o">))</span> <span class="o">==</span> <span class="mi">0</span><span class="o">)</span> <span class="o">&amp;&amp;</span>
                        <span class="o">((</span><span class="n">occupied</span> <span class="o">&amp;</span> <span class="o">(</span><span class="mi">1L</span> <span class="o">&lt;&lt;</span> <span class="n">targetSquare</span><span class="o">))</span> <span class="o">==</span> <span class="mi">0</span><span class="o">))</span> <span class="o">{</span>
                    <span class="n">moves</span> <span class="o">|=</span> <span class="o">(</span><span class="mi">1L</span> <span class="o">&lt;&lt;</span> <span class="n">doubleMoveSquare</span><span class="o">);</span>
                <span class="o">}</span>
            <span class="o">}</span>
        <span class="o">}</span>
        <span class="kt">int</span><span class="o">[]</span> <span class="n">captureSquares</span> <span class="o">=</span> <span class="o">{(</span><span class="n">color</span> <span class="o">==</span> <span class="no">WHITE</span><span class="o">)</span> <span class="o">?</span> <span class="n">square</span> <span class="o">+</span> <span class="mi">7</span> <span class="o">:</span> <span class="n">square</span> <span class="o">-</span> <span class="mi">7</span><span class="o">,</span> <span class="o">(</span><span class="n">color</span> <span class="o">==</span> <span class="no">WHITE</span><span class="o">)</span> <span class="o">?</span> <span class="n">square</span> <span class="o">+</span> <span class="mi">9</span> <span class="o">:</span> <span class="n">square</span> <span class="o">-</span> <span class="mi">9</span><span class="o">};</span>
        <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">captureSquare</span> <span class="o">:</span> <span class="n">captureSquares</span><span class="o">)</span> <span class="o">{</span>
            <span class="k">if</span> <span class="o">((</span><span class="n">captureSquare</span> <span class="o">&gt;=</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">captureSquare</span> <span class="o">&lt;</span> <span class="mi">64</span><span class="o">)</span> <span class="o">&amp;&amp;</span>
                    <span class="o">((</span><span class="n">occupied</span> <span class="o">&amp;</span> <span class="o">(</span><span class="mi">1L</span> <span class="o">&lt;&lt;</span> <span class="n">captureSquare</span><span class="o">))</span> <span class="o">!=</span> <span class="mi">0</span><span class="o">)</span> <span class="o">&amp;&amp;</span>
                    <span class="o">((</span><span class="mi">1L</span> <span class="o">&lt;&lt;</span> <span class="n">captureSquare</span><span class="o">)</span> <span class="o">&amp;</span> <span class="n">enemyPieces</span><span class="o">)</span> <span class="o">!=</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
                <span class="n">moves</span> <span class="o">|=</span> <span class="o">(</span><span class="mi">1L</span> <span class="o">&lt;&lt;</span> <span class="n">captureSquare</span><span class="o">);</span>
            <span class="o">}</span>
        <span class="o">}</span>
        <span class="k">return</span> <span class="n">moves</span><span class="o">;</span>
    <span class="o">}</span>
</code></pre></div></div>

<h2 id="the-knight-majestic-horse">The Knight (Majestic Horse)</h2>

<h4 id="directional-movements">Directional Movements</h4>

<ul>
  <li>Defines possible knight moves as horizontal and vertical components.</li>
</ul>

<h4 id="generating-moves">Generating Moves</h4>

<ul>
  <li>Iterates through directions to calculate potential target squares.
Sets corresponding bits in the moves bitboard for valid and unoccupied target squares.</li>
</ul>

<h4 id="return-value-1">Return value</h4>

<ul>
  <li>Returns a long integer (a bitboard) with bits set for all valid knight moves from the given square.</li>
</ul>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kd">public</span> <span class="kd">static</span> <span class="kt">long</span> <span class="nf">generateKnightMoves</span><span class="o">(</span><span class="kt">int</span> <span class="n">square</span><span class="o">,</span> <span class="kt">long</span> <span class="n">occupied</span><span class="o">)</span> <span class="o">{</span>
        <span class="kt">long</span> <span class="n">moves</span> <span class="o">=</span> <span class="mi">0L</span><span class="o">;</span>
        <span class="kt">int</span><span class="o">[]</span> <span class="n">directions</span> <span class="o">=</span> <span class="o">{</span><span class="mi">6</span><span class="o">,</span> <span class="mi">10</span><span class="o">,</span> <span class="mi">15</span><span class="o">,</span> <span class="mi">17</span><span class="o">,</span> <span class="o">-</span><span class="mi">6</span><span class="o">,</span> <span class="o">-</span><span class="mi">10</span><span class="o">,</span> <span class="o">-</span><span class="mi">15</span><span class="o">,</span> <span class="o">-</span><span class="mi">17</span><span class="o">};</span>

        <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">direction</span> <span class="o">:</span> <span class="n">directions</span><span class="o">)</span> <span class="o">{</span>
            <span class="kt">int</span> <span class="n">targetSquare</span> <span class="o">=</span> <span class="n">square</span> <span class="o">+</span> <span class="n">direction</span><span class="o">;</span>
            <span class="k">if</span> <span class="o">((</span><span class="n">targetSquare</span> <span class="o">&gt;=</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">targetSquare</span> <span class="o">&lt;</span> <span class="mi">64</span><span class="o">)</span> <span class="o">&amp;&amp;</span> <span class="o">((</span><span class="n">occupied</span> <span class="o">&amp;</span> <span class="o">(</span><span class="mi">1L</span> <span class="o">&lt;&lt;</span> <span class="n">targetSquare</span><span class="o">))</span> <span class="o">==</span> <span class="mi">0</span><span class="o">))</span> <span class="o">{</span>
                <span class="n">moves</span> <span class="o">|=</span> <span class="o">(</span><span class="mi">1L</span> <span class="o">&lt;&lt;</span> <span class="n">targetSquare</span><span class="o">);</span>
            <span class="o">}</span>
        <span class="o">}</span>
        <span class="k">return</span> <span class="n">moves</span><span class="o">;</span>
    <span class="o">}</span>
</code></pre></div></div>

<h2 id="the-bishop">The Bishop</h2>

<h3 id="diagonal-movement">Diagonal Movement</h3>

<ul>
  <li>Represents bishop moves as diagonal paths on the chessboard.</li>
</ul>

<h3 id="generating-moves-1">Generating Moves:</h3>

<ul>
  <li>Iterates through diagonal directions to calculate potential target squares.
Sets corresponding bits in the moves bitboard for valid and unoccupied target squares.</li>
</ul>

<h3 id="return-value-2">Return value</h3>

<ul>
  <li>Returns a long integer (bitboard) with bits set for all valid bishop moves from the given square.</li>
</ul>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">static</span> <span class="kt">long</span> <span class="nf">generateBishopMoves</span><span class="o">(</span><span class="kt">int</span> <span class="n">square</span><span class="o">,</span> <span class="kt">long</span> <span class="n">occupied</span><span class="o">)</span> <span class="o">{</span>
    <span class="kt">long</span> <span class="n">moves</span> <span class="o">=</span> <span class="mi">0L</span><span class="o">;</span>
    <span class="kt">int</span><span class="o">[]</span> <span class="n">directions</span> <span class="o">=</span> <span class="o">{</span><span class="mi">7</span><span class="o">,</span> <span class="mi">9</span><span class="o">,</span> <span class="o">-</span><span class="mi">7</span><span class="o">,</span> <span class="o">-</span><span class="mi">9</span><span class="o">};</span>

    <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">direction</span> <span class="o">:</span> <span class="n">directions</span><span class="o">)</span> <span class="o">{</span>
        <span class="kt">int</span> <span class="n">targetSquare</span> <span class="o">=</span> <span class="n">square</span> <span class="o">+</span> <span class="n">direction</span><span class="o">;</span>
        <span class="k">while</span> <span class="o">(</span><span class="n">targetSquare</span> <span class="o">&gt;=</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">targetSquare</span> <span class="o">&lt;</span> <span class="mi">64</span> <span class="o">&amp;&amp;</span> <span class="o">((</span><span class="n">occupied</span> <span class="o">&amp;</span> <span class="o">(</span><span class="mi">1L</span> <span class="o">&lt;&lt;</span> <span class="n">targetSquare</span><span class="o">))</span> <span class="o">==</span> <span class="mi">0</span><span class="o">))</span> <span class="o">{</span>
            <span class="n">moves</span> <span class="o">|=</span> <span class="o">(</span><span class="mi">1L</span> <span class="o">&lt;&lt;</span> <span class="n">targetSquare</span><span class="o">);</span>
            <span class="n">targetSquare</span> <span class="o">+=</span> <span class="n">direction</span><span class="o">;</span>
        <span class="o">}</span>
    <span class="o">}</span>
    <span class="k">return</span> <span class="n">moves</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>

<h2 id="the-rook">The Rook</h2>

<h3 id="orthogonal-movement">Orthogonal Movement</h3>

<ul>
  <li>Represents rook moves as orthogonal paths on the chessboard.</li>
</ul>

<h3 id="generating-moves-2">Generating Moves</h3>

<ul>
  <li>Iterates through orthogonal directions to calculate potential target squares.
Sets corresponding bits in the moves bitboard for valid and unoccupied target squares.</li>
</ul>

<h3 id="return-value-3">Return Value</h3>

<ul>
  <li>Returns a long integer (bitboard) with bits set for all valid rook moves from the given square.</li>
</ul>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">static</span> <span class="kt">long</span> <span class="nf">generateRookMoves</span><span class="o">(</span><span class="kt">int</span> <span class="n">square</span><span class="o">,</span> <span class="kt">long</span> <span class="n">occupied</span><span class="o">)</span> <span class="o">{</span>
    <span class="kt">long</span> <span class="n">moves</span> <span class="o">=</span> <span class="mi">0L</span><span class="o">;</span>
    <span class="kt">int</span><span class="o">[]</span> <span class="n">directions</span> <span class="o">=</span> <span class="o">{</span><span class="mi">8</span><span class="o">,</span> <span class="mi">1</span><span class="o">,</span> <span class="o">-</span><span class="mi">8</span><span class="o">,</span> <span class="o">-</span><span class="mi">1</span><span class="o">};</span>

    <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">direction</span> <span class="o">:</span> <span class="n">directions</span><span class="o">)</span> <span class="o">{</span>
        <span class="kt">int</span> <span class="n">targetSquare</span> <span class="o">=</span> <span class="n">square</span> <span class="o">+</span> <span class="n">direction</span><span class="o">;</span>
        <span class="k">while</span> <span class="o">(</span><span class="n">targetSquare</span> <span class="o">&gt;=</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">targetSquare</span> <span class="o">&lt;</span> <span class="mi">64</span> <span class="o">&amp;&amp;</span> <span class="o">((</span><span class="n">occupied</span> <span class="o">&amp;</span> <span class="o">(</span><span class="mi">1L</span> <span class="o">&lt;&lt;</span> <span class="n">targetSquare</span><span class="o">))</span> <span class="o">==</span> <span class="mi">0</span><span class="o">))</span> <span class="o">{</span>
            <span class="n">moves</span> <span class="o">|=</span> <span class="o">(</span><span class="mi">1L</span> <span class="o">&lt;&lt;</span> <span class="n">targetSquare</span><span class="o">);</span>
            <span class="n">targetSquare</span> <span class="o">+=</span> <span class="n">direction</span><span class="o">;</span>
        <span class="o">}</span>
    <span class="o">}</span>
    <span class="k">return</span> <span class="n">moves</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>

<h2 id="the-queen">The Queen</h2>

<h3 id="combination-of-bishop-and-rook-moves">Combination of Bishop and Rook Moves</h3>

<ul>
  <li>Combines the movement patterns of bishops and rooks, allowing both diagonal and orthogonal paths.</li>
</ul>

<h3 id="generating-moves-3">Generating Moves</h3>

<ul>
  <li>Iterates through combined diagonal and orthogonal directions to calculate potential target squares.
Sets corresponding bits in the moves bitboard for valid and unoccupied target squares.</li>
</ul>

<h3 id="return-value-4">Return Value</h3>

<ul>
  <li>Returns a long integer (bitboard) with bits set for all valid queen moves from the given square.</li>
</ul>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">static</span> <span class="kt">long</span> <span class="nf">generateQueenMoves</span><span class="o">(</span><span class="kt">int</span> <span class="n">square</span><span class="o">,</span> <span class="kt">long</span> <span class="n">occupied</span><span class="o">)</span> <span class="o">{</span>
    <span class="kt">long</span> <span class="n">moves</span> <span class="o">=</span> <span class="mi">0L</span><span class="o">;</span>
    <span class="kt">int</span><span class="o">[]</span> <span class="n">directions</span> <span class="o">=</span> <span class="o">{</span><span class="mi">7</span><span class="o">,</span> <span class="mi">9</span><span class="o">,</span> <span class="o">-</span><span class="mi">7</span><span class="o">,</span> <span class="o">-</span><span class="mi">9</span><span class="o">,</span> <span class="mi">8</span><span class="o">,</span> <span class="mi">1</span><span class="o">,</span> <span class="o">-</span><span class="mi">8</span><span class="o">,</span> <span class="o">-</span><span class="mi">1</span><span class="o">};</span>

    <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">direction</span> <span class="o">:</span> <span class="n">directions</span><span class="o">)</span> <span class="o">{</span>
        <span class="kt">int</span> <span class="n">targetSquare</span> <span class="o">=</span> <span class="n">square</span> <span class="o">+</span> <span class="n">direction</span><span class="o">;</span>
        <span class="k">while</span> <span class="o">(</span><span class="n">targetSquare</span> <span class="o">&gt;=</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">targetSquare</span> <span class="o">&lt;</span> <span class="mi">64</span> <span class="o">&amp;&amp;</span> <span class="o">((</span><span class="n">occupied</span> <span class="o">&amp;</span> <span class="o">(</span><span class="mi">1L</span> <span class="o">&lt;&lt;</span> <span class="n">targetSquare</span><span class="o">))</span> <span class="o">==</span> <span class="mi">0</span><span class="o">))</span> <span class="o">{</span>
            <span class="n">moves</span> <span class="o">|=</span> <span class="o">(</span><span class="mi">1L</span> <span class="o">&lt;&lt;</span> <span class="n">targetSquare</span><span class="o">);</span>
            <span class="n">targetSquare</span> <span class="o">+=</span> <span class="n">direction</span><span class="o">;</span>
        <span class="o">}</span>
    <span class="o">}</span>
    <span class="k">return</span> <span class="n">moves</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>

<h2 id="the-king">The King</h2>

<h3 id="adjacent-movements">Adjacent Movements</h3>

<ul>
  <li>Represents king moves as adjacent squares in all eight directions.</li>
</ul>

<h3 id="generating-moves-4">Generating Moves</h3>

<ul>
  <li>Iterates through all directions to calculate potential target squares.
Sets corresponding bits in the moves bitboard for valid and unoccupied target squares.</li>
</ul>

<h3 id="return-value-5">Return Value</h3>

<ul>
  <li>Returns a long integer (bitboard) with bits set for all valid king moves from the given square.</li>
</ul>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">static</span> <span class="kt">long</span> <span class="nf">generateKingMoves</span><span class="o">(</span><span class="kt">int</span> <span class="n">square</span><span class="o">,</span> <span class="kt">long</span> <span class="n">occupied</span><span class="o">)</span> <span class="o">{</span>
    <span class="kt">long</span> <span class="n">moves</span> <span class="o">=</span> <span class="mi">0L</span><span class="o">;</span>
    <span class="kt">int</span><span class="o">[]</span> <span class="n">directions</span> <span class="o">=</span> <span class="o">{</span><span class="mi">7</span><span class="o">,</span> <span class="mi">8</span><span class="o">,</span> <span class="mi">9</span><span class="o">,</span> <span class="o">-</span><span class="mi">7</span><span class="o">,</span> <span class="o">-</span><span class="mi">8</span><span class="o">,</span> <span class="o">-</span><span class="mi">9</span><span class="o">,</span> <span class="mi">1</span><span class="o">,</span> <span class="o">-</span><span class="mi">1</span><span class="o">};</span>

    <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">direction</span> <span class="o">:</span> <span class="n">directions</span><span class="o">)</span> <span class="o">{</span>
        <span class="kt">int</span> <span class="n">targetSquare</span> <span class="o">=</span> <span class="n">square</span> <span class="o">+</span> <span class="n">direction</span><span class="o">;</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">targetSquare</span> <span class="o">&gt;=</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">targetSquare</span> <span class="o">&lt;</span> <span class="mi">64</span> <span class="o">&amp;&amp;</span> <span class="o">((</span><span class="n">occupied</span> <span class="o">&amp;</span> <span class="o">(</span><span class="mi">1L</span> <span class="o">&lt;&lt;</span> <span class="n">targetSquare</span><span class="o">))</span> <span class="o">==</span> <span class="mi">0</span><span class="o">))</span> <span class="o">{</span>
            <span class="n">moves</span> <span class="o">|=</span> <span class="o">(</span><span class="mi">1L</span> <span class="o">&lt;&lt;</span> <span class="n">targetSquare</span><span class="o">);</span>
        <span class="o">}</span>
    <span class="o">}</span>
    <span class="k">return</span> <span class="n">moves</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>

<h2 id="to-conclude">To Conclude</h2>

<p>If you got this far, congratulations! The idea behind bitboards is relatively simple, however implementations can certainly be nuanced.</p>

<p>I have quite a few creative ideas that can be implemented for different variants of Chess, so this post was made minimal and concise for viewer understanding.</p>

<h3 id="recommendations">Recommendations</h3>

<ul>
  <li>
    <p>A video visually explaining bitboards by Holistic3D <a href="https://youtu.be/MzfQ8H16n0M?si=FEtGqBc9qxAELrOG">here</a></p>
  </li>
  <li>
    <p>The chessprogramming.org wiki articles <a href="https://www.chessprogramming.org/Bitboards#General_Bitboard_Techniques"> here </a></p>
  </li>
</ul>

<p><i> If you’d like to play a chess game, contact me! </i></p>]]></content><author><name>qbb84</name></author><category term="Chess" /><category term="Bitboards" /><category term="Technical" /><category term="Informative" /><summary type="html"><![CDATA[Chess, often considered the king of strategy games, has captivated minds for centuries. Behind the scenes of every formidable chess engine lies a sophisticated representation of the chessboard and its pieces. In the realm of chess engine development, one powerful technique stands out: bitboards.]]></summary></entry><entry><title type="html">Graph Algorithm Visualizer</title><link href="https://qbb84.github.io/graph-algorithm-visualizer" rel="alternate" type="text/html" title="Graph Algorithm Visualizer" /><published>2023-09-08T00:00:00+00:00</published><updated>2023-09-08T00:00:00+00:00</updated><id>https://qbb84.github.io/Graph-Algorithm-Visualizer</id><content type="html" xml:base="https://qbb84.github.io/graph-algorithm-visualizer"><![CDATA[<p>A helper application made with Java, utilizing Swing, that helps users visualize certain algorithms on Graphs like Dijkstra’s, Prim’s and more.</p>

<h3 id="features">Features</h3>

<ol>
  <li>Vertex Creation/Removal</li>
  <li>Edge Creation/Removal</li>
  <li>New graph state</li>
  <li>Algorithms input, as well as built-in testing algorithms</li>
</ol>

<h4 id="early-development-footage">Early Development Footage</h4>

<p><img src="/images/Picture1.png" /></p>

<p>You’ll be able to access the repository, and download once I release the application <a href="https://github.com/qbb84/AlgorithmVisualizer"> here</a>.</p>]]></content><author><name>qbb84</name></author><category term="Graph" /><category term="Algorithms" /><category term="Visualizer" /><summary type="html"><![CDATA[A helper application made with Java, utilizing Swing, that helps users visualize certain algorithms on Graphs like Dijkstra’s, Prim’s and more.]]></summary></entry><entry><title type="html">Lightweight Rust Interpreter</title><link href="https://qbb84.github.io/lightweight-rust-interpreter" rel="alternate" type="text/html" title="Lightweight Rust Interpreter" /><published>2023-09-05T00:00:00+00:00</published><updated>2023-09-05T00:00:00+00:00</updated><id>https://qbb84.github.io/Lightweight-Rust-Interpreter</id><content type="html" xml:base="https://qbb84.github.io/lightweight-rust-interpreter"><![CDATA[<p><i>This is a technical post regarding lri, I will try to provide explanation with example snippets.</i></p>

<p>lri is a project born out of a desire to deepen my understanding of the Rust programming language. As a passionate developer, I recognized the value of hands-on experience, and building an interpreter provided an excellent opportunity to explore Rust’s unique features and challenges.</p>

<h2 id="1-what-is-an-interpreter">1. What is an Interpreter?</h2>

<p>An interpreter is a program that reads and executes code directly, without the need for a separate compilation step. It takes source code as input and interprets it on the fly, executing the instructions one at a time which can be useful for ease of development, portability, dynamic typing, and more.</p>

<p>Some popular languages which commonly use interpreters include:</p>

<ul>
  <li>Python</li>
  <li>Javascript</li>
  <li>Ruby</li>
  <li>PHP</li>
</ul>

<h2 id="2-lexical-analysis">2. Lexical Analysis:</h2>

<p>Lexical analysis is the process of breaking the input code into meaningful units called tokens. Tokens are the smallest units of a program, such as keywords, identifiers, literals, and operators. In the context of lri, lexical analysis involves scanning the input Rust code and identifying and categorizing these tokens.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="n">Lexer</span> <span class="p">{</span> <span class="n">input</span><span class="p">:</span> <span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">char</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">position</span><span class="p">:</span> <span class="nb">usize</span><span class="p">,</span> <span class="n">read_position</span><span class="p">:</span> <span class="nb">usize</span><span class="p">,</span> <span class="n">ch</span><span class="p">:</span> <span class="nb">char</span> <span class="p">}</span>

<span class="k">impl</span> <span class="n">Lexer</span> <span class="p">{</span>
    <span class="k">pub</span> <span class="k">fn</span> <span class="nf">new</span><span class="p">(</span><span class="n">input</span><span class="p">:</span> <span class="o">&amp;</span><span class="nb">str</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="n">Lexer</span> <span class="p">{</span> <span class="n">Lexer</span> <span class="p">{</span> <span class="n">input</span><span class="p">:</span> <span class="n">input</span><span class="nf">.chars</span><span class="p">()</span><span class="nf">.collect</span><span class="p">(),</span> <span class="n">position</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span> <span class="n">read_position</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span> <span class="n">ch</span><span class="p">:</span> <span class="sc">'\0'</span> <span class="p">}</span> <span class="p">}</span>
    <span class="k">fn</span> <span class="nf">next_token</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="n">Token</span> <span class="p">{</span> <span class="k">self</span><span class="nf">.skip_whitespace</span><span class="p">();</span> <span class="k">let</span> <span class="n">token</span> <span class="o">=</span> <span class="k">match</span> <span class="k">self</span><span class="py">.ch</span> <span class="p">{</span> <span class="sc">'='</span> <span class="k">=&gt;</span> <span class="nn">Lexer</span><span class="p">::</span><span class="nf">new_token</span><span class="p">(</span><span class="nn">TokenKind</span><span class="p">::</span><span class="n">ASSIGN</span><span class="p">,</span> <span class="k">self</span><span class="py">.ch</span><span class="p">),</span> <span class="sc">';'</span> <span class="k">=&gt;</span> <span class="nn">Lexer</span><span class="p">::</span><span class="nf">new_token</span><span class="p">(</span><span class="nn">TokenKind</span><span class="p">::</span><span class="n">SEMICOLON</span><span class="p">,</span> <span class="k">self</span><span class="py">.ch</span><span class="p">),</span> <span class="sc">'('</span><span class="o">..=</span><span class="sc">'}'</span> <span class="k">=&gt;</span> <span class="nn">Lexer</span><span class="p">::</span><span class="nf">new_token</span><span class="p">(</span><span class="nn">TokenKind</span><span class="p">::</span><span class="nf">from</span><span class="p">(</span><span class="k">self</span><span class="py">.ch</span><span class="p">),</span> <span class="k">self</span><span class="py">.ch</span><span class="p">),</span> <span class="n">_</span> <span class="k">=&gt;</span> <span class="nn">Lexer</span><span class="p">::</span><span class="nf">classify_token</span><span class="p">(</span><span class="k">self</span><span class="py">.ch</span><span class="p">),</span> <span class="p">};</span> <span class="k">self</span><span class="nf">.read_char</span><span class="p">();</span> <span class="n">token</span> <span class="p">}</span>
    <span class="k">fn</span> <span class="nf">classify_token</span><span class="p">(</span><span class="n">ch</span><span class="p">:</span> <span class="nb">char</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="n">Token</span> <span class="p">{</span> <span class="k">match</span> <span class="n">ch</span> <span class="p">{</span> <span class="n">_</span> <span class="k">if</span> <span class="nn">Lexer</span><span class="p">::</span><span class="nf">is_letter</span><span class="p">(</span><span class="n">ch</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="n">Token</span> <span class="p">{</span> <span class="n">kind</span><span class="p">:</span> <span class="nf">lookup_ident</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="nf">.read_identifier</span><span class="p">()),</span> <span class="n">literal</span><span class="p">:</span> <span class="nn">String</span><span class="p">::</span><span class="nf">new</span><span class="p">()</span> <span class="p">},</span> <span class="n">_</span> <span class="k">if</span> <span class="nn">Lexer</span><span class="p">::</span><span class="nf">is_digit</span><span class="p">(</span><span class="n">ch</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="n">Token</span> <span class="p">{</span> <span class="n">kind</span><span class="p">:</span> <span class="nn">TokenKind</span><span class="p">::</span><span class="n">INT</span><span class="p">,</span> <span class="n">literal</span><span class="p">:</span> <span class="k">self</span><span class="nf">.read_number</span><span class="p">()</span> <span class="p">},</span> <span class="n">_</span> <span class="k">=&gt;</span> <span class="nn">Lexer</span><span class="p">::</span><span class="nf">new_token</span><span class="p">(</span><span class="nn">TokenKind</span><span class="p">::</span><span class="n">ILLEGAL</span><span class="p">,</span> <span class="n">ch</span><span class="p">),</span> <span class="p">}</span> <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="3-parsing">3. Parsing</h2>

<p>Parsing is the process of taking the stream of tokens generated by lexical analysis and converting it into a structured representation, often represented as an Abstract Syntax Tree (AST). The AST reflects the hierarchical structure of the code and makes it easier to analyze and execute.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="nf">parse</span><span class="p">(</span><span class="n">tokens</span><span class="p">:</span> <span class="nb">Vec</span><span class="o">&lt;</span><span class="n">Token</span><span class="o">&gt;</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="n">ASTNode</span> <span class="p">{</span>
    <span class="c1">// Implementation of parsing goes here</span>
    <span class="c1">// Build an Abstract Syntax Tree (AST) from the tokens</span>
    <span class="c1">// Return the root of the AST</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="work-in-progress-wip">Work in Progress (WIP)</h2>

<p>Given that lri is in its early development stages, this was a showcase of how some of the systems function, in simplistic terms.</p>

<p>Remember, this is a simplified representation, and the actual implementation may involve more complexity, especially considering the features and nuances of the Rust programming language.</p>

<p>You can view the repository <a href="https://github.com/qbb84/lri">here</a></p>]]></content><author><name>qbb84</name></author><category term="Rust" /><category term="Interpreter" /><summary type="html"><![CDATA[This is a technical post regarding lri, I will try to provide explanation with example snippets.]]></summary></entry><entry><title type="html">Threejs Project</title><link href="https://qbb84.github.io/threejs-project" rel="alternate" type="text/html" title="Threejs Project" /><published>2023-05-01T00:00:00+00:00</published><updated>2023-05-01T00:00:00+00:00</updated><id>https://qbb84.github.io/ThreeJS-Project</id><content type="html" xml:base="https://qbb84.github.io/threejs-project"><![CDATA[<p>ThreeJS-powered website meticulously crafted using Javascript, Typescript, React, and React Three Fiber. As the creator, I delved into the intricate technicalities, making strategic decisions to enhance performance and ensure code elegance.</p>

<h2 id="multiple-objects-are-interactable">Multiple Objects are interactable</h2>

<p>At the heart of this project lies a meticulously designed 3D mesh representation of my bedroom, complemented by a creative loading screen that sets the stage for an immersive experience. Engage with the interactive portfolio, where the computer monitor reveals insights about the creator and showcases a dynamic portfolio screen.</p>

<h2 id="beyond-the-ordinary">Beyond the Ordinary</h2>

<ul>
  <li>Chessboard Challenge: You are able to immerse yourself in a game of chess on a thoughtfully designed chessboard.</li>
  <li>Mirror Reflection: A mirror that reflects more than just a visual representation.</li>
  <li>First Person Controls: A first-person perspective that puts you in the center of this digital adventure.</li>
</ul>

<hr />

<h2 id="improving-performance">Improving Performance</h2>

<p>Here will be a glimpse of how I worked to improve performance, and reduce load times.</p>

<h3 id="how-did-i-know-when-the-performance-was-declining">How did I know when the performance was declining?</h3>

<p>Firstly, it’s important to understand that there can be a multitude of different reasons for ill-performance during development, especially game development, and performance issues are usually quite simple to track down.</p>

<p>I used a performance monitor to track the stress of the GPU/CPU of my scene - using this, I was able to easily discover issues I had made. Before I proceed, I’d like to note that the creation and manipulation of 3D objects are managed by the CPU, and the rendering and display of meshes occur on the GPU. Let’s proceed.</p>

<p>Here is a basic component, similar to how I loaded my GLTF textures:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">export</span> <span class="kd">function</span> <span class="nx">Room</span><span class="p">(</span><span class="nx">props</span><span class="p">:</span> <span class="nx">JSX</span><span class="p">.</span><span class="nx">IntrinsicElements</span><span class="p">[</span><span class="dl">'</span><span class="s1">group</span><span class="dl">'</span><span class="p">])</span> <span class="p">{</span>
  <span class="kd">const</span> <span class="p">{</span> <span class="nx">nodes</span><span class="p">,</span> <span class="nx">materials</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">useGLTF</span><span class="p">(</span><span class="dl">'</span><span class="s1">/Portfolio_room.glb</span><span class="dl">'</span><span class="p">)</span> <span class="k">as</span> <span class="nx">GLTFResult</span><span class="p">;</span>
  <span class="kd">const</span> <span class="p">{</span> <span class="nx">isVisible</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">useContext</span><span class="p">(</span><span class="nx">VisibilityContext</span><span class="p">);</span>

  <span class="kd">const</span> <span class="nx">bedRef</span> <span class="o">=</span> <span class="nx">useRef</span><span class="p">();</span>
  <span class="kd">const</span> <span class="nx">roomRef</span> <span class="o">=</span> <span class="nx">useRef</span><span class="p">();</span>

  <span class="k">return</span> <span class="p">(</span>
    <span class="o">&lt;&gt;</span>
      <span class="o">&lt;</span><span class="nx">group</span> <span class="p">{...</span><span class="nx">props</span><span class="p">}</span> <span class="nx">dispose</span><span class="o">=</span><span class="p">{</span><span class="kc">null</span><span class="p">}</span> <span class="nx">ref</span><span class="o">=</span><span class="p">{</span><span class="nx">roomRef</span><span class="p">}</span><span class="o">&gt;</span>
        <span class="o">&lt;</span><span class="nx">group</span> <span class="nx">name</span><span class="o">=</span><span class="dl">"</span><span class="s2">Bed</span><span class="dl">"</span> <span class="nx">ref</span><span class="o">=</span><span class="p">{</span><span class="nx">bedRef</span><span class="p">}</span><span class="o">&gt;</span>
          <span class="o">&lt;</span><span class="nx">mesh</span>
            <span class="nx">name</span><span class="o">=</span><span class="dl">"</span><span class="s2">Bed_Pillows</span><span class="dl">"</span>
            <span class="nx">geometry</span><span class="o">=</span><span class="p">{</span><span class="nx">nodes</span><span class="p">.</span><span class="nx">Box002_Baked</span><span class="p">.</span><span class="nx">geometry</span><span class="p">}</span>
            <span class="c1">// material={materials.Objs2_Baked}</span>
            <span class="nx">position</span><span class="o">=</span><span class="p">{[</span><span class="o">-</span><span class="mf">6.907</span><span class="p">,</span> <span class="mf">2.052</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.094</span><span class="p">]}</span>
            <span class="nx">rotation</span><span class="o">=</span><span class="p">{[</span><span class="o">-</span><span class="mf">0.898</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">]}</span>
            <span class="nx">material</span><span class="o">=</span><span class="p">{</span><span class="nx">materials</span><span class="p">.</span><span class="nx">Objs2_Baked</span><span class="p">}</span>
            <span class="nx">userData</span><span class="o">=</span>
          <span class="sr">/</span><span class="err">&gt;
</span>      <span class="o">&lt;</span><span class="sr">/group</span><span class="err">&gt;
</span>        <span class="o">&lt;</span><span class="sr">/group</span><span class="err">&gt;
</span>    <span class="o">&lt;</span><span class="sr">/</span><span class="err">&gt;
</span>  <span class="p">);</span>

</code></pre></div></div>

<p>This component was called inside another component like this:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">export</span> <span class="k">default</span> <span class="kd">function</span> <span class="nx">loading</span><span class="p">()</span> <span class="p">{</span>
  <span class="kd">const</span> <span class="p">[</span><span class="nx">isRoomVisible</span><span class="p">,</span> <span class="nx">setRoomVisible</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">(</span><span class="kc">true</span><span class="p">);</span>

  <span class="nx">useEffect</span><span class="p">(()</span> <span class="o">=&gt;</span> <span class="p">{</span>
    <span class="kd">const</span> <span class="nx">animationFrameId</span> <span class="o">=</span> <span class="nx">requestAnimationFrame</span><span class="p">(()</span> <span class="o">=&gt;</span> <span class="p">{</span>
      <span class="nx">setRoomVisible</span><span class="p">((</span><span class="nx">prevVisible</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="o">!</span><span class="nx">prevVisible</span><span class="p">);</span>
    <span class="p">});</span>

    <span class="k">return</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="nx">cancelAnimationFrame</span><span class="p">(</span><span class="nx">animationFrameId</span><span class="p">);</span>
  <span class="p">});</span>

  <span class="k">return</span> <span class="o">&lt;&gt;</span><span class="p">{</span><span class="nx">isRoomVisible</span> <span class="o">&amp;&amp;</span> <span class="o">&lt;</span><span class="nx">Room</span> <span class="o">/&gt;</span><span class="p">}</span><span class="o">&lt;</span><span class="sr">/&gt;</span><span class="err">;
</span><span class="p">}</span>
</code></pre></div></div>

<p>The code above isn’t correct, but why? Well, because the room is being set visible on every frame, which will cause strenuous load on the GPU and CPU - Imagine every time you walked downstairs, you ended up on top of the stairs, after a while you’re going to become tired, and as such, the website eventually will become unusable. Let’s dive deeper.</p>

<h2 id="utilizing-big-o-notation">Utilizing Big O Notation</h2>

<h3 id="what-is-the-big-o">What is the “Big O”?</h3>

<p>Big O notation is a way to describe the efficiency of an algorithm or the performance of a piece of code. It provides a standardized method for expressing the upper bound of the time complexity or space complexity of an algorithm in relation to its input size.</p>

<p>In simpler terms, Big O notation helps us understand how the performance of an algorithm scales as the size of the input (e.g., the number of elements in a list) increases. It’s a way to analyze and compare algorithms, enabling us to choose the most efficient solution for a given problem.</p>

<p>Let’s say you use a loop to manipulate pixels in an 2D array of a large image like this:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">images</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">j</span> <span class="o">&lt;</span> <span class="nx">images</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">j</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
    <span class="c1">// Simulate manipulation of pixels inside an image</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>This loop is running in quadratic time complexity O(n^2). Can we achieve faster performance?</p>

<p>Since our pixels are stored inside a 2D array, if we know the image width and height, we can linearly loop through the image width * height, and get each pixel inside the array using some arithmetic like so:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">imageWidth</span> <span class="o">=</span> <span class="mi">42</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">imageHeight</span> <span class="o">=</span> <span class="mi">21</span><span class="p">;</span>

<span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">imageWidth</span> <span class="o">*</span> <span class="nx">imageHeight</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
  <span class="kd">const</span> <span class="nx">row</span> <span class="o">=</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">floor</span><span class="p">(</span><span class="nx">i</span> <span class="o">/</span> <span class="nx">imageWidth</span><span class="p">);</span>
  <span class="kd">const</span> <span class="nx">col</span> <span class="o">=</span> <span class="nx">i</span> <span class="o">%</span> <span class="nx">imageWidth</span><span class="p">;</span>

  <span class="c1">// Simulate manipulation of pixels inside an image</span>
  <span class="kd">const</span> <span class="nx">pixelValue</span> <span class="o">=</span> <span class="nx">pixels</span><span class="p">[</span><span class="nx">row</span><span class="p">][</span><span class="nx">col</span><span class="p">];</span>
  <span class="c1">// Do something with the pixel value</span>
<span class="p">}</span>
</code></pre></div></div>

<p>It’s important to be cognizant of little changes like these which improve the time complexity to linear O(n). This was a more simpler example of how I improved performance of various parts of code inside my codebase.</p>

<h2 id="updates">Updates</h2>

<ul>
  <li>I expect to release the site this year, and at the time Im writing this post I’m getting close to a beta build.</li>
  <li>The Chess board uses a design similar to bitboard engines, we love bytes!</li>
  <li>Recently implemented working Computer Monitors</li>
</ul>

<p>Here’s a sneak peak of the loading scene (low fps gif):</p>

<p><img style="border-radius: 8px;" src="/images/sneakpeak.gif" /></p>]]></content><author><name>qbb84</name></author><category term="Three.JS" /><category term="Full-Stack" /><category term="JavaScript" /><category term="Typescript" /><category term="R3F" /><category term="React" /><category term="HTML" /><category term="CSS" /><summary type="html"><![CDATA[ThreeJS-powered website meticulously crafted using Javascript, Typescript, React, and React Three Fiber. As the creator, I delved into the intricate technicalities, making strategic decisions to enhance performance and ensure code elegance.]]></summary></entry><entry><title type="html">Network Levelling</title><link href="https://qbb84.github.io/network-levelling" rel="alternate" type="text/html" title="Network Levelling" /><published>2023-03-15T00:00:00+00:00</published><updated>2023-03-15T00:00:00+00:00</updated><id>https://qbb84.github.io/Network-Levelling</id><content type="html" xml:base="https://qbb84.github.io/network-levelling"><![CDATA[<p><i> This is a technical post regarding Network Levelling, and the tools I used to design a rigorous plugin for Minecraft networks.</i></p>

<h2 id="the-design">The Design</h2>

<p>I find it quite important to start any large project with some form of design documentation so that there’s a centralized, and highly specialized location of ideas, and sharing the documentation with others developers (if you work on a team).</p>

<p>If I have some form of control with design then I tend to go with mind maps for clarity. This is the approach I used within contract positions, and during freelance development.</p>

<p>Below will contain the features, followed by an example design documentation.</p>

<h4 id="linear-levelling-progression">Linear Levelling Progression</h4>

<ul>
  <li>The required XP increases linearly with the player’s level.</li>
  <li>Example: 2500, 5000, 7500, etc.</li>
  <li>Customizable: Base increase of 3500*n.</li>
</ul>

<h4 id="exponential-levelling-progression">Exponential Levelling Progression</h4>

<ul>
  <li>The required XP increases exponentially with the player’s level.</li>
  <li>Common in MMOS/RPGs like WoW.</li>
</ul>

<h4 id="polynomial-levelling-progression">Polynomial Levelling Progression</h4>

<ul>
  <li>The required XP increases according to a power of the player’s level.</li>
  <li>Similar to games like FFXIV, POE, Diablo 3, Skyrim, Oblivion.</li>
</ul>

<h4 id="boosters">Boosters</h4>

<ul>
  <li>Boosters are implemented to enhance XP gain for players.</li>
  <li>Customizable: Boost percentages, duration, etc.</li>
</ul>

<h4 id="discord-integreation">Discord Integreation</h4>

<ul>
  <li>Discord integration for level updates by proxy.</li>
</ul>

<h4 id="notifiers-for-best-player-experience">Notifiers for Best Player Experience</h4>

<ul>
  <li>includes notifiers to enhance the overall player experience.</li>
</ul>

<h4 id="psychology-utilization">Psychology Utilization</h4>

<ul>
  <li>Utilizes researched psychological principles to optimize player engagement.</li>
</ul>

<h4 id="customization">Customization</h4>

<ul>
  <li>The system allows for easy customization of XP progression via config.</li>
</ul>

<p>Now the features are transparent, I spent time creating a design doc.</p>

<p>It’s important to encapsulate all the features, as well as any additional ideas you can think of, let yourself be creative. Here’s an image of the documentation:</p>

<div class="mxgraph" style="max-width:100%;border:1px solid transparent;" data-mxgraph="{&quot;highlight&quot;:&quot;#0000ff&quot;,&quot;nav&quot;:true,&quot;resize&quot;:true,&quot;toolbar&quot;:&quot;zoom layers tags lightbox&quot;,&quot;edit&quot;:&quot;_blank&quot;,&quot;xml&quot;:&quot;&lt;mxfile host=\&quot;Electron\&quot; modified=\&quot;2023-05-25T20:01:21.077Z\&quot; agent=\&quot;Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/21.2.8 Chrome/112.0.5615.165 Electron/24.2.0 Safari/537.36\&quot; etag=\&quot;xZ9k0fwbciAOoYujRb3c\&quot; version=\&quot;21.2.8\&quot; type=\&quot;device\&quot;&gt;\n  &lt;diagram id=\&quot;C5RBs43oDa-KdzZeNtuy\&quot; name=\&quot;Page-1\&quot;&gt;\n    &lt;mxGraphModel dx=\&quot;4261\&quot; dy=\&quot;2704\&quot; grid=\&quot;1\&quot; gridSize=\&quot;10\&quot; guides=\&quot;1\&quot; tooltips=\&quot;1\&quot; connect=\&quot;1\&quot; arrows=\&quot;1\&quot; fold=\&quot;1\&quot; page=\&quot;1\&quot; pageScale=\&quot;1\&quot; pageWidth=\&quot;827\&quot; pageHeight=\&quot;1169\&quot; math=\&quot;0\&quot; shadow=\&quot;0\&quot;&gt;\n      &lt;root&gt;\n        &lt;mxCell id=\&quot;WIyWlLk6GJQsqaUBKTNV-0\&quot; /&gt;\n        &lt;mxCell id=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-0\&quot; /&gt;\n        &lt;mxCell id=\&quot;WIyWlLk6GJQsqaUBKTNV-2\&quot; value=\&quot;\&quot; style=\&quot;rounded=0;html=1;jettySize=auto;orthogonalLoop=1;fontSize=11;endArrow=block;endFill=0;endSize=8;strokeWidth=1;shadow=0;labelBackgroundColor=none;edgeStyle=orthogonalEdgeStyle;\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot; source=\&quot;WIyWlLk6GJQsqaUBKTNV-3\&quot; edge=\&quot;1\&quot;&gt;\n          &lt;mxGeometry relative=\&quot;1\&quot; as=\&quot;geometry\&quot;&gt;\n            &lt;mxPoint x=\&quot;480\&quot; y=\&quot;550\&quot; as=\&quot;targetPoint\&quot; /&gt;\n          &lt;/mxGeometry&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-4\&quot; style=\&quot;edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;\&quot; edge=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot; source=\&quot;WIyWlLk6GJQsqaUBKTNV-3\&quot; target=\&quot;uOGT53f4ggUUIF5St2bJ-2\&quot;&gt;\n          &lt;mxGeometry relative=\&quot;1\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-38\&quot; style=\&quot;edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;\&quot; edge=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot; source=\&quot;WIyWlLk6GJQsqaUBKTNV-3\&quot; target=\&quot;uOGT53f4ggUUIF5St2bJ-35\&quot;&gt;\n          &lt;mxGeometry relative=\&quot;1\&quot; as=\&quot;geometry\&quot;&gt;\n            &lt;Array as=\&quot;points\&quot;&gt;\n              &lt;mxPoint x=\&quot;1100\&quot; y=\&quot;220\&quot; /&gt;\n              &lt;mxPoint x=\&quot;1100\&quot; y=\&quot;-25\&quot; /&gt;\n            &lt;/Array&gt;\n          &lt;/mxGeometry&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-39\&quot; style=\&quot;edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;\&quot; edge=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot; source=\&quot;WIyWlLk6GJQsqaUBKTNV-3\&quot; target=\&quot;uOGT53f4ggUUIF5St2bJ-3\&quot;&gt;\n          &lt;mxGeometry relative=\&quot;1\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-51\&quot; style=\&quot;edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;\&quot; edge=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot; source=\&quot;WIyWlLk6GJQsqaUBKTNV-3\&quot;&gt;\n          &lt;mxGeometry relative=\&quot;1\&quot; as=\&quot;geometry\&quot;&gt;\n            &lt;mxPoint x=\&quot;1320\&quot; y=\&quot;220\&quot; as=\&quot;targetPoint\&quot; /&gt;\n          &lt;/mxGeometry&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-62\&quot; style=\&quot;edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;\&quot; edge=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot; source=\&quot;WIyWlLk6GJQsqaUBKTNV-3\&quot; target=\&quot;uOGT53f4ggUUIF5St2bJ-61\&quot;&gt;\n          &lt;mxGeometry relative=\&quot;1\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-104\&quot; style=\&quot;edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=1;entryY=0.5;entryDx=0;entryDy=0;\&quot; edge=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot; source=\&quot;WIyWlLk6GJQsqaUBKTNV-3\&quot; target=\&quot;uOGT53f4ggUUIF5St2bJ-23\&quot;&gt;\n          &lt;mxGeometry relative=\&quot;1\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;WIyWlLk6GJQsqaUBKTNV-3\&quot; value=\&quot;&amp;lt;font style=&amp;quot;font-size: 15px;&amp;quot;&amp;gt;Network Levelling&amp;amp;nbsp;&amp;lt;/font&amp;gt;\&quot; style=\&quot;rounded=1;whiteSpace=wrap;html=1;fontSize=12;glass=0;strokeWidth=1;shadow=1;fillColor=#d5e8d4;strokeColor=#82b366;\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot; vertex=\&quot;1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;360\&quot; y=\&quot;150\&quot; width=\&quot;240\&quot; height=\&quot;140\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-10\&quot; style=\&quot;edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;\&quot; edge=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot; source=\&quot;uOGT53f4ggUUIF5St2bJ-1\&quot;&gt;\n          &lt;mxGeometry relative=\&quot;1\&quot; as=\&quot;geometry\&quot;&gt;\n            &lt;mxPoint x=\&quot;480\&quot; y=\&quot;150\&quot; as=\&quot;targetPoint\&quot; /&gt;\n          &lt;/mxGeometry&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-1\&quot; value=\&quot;Network Statistics\&quot; style=\&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;240\&quot; y=\&quot;-170\&quot; width=\&quot;480\&quot; height=\&quot;230\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-21\&quot; style=\&quot;edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;\&quot; edge=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot; source=\&quot;uOGT53f4ggUUIF5St2bJ-2\&quot; target=\&quot;uOGT53f4ggUUIF5St2bJ-13\&quot;&gt;\n          &lt;mxGeometry relative=\&quot;1\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-22\&quot; style=\&quot;edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.558;entryY=-0.017;entryDx=0;entryDy=0;entryPerimeter=0;\&quot; edge=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot; source=\&quot;uOGT53f4ggUUIF5St2bJ-2\&quot; target=\&quot;uOGT53f4ggUUIF5St2bJ-14\&quot;&gt;\n          &lt;mxGeometry relative=\&quot;1\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-2\&quot; value=\&quot;Boosters\&quot; style=\&quot;rounded=1;whiteSpace=wrap;html=1;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;200\&quot; y=\&quot;350\&quot; width=\&quot;140\&quot; height=\&quot;80\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-44\&quot; style=\&quot;edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;\&quot; edge=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot; source=\&quot;uOGT53f4ggUUIF5St2bJ-3\&quot; target=\&quot;uOGT53f4ggUUIF5St2bJ-45\&quot;&gt;\n          &lt;mxGeometry relative=\&quot;1\&quot; as=\&quot;geometry\&quot;&gt;\n            &lt;mxPoint x=\&quot;1090\&quot; y=\&quot;480\&quot; as=\&quot;targetPoint\&quot; /&gt;\n          &lt;/mxGeometry&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-47\&quot; style=\&quot;edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.75;entryDx=0;entryDy=0;\&quot; edge=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot; source=\&quot;uOGT53f4ggUUIF5St2bJ-3\&quot; target=\&quot;uOGT53f4ggUUIF5St2bJ-46\&quot;&gt;\n          &lt;mxGeometry relative=\&quot;1\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-55\&quot; style=\&quot;edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;\&quot; edge=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot; source=\&quot;uOGT53f4ggUUIF5St2bJ-3\&quot; target=\&quot;uOGT53f4ggUUIF5St2bJ-49\&quot;&gt;\n          &lt;mxGeometry relative=\&quot;1\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-59\&quot; style=\&quot;edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;\&quot; edge=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot; source=\&quot;uOGT53f4ggUUIF5St2bJ-3\&quot; target=\&quot;uOGT53f4ggUUIF5St2bJ-58\&quot;&gt;\n          &lt;mxGeometry relative=\&quot;1\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-3\&quot; value=\&quot;Reward System\&quot; style=\&quot;rounded=1;whiteSpace=wrap;html=1;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;780\&quot; y=\&quot;440\&quot; width=\&quot;130\&quot; height=\&quot;80\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-40\&quot; style=\&quot;edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;\&quot; edge=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot; source=\&quot;uOGT53f4ggUUIF5St2bJ-7\&quot;&gt;\n          &lt;mxGeometry relative=\&quot;1\&quot; as=\&quot;geometry\&quot;&gt;\n            &lt;mxPoint x=\&quot;490\&quot; y=\&quot;800\&quot; as=\&quot;targetPoint\&quot; /&gt;\n          &lt;/mxGeometry&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-7\&quot; value=\&quot;Player Experience\&quot; style=\&quot;rounded=1;whiteSpace=wrap;html=1;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;420\&quot; y=\&quot;560\&quot; width=\&quot;140\&quot; height=\&quot;80\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-9\&quot; value=\&quot;Player Levelling Manager\&quot; style=\&quot;rounded=1;whiteSpace=wrap;html=1;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;430\&quot; y=\&quot;810\&quot; width=\&quot;120\&quot; height=\&quot;60\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-13\&quot; value=\&quot;Booster Type\&quot; style=\&quot;rounded=1;whiteSpace=wrap;html=1;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;-70\&quot; y=\&quot;410\&quot; width=\&quot;120\&quot; height=\&quot;60\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-14\&quot; value=\&quot;Booster Manager\&quot; style=\&quot;rounded=1;whiteSpace=wrap;html=1;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;80\&quot; y=\&quot;540\&quot; width=\&quot;120\&quot; height=\&quot;60\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-16\&quot; value=\&quot;\&quot; style=\&quot;endArrow=none;dashed=1;html=1;dashPattern=1 3;strokeWidth=2;rounded=0;\&quot; edge=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot; source=\&quot;uOGT53f4ggUUIF5St2bJ-7\&quot;&gt;\n          &lt;mxGeometry width=\&quot;50\&quot; height=\&quot;50\&quot; relative=\&quot;1\&quot; as=\&quot;geometry\&quot;&gt;\n            &lt;mxPoint x=\&quot;290\&quot; y=\&quot;470\&quot; as=\&quot;sourcePoint\&quot; /&gt;\n            &lt;mxPoint x=\&quot;340\&quot; y=\&quot;420\&quot; as=\&quot;targetPoint\&quot; /&gt;\n          &lt;/mxGeometry&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-20\&quot; style=\&quot;edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;\&quot; edge=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot; source=\&quot;uOGT53f4ggUUIF5St2bJ-18\&quot; target=\&quot;WIyWlLk6GJQsqaUBKTNV-3\&quot;&gt;\n          &lt;mxGeometry relative=\&quot;1\&quot; as=\&quot;geometry\&quot;&gt;\n            &lt;mxPoint x=\&quot;140\&quot; y=\&quot;210\&quot; as=\&quot;targetPoint\&quot; /&gt;\n          &lt;/mxGeometry&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-105\&quot; style=\&quot;edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;\&quot; edge=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot; source=\&quot;uOGT53f4ggUUIF5St2bJ-18\&quot; target=\&quot;uOGT53f4ggUUIF5St2bJ-24\&quot;&gt;\n          &lt;mxGeometry relative=\&quot;1\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-18\&quot; value=\&quot;Discord Integration\&quot; style=\&quot;rounded=1;whiteSpace=wrap;html=1;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;-80\&quot; y=\&quot;180\&quot; width=\&quot;120\&quot; height=\&quot;80\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-28\&quot; style=\&quot;edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;\&quot; edge=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot; source=\&quot;uOGT53f4ggUUIF5St2bJ-23\&quot;&gt;\n          &lt;mxGeometry relative=\&quot;1\&quot; as=\&quot;geometry\&quot;&gt;\n            &lt;mxPoint x=\&quot;-210\&quot; y=\&quot;180\&quot; as=\&quot;targetPoint\&quot; /&gt;\n          &lt;/mxGeometry&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-30\&quot; style=\&quot;edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;\&quot; edge=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot; source=\&quot;uOGT53f4ggUUIF5St2bJ-23\&quot; target=\&quot;uOGT53f4ggUUIF5St2bJ-25\&quot;&gt;\n          &lt;mxGeometry relative=\&quot;1\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-32\&quot; style=\&quot;edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=1;entryY=0.5;entryDx=0;entryDy=0;\&quot; edge=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot; source=\&quot;uOGT53f4ggUUIF5St2bJ-23\&quot; target=\&quot;uOGT53f4ggUUIF5St2bJ-31\&quot;&gt;\n          &lt;mxGeometry relative=\&quot;1\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-23\&quot; value=\&quot;Notifier(s)\&quot; style=\&quot;rounded=1;whiteSpace=wrap;html=1;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;-140\&quot; y=\&quot;20\&quot; width=\&quot;100\&quot; height=\&quot;70\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-24\&quot; value=\&quot;Discord Notifier\&quot; style=\&quot;rounded=1;whiteSpace=wrap;html=1;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;-260\&quot; y=\&quot;180\&quot; width=\&quot;100\&quot; height=\&quot;40\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-25\&quot; value=\&quot;Game Notifier\&quot; style=\&quot;rounded=1;whiteSpace=wrap;html=1;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;-400\&quot; y=\&quot;180\&quot; width=\&quot;100\&quot; height=\&quot;40\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-31\&quot; value=\&quot;n... Notifier\&quot; style=\&quot;rounded=1;whiteSpace=wrap;html=1;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;-480\&quot; y=\&quot;-10\&quot; width=\&quot;90\&quot; height=\&quot;30\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-33\&quot; value=\&quot;\&quot; style=\&quot;endArrow=none;dashed=1;html=1;dashPattern=1 3;strokeWidth=2;rounded=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;\&quot; edge=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot; source=\&quot;uOGT53f4ggUUIF5St2bJ-9\&quot; target=\&quot;uOGT53f4ggUUIF5St2bJ-3\&quot;&gt;\n          &lt;mxGeometry width=\&quot;50\&quot; height=\&quot;50\&quot; relative=\&quot;1\&quot; as=\&quot;geometry\&quot;&gt;\n            &lt;mxPoint x=\&quot;650\&quot; y=\&quot;490\&quot; as=\&quot;sourcePoint\&quot; /&gt;\n            &lt;mxPoint x=\&quot;700\&quot; y=\&quot;440\&quot; as=\&quot;targetPoint\&quot; /&gt;\n          &lt;/mxGeometry&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-54\&quot; style=\&quot;edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.516;entryY=-0.146;entryDx=0;entryDy=0;entryPerimeter=0;\&quot; edge=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot; source=\&quot;uOGT53f4ggUUIF5St2bJ-35\&quot; target=\&quot;uOGT53f4ggUUIF5St2bJ-53\&quot;&gt;\n          &lt;mxGeometry relative=\&quot;1\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-57\&quot; style=\&quot;edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;\&quot; edge=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot; source=\&quot;uOGT53f4ggUUIF5St2bJ-35\&quot;&gt;\n          &lt;mxGeometry relative=\&quot;1\&quot; as=\&quot;geometry\&quot;&gt;\n            &lt;mxPoint x=\&quot;1690\&quot; y=\&quot;110\&quot; as=\&quot;targetPoint\&quot; /&gt;\n          &lt;/mxGeometry&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-35\&quot; value=\&quot;Server Event System\&quot; style=\&quot;rounded=0;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;sketch=1;curveFitting=1;jiggle=2;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;1150\&quot; y=\&quot;-70\&quot; width=\&quot;210\&quot; height=\&quot;90\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-36\&quot; value=\&quot;&amp;lt;font style=&amp;quot;background-color: initial; font-size: 27px;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;&amp;amp;nbsp; Levelling Flowchart&amp;lt;/b&amp;gt; &amp;lt;br&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;span style=&amp;quot;background-color: initial;&amp;quot;&amp;gt;(Abstract) (redacted) (WIP)&amp;amp;nbsp;&amp;lt;/span&amp;gt;\&quot; style=\&quot;text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;195\&quot; y=\&quot;-310\&quot; width=\&quot;570\&quot; height=\&quot;130\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-43\&quot; value=\&quot;Random Event System&amp;amp;nbsp;\&quot; style=\&quot;rounded=1;whiteSpace=wrap;html=1;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;1640\&quot; y=\&quot;120\&quot; width=\&quot;120\&quot; height=\&quot;50\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-45\&quot; value=\&quot;Learning / Skills Points\&quot; style=\&quot;rounded=1;whiteSpace=wrap;html=1;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;1030\&quot; y=\&quot;470\&quot; width=\&quot;120\&quot; height=\&quot;40\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-46\&quot; value=\&quot;Coins\&quot; style=\&quot;rounded=1;whiteSpace=wrap;html=1;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;1030\&quot; y=\&quot;560\&quot; width=\&quot;120\&quot; height=\&quot;40\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-49\&quot; value=\&quot;Special Quests Unlock\&quot; style=\&quot;rounded=1;whiteSpace=wrap;html=1;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;1030\&quot; y=\&quot;640\&quot; width=\&quot;120\&quot; height=\&quot;40\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-50\&quot; value=\&quot;Network Activites (Quests)\&quot; style=\&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;sketch=1;curveFitting=1;jiggle=2;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;1350\&quot; y=\&quot;190\&quot; width=\&quot;150\&quot; height=\&quot;90\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-52\&quot; value=\&quot;\&quot; style=\&quot;endArrow=none;dashed=1;html=1;dashPattern=1 3;strokeWidth=2;rounded=0;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.468;entryY=1.043;entryDx=0;entryDy=0;entryPerimeter=0;\&quot; edge=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot; source=\&quot;uOGT53f4ggUUIF5St2bJ-50\&quot; target=\&quot;uOGT53f4ggUUIF5St2bJ-35\&quot;&gt;\n          &lt;mxGeometry width=\&quot;50\&quot; height=\&quot;50\&quot; relative=\&quot;1\&quot; as=\&quot;geometry\&quot;&gt;\n            &lt;mxPoint x=\&quot;1090\&quot; y=\&quot;70\&quot; as=\&quot;sourcePoint\&quot; /&gt;\n            &lt;mxPoint x=\&quot;1140\&quot; y=\&quot;20\&quot; as=\&quot;targetPoint\&quot; /&gt;\n          &lt;/mxGeometry&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-53\&quot; value=\&quot;Specific Event System\&quot; style=\&quot;rounded=1;whiteSpace=wrap;html=1;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;1830\&quot; y=\&quot;120\&quot; width=\&quot;120\&quot; height=\&quot;50\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-58\&quot; value=\&quot;Anything else...\&quot; style=\&quot;rounded=1;whiteSpace=wrap;html=1;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;1030\&quot; y=\&quot;710\&quot; width=\&quot;120\&quot; height=\&quot;40\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-61\&quot; value=\&quot;Achievements\&quot; style=\&quot;rounded=0;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;fillStyle=auto;shadow=0;sketch=1;curveFitting=1;jiggle=2;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;850\&quot; y=\&quot;-70\&quot; width=\&quot;210\&quot; height=\&quot;90\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-63\&quot; value=\&quot;\&quot; style=\&quot;endArrow=none;dashed=1;html=1;dashPattern=1 3;strokeWidth=2;rounded=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;\&quot; edge=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot; target=\&quot;uOGT53f4ggUUIF5St2bJ-1\&quot;&gt;\n          &lt;mxGeometry width=\&quot;50\&quot; height=\&quot;50\&quot; relative=\&quot;1\&quot; as=\&quot;geometry\&quot;&gt;\n            &lt;mxPoint x=\&quot;840\&quot; y=\&quot;-30\&quot; as=\&quot;sourcePoint\&quot; /&gt;\n            &lt;mxPoint x=\&quot;910\&quot; y=\&quot;10\&quot; as=\&quot;targetPoint\&quot; /&gt;\n          &lt;/mxGeometry&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-69\&quot; value=\&quot;\&quot; style=\&quot;rounded=0;whiteSpace=wrap;html=1;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;-580\&quot; y=\&quot;-420\&quot; width=\&quot;300\&quot; height=\&quot;260\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-70\&quot; value=\&quot;Association Key List\&quot; style=\&quot;rounded=0;whiteSpace=wrap;html=1;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;-480\&quot; y=\&quot;-420\&quot; width=\&quot;120\&quot; height=\&quot;30\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-71\&quot; value=\&quot;\&quot; style=\&quot;ellipse;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;-545\&quot; y=\&quot;-380\&quot; width=\&quot;20\&quot; height=\&quot;20\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-72\&quot; value=\&quot;Admin Configurable\&quot; style=\&quot;text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;-510\&quot; y=\&quot;-385\&quot; width=\&quot;130\&quot; height=\&quot;30\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-77\&quot; value=\&quot;\&quot; style=\&quot;ellipse;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;790\&quot; y=\&quot;450\&quot; width=\&quot;10\&quot; height=\&quot;10\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-78\&quot; value=\&quot;\&quot; style=\&quot;ellipse;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;430\&quot; y=\&quot;575\&quot; width=\&quot;10\&quot; height=\&quot;10\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-79\&quot; value=\&quot;\&quot; style=\&quot;ellipse;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;860\&quot; y=\&quot;-60\&quot; width=\&quot;10\&quot; height=\&quot;10\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-80\&quot; value=\&quot;\&quot; style=\&quot;ellipse;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;1160\&quot; y=\&quot;-60\&quot; width=\&quot;10\&quot; height=\&quot;10\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-81\&quot; value=\&quot;\&quot; style=\&quot;ellipse;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;1360\&quot; y=\&quot;195\&quot; width=\&quot;10\&quot; height=\&quot;10\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-82\&quot; value=\&quot;\&quot; style=\&quot;ellipse;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;-250\&quot; y=\&quot;60\&quot; width=\&quot;10\&quot; height=\&quot;10\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-83\&quot; value=\&quot;\&quot; style=\&quot;rounded=0;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;sketch=1;curveFitting=1;jiggle=2;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;-545\&quot; y=\&quot;-330\&quot; width=\&quot;20\&quot; height=\&quot;20\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-85\&quot; value=\&quot;Large Future Possibilites with the system\&quot; style=\&quot;text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;-510\&quot; y=\&quot;-335\&quot; width=\&quot;200\&quot; height=\&quot;30\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-86\&quot; value=\&quot;\&quot; style=\&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;-545\&quot; y=\&quot;-280\&quot; width=\&quot;30\&quot; height=\&quot;25\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-87\&quot; value=\&quot;Parent (IMPORTANT)\&quot; style=\&quot;text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;-490\&quot; y=\&quot;-280\&quot; width=\&quot;120\&quot; height=\&quot;30\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-88\&quot; value=\&quot;\&quot; style=\&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;-555\&quot; y=\&quot;-230\&quot; width=\&quot;40\&quot; height=\&quot;40\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-91\&quot; value=\&quot;Parent of the system(s) I&amp;#39;ll implement&amp;amp;nbsp;\&quot; style=\&quot;text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;-490\&quot; y=\&quot;-225\&quot; width=\&quot;170\&quot; height=\&quot;30\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-92\&quot; value=\&quot;\&quot; style=\&quot;endArrow=none;dashed=1;html=1;dashPattern=1 3;strokeWidth=2;rounded=0;opacity=20;\&quot; edge=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry width=\&quot;50\&quot; height=\&quot;50\&quot; relative=\&quot;1\&quot; as=\&quot;geometry\&quot;&gt;\n            &lt;mxPoint x=\&quot;-10\&quot; y=\&quot;410\&quot; as=\&quot;sourcePoint\&quot; /&gt;\n            &lt;mxPoint x=\&quot;-200\&quot; y=\&quot;220\&quot; as=\&quot;targetPoint\&quot; /&gt;\n          &lt;/mxGeometry&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-94\&quot; value=\&quot;\&quot; style=\&quot;endArrow=none;dashed=1;html=1;dashPattern=1 3;strokeWidth=2;rounded=0;opacity=20;\&quot; edge=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry width=\&quot;50\&quot; height=\&quot;50\&quot; relative=\&quot;1\&quot; as=\&quot;geometry\&quot;&gt;\n            &lt;mxPoint x=\&quot;-90\&quot; y=\&quot;330\&quot; as=\&quot;sourcePoint\&quot; /&gt;\n            &lt;mxPoint x=\&quot;-325\&quot; y=\&quot;220\&quot; as=\&quot;targetPoint\&quot; /&gt;\n          &lt;/mxGeometry&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-95\&quot; value=\&quot;\&quot; style=\&quot;endArrow=none;dashed=1;html=1;dashPattern=1 3;strokeWidth=2;rounded=0;exitX=0.195;exitY=-0.021;exitDx=0;exitDy=0;exitPerimeter=0;opacity=20;\&quot; edge=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot; source=\&quot;uOGT53f4ggUUIF5St2bJ-14\&quot;&gt;\n          &lt;mxGeometry width=\&quot;50\&quot; height=\&quot;50\&quot; relative=\&quot;1\&quot; as=\&quot;geometry\&quot;&gt;\n            &lt;mxPoint x=\&quot;-10\&quot; y=\&quot;520\&quot; as=\&quot;sourcePoint\&quot; /&gt;\n            &lt;mxPoint x=\&quot;40\&quot; y=\&quot;470\&quot; as=\&quot;targetPoint\&quot; /&gt;\n          &lt;/mxGeometry&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-97\&quot; value=\&quot;\&quot; style=\&quot;rounded=0;whiteSpace=wrap;html=1;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;-1580\&quot; y=\&quot;-420\&quot; width=\&quot;950\&quot; height=\&quot;4470\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-102\&quot; value=\&quot;&amp;lt;h1&amp;gt;&amp;lt;span style=&amp;quot;font-size: 31px;&amp;quot;&amp;gt;Levelling System Explanation [0.1]&amp;lt;/span&amp;gt;&amp;lt;/h1&amp;gt;&amp;lt;p&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;blockquote style=&amp;quot;margin: 0 0 0 40px; border: none; padding: 0px;&amp;quot;&amp;gt;&amp;lt;div style=&amp;quot;text-align: left;&amp;quot;&amp;gt;&amp;lt;b style=&amp;quot;background-color: initial;&amp;quot;&amp;gt;&amp;lt;font style=&amp;quot;font-size: 25px;&amp;quot;&amp;gt;Network Levelling&amp;lt;/font&amp;gt;&amp;lt;/b&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;ul style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;li style=&amp;quot;text-align: left;&amp;quot;&amp;gt;The idea of the Network Levelling will be to depend (extend) on a Network Statistic(s) (Player Stats), this will make it easier for other Developers to implement future progression systems or more player stats which is unifed and horizontal in progression. E.G. We will easily be able to add and track different types of progression because of implementation. An example could be a &amp;quot;Game-Levelling&amp;quot; system.&amp;lt;/li&amp;gt;&amp;lt;li style=&amp;quot;text-align: left;&amp;quot;&amp;gt;Player Experience will handle XP and the scaling system we choose.&amp;lt;/li&amp;gt;&amp;lt;li style=&amp;quot;text-align: left;&amp;quot;&amp;gt;Levelling Manager will handle at the core levelling players up and other stuff like retrieval of levels from database(s) etc.&amp;lt;/li&amp;gt;&amp;lt;/ul&amp;gt;&amp;lt;blockquote style=&amp;quot;margin: 0 0 0 40px; border: none; padding: 0px;&amp;quot;&amp;gt;&amp;lt;div style=&amp;quot;text-align: left;&amp;quot;&amp;gt;&amp;lt;b style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;font style=&amp;quot;font-size: 25px;&amp;quot;&amp;gt;Player Experience &amp;amp;amp; Levelling Psychology&amp;amp;nbsp;&amp;lt;/font&amp;gt;&amp;lt;/b&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;div style=&amp;quot;text-align: left; font-size: 22px;&amp;quot;&amp;gt;&amp;lt;ul&amp;gt;&amp;lt;li style=&amp;quot;border-color: var(--border-color);&amp;quot;&amp;gt;Players on the network need to have a fun and enjoyable levelling experience, but it also needs to be capitivating.&amp;lt;/li&amp;gt;&amp;lt;li style=&amp;quot;border-color: var(--border-color);&amp;quot;&amp;gt;Focusing horizontal progression over vertical (unlock new abilities, etc, rather than making players more powerful; make them feel more &amp;#39;cool&amp;#39;)&amp;lt;/li&amp;gt;&amp;lt;li style=&amp;quot;border-color: var(--border-color);&amp;quot;&amp;gt;We could eventually scale parts of the network with player achievements. What I mean by this, is we could have a system called &amp;quot;Stories&amp;quot;, which is Lore tied to the server, and the more achievements you have, the more you can &amp;quot;see&amp;quot; the lore.&amp;lt;/li&amp;gt;&amp;lt;li style=&amp;quot;border-color: var(--border-color);&amp;quot;&amp;gt;Visual Progression System = Dopamine = Win&amp;lt;/li&amp;gt;&amp;lt;/ul&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;blockquote style=&amp;quot;margin: 0 0 0 40px; border: none; padding: 0px;&amp;quot;&amp;gt;&amp;lt;b style=&amp;quot;border-color: var(--border-color); background-color: initial;&amp;quot;&amp;gt;&amp;lt;div style=&amp;quot;text-align: left; font-size: 25px;&amp;quot;&amp;gt;Boosters&amp;lt;/div&amp;gt;&amp;lt;/b&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;ul style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;li style=&amp;quot;text-align: left;&amp;quot;&amp;gt;There will be four default boosters: minor (10%), half(50%), double(100%), triple(200%) more XP. Boosters will also be configurable through a GUI for those with permissions (create/edit network boosters).&amp;lt;/li&amp;gt;&amp;lt;li style=&amp;quot;text-align: left;&amp;quot;&amp;gt;&amp;amp;nbsp;The booster implementation will make it easier to add other boosters in the future E.G. Coin Boosters, etc.&amp;lt;/li&amp;gt;&amp;lt;/ul&amp;gt;&amp;lt;blockquote style=&amp;quot;margin: 0 0 0 40px; border: none; padding: 0px;&amp;quot;&amp;gt;&amp;lt;div style=&amp;quot;text-align: left;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;&amp;lt;font style=&amp;quot;font-size: 25px;&amp;quot;&amp;gt;Discord Integration&amp;lt;/font&amp;gt;&amp;lt;/b&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;div style=&amp;quot;text-align: left;&amp;quot;&amp;gt;&amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;&amp;lt;span style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;Discord webhook integreation will essentially be an API that&amp;#39;s able to be used anywhere, so if anyone wanted to create a webhook E.G. Player Report webhook then it can easily be done and created on the code side.&amp;lt;/span&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;span style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;The Booster message webhook message will do exactly as specified.&amp;lt;/span&amp;gt;&amp;amp;nbsp;&amp;lt;/li&amp;gt;&amp;lt;/ul&amp;gt;&amp;lt;div&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;blockquote style=&amp;quot;margin: 0 0 0 40px; border: none; padding: 0px;&amp;quot;&amp;gt;&amp;lt;div style=&amp;quot;text-align: left;&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;font-size: 25px;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;Notifiers&amp;lt;/b&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;div style=&amp;quot;text-align: left;&amp;quot;&amp;gt;&amp;lt;div&amp;gt;&amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;&amp;lt;font style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;Notifier is just a parent of notifiers that can be creatable E.G. Game Notifiers, Discord Notifiers, any other future notifiers [...]&amp;lt;/font&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ul&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;blockquote style=&amp;quot;margin: 0 0 0 40px; border: none; padding: 0px;&amp;quot;&amp;gt;&amp;lt;div style=&amp;quot;text-align: left;&amp;quot;&amp;gt;&amp;lt;div&amp;gt;&amp;lt;div&amp;gt;&amp;lt;font style=&amp;quot;font-size: 25px;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;Reward System&amp;lt;/b&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;div style=&amp;quot;text-align: left;&amp;quot;&amp;gt;&amp;lt;div&amp;gt;&amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;&amp;lt;span style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;Levelling will of course have a reward sytem which could have rewards like: Coins, Learning Points (Skill points) - which could be for something in the future, Special Quests which are longer but give more XP, etc.&amp;lt;/span&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;span style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;Anything else--this will eventually be customizable also, but most of the customization reward types will need to specifially be coded unless they&amp;#39;re super trivial&amp;lt;/span&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ul&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;blockquote style=&amp;quot;margin: 0 0 0 40px; border: none; padding: 0px;&amp;quot;&amp;gt;&amp;lt;div style=&amp;quot;text-align: left;&amp;quot;&amp;gt;&amp;lt;font color=&amp;quot;#ff3333&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;font-size: 25px;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;Achievements / Server Event System / Network Activities (Quests)&amp;lt;/b&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;div style=&amp;quot;text-align: left; font-size: 21px;&amp;quot;&amp;gt;&amp;lt;div&amp;gt;&amp;lt;div&amp;gt;&amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;&amp;lt;span style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;These could all be future large updates to network levelling, and are all possible under the current implementation.&amp;lt;/span&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;span style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;Achievements could be similiar to Hypixel&amp;#39;s, or a bit more expansive.&amp;lt;/span&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;span style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;Server Event System could act as a event &amp;quot;day&amp;quot; cycle for the server, for instance every day at some timezone the server has a day cycle, which can process and determine new events. Some events I thought of was, randomly choosing a minigame on the network, and giving it an Xp boost for a few hours or so, which can help make the games that are recently a bit player diverse. Server Events, could also be setup as well for specific events.&amp;lt;/span&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;span style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;Quests / Activites - stuff for the players to do could grant more XP, coins, etc, etc. Could eventually be dynamic quests. Completing Quests can also have it&amp;#39;s own rewards or achievements (we can&amp;#39;t have too many systems of progression or newer players will be overwhelmed)&amp;amp;nbsp;&amp;lt;/span&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ul&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;blockquote style=&amp;quot;margin: 0px 0px 0px 40px; border: none; padding: 0px; font-size: 21px;&amp;quot;&amp;gt;&amp;lt;div style=&amp;quot;text-align: left;&amp;quot;&amp;gt;&amp;lt;div style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;div&amp;gt;&amp;lt;div&amp;gt;&amp;lt;b style=&amp;quot;border-color: var(--border-color); font-size: 25px;&amp;quot;&amp;gt;The Math behind Player Experience Scaling&amp;lt;/b&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div&amp;gt;&amp;lt;span style=&amp;quot;background-color: initial;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div&amp;gt;&amp;lt;span style=&amp;quot;background-color: initial;&amp;quot;&amp;gt;&amp;lt;i&amp;gt;These are scaling systems we need to agree on, of course we&amp;#39;ll be able edit XP progression, but for a network, this isn&amp;#39;t the best approach. We should stick with a scaling and run with it.&amp;lt;/i&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;background-color: initial;&amp;quot;&amp;gt;&amp;lt;i&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;font-size: 20px;&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;background-color: initial; font-size: 21px;&amp;quot;&amp;gt;&amp;lt;i&amp;gt;&amp;lt;div style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;background-color: initial;&amp;quot;&amp;gt;The balance of player progression in games is a key part of game design. This document presents three common scaling methods used to calculate the experience points (XP) a player needs to level up.&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;background-color: initial;&amp;quot;&amp;gt;&amp;lt;i&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;ul style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Linear Levelling Progression&amp;lt;/b&amp;gt;:&amp;amp;nbsp;The required XP increases linearly with the player&amp;#39;s level. Similiar to Hypixel&amp;#39;s and other servers E.G. 2500, 5000, 7500, etc. If we were to use this we could have it start at base increase of 3500*n.&amp;lt;/li&amp;gt;&amp;lt;/ul&amp;gt;&amp;lt;div style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;ul style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;li style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;font style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;b&amp;gt;Exponential Levelling Progression&amp;lt;/b&amp;gt;:&amp;amp;nbsp;The required XP increases exponentially with the player&amp;#39;s level. This is a common approach in MMOS/RPG (WoW, etc). This is how we could implement this:&amp;lt;/font&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ul&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/blockquote&amp;gt;&amp;lt;div style=&amp;quot;text-align: left;&amp;quot;&amp;gt;&amp;lt;div style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;div&amp;gt;&amp;lt;div&amp;gt;&amp;lt;font style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div&amp;gt;&amp;lt;font style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;How we could use it:&amp;lt;/font&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;font style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;font style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;font style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;i style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;font style=&amp;quot;font-size: 18px;&amp;quot;&amp;gt;How games like RuneScape implements it:&amp;lt;/font&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;span style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;amp;nbsp;&amp;lt;/span&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;font style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;font style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;font style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;font size=&amp;quot;1&amp;quot; style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;i style=&amp;quot;font-size: 18px;&amp;quot;&amp;gt;How games like RuneScape get XP needed to reach Level L&amp;lt;/i&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;font size=&amp;quot;1&amp;quot; style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;i style=&amp;quot;font-size: 18px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;font size=&amp;quot;1&amp;quot; style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;i style=&amp;quot;font-size: 18px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;font size=&amp;quot;1&amp;quot; style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;i style=&amp;quot;font-size: 18px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;font size=&amp;quot;1&amp;quot; style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;i style=&amp;quot;font-size: 18px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;font size=&amp;quot;1&amp;quot; style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;i style=&amp;quot;font-size: 18px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;font size=&amp;quot;1&amp;quot; style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;i style=&amp;quot;font-size: 18px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;font size=&amp;quot;1&amp;quot; style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;i style=&amp;quot;font-size: 18px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;font size=&amp;quot;1&amp;quot; style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;i style=&amp;quot;font-size: 18px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;font size=&amp;quot;1&amp;quot; style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;i style=&amp;quot;font-size: 18px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;font size=&amp;quot;1&amp;quot; style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;i style=&amp;quot;font-size: 18px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;font size=&amp;quot;1&amp;quot; style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;i style=&amp;quot;font-size: 18px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;font size=&amp;quot;1&amp;quot; style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;i style=&amp;quot;font-size: 18px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;font size=&amp;quot;1&amp;quot; style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;i style=&amp;quot;font-size: 18px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;font size=&amp;quot;1&amp;quot; style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;i style=&amp;quot;font-size: 18px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;font size=&amp;quot;1&amp;quot; style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;i style=&amp;quot;font-size: 18px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;font size=&amp;quot;1&amp;quot; style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;i style=&amp;quot;font-size: 18px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;font size=&amp;quot;1&amp;quot; style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;i style=&amp;quot;font-size: 18px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;font size=&amp;quot;1&amp;quot; style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;i style=&amp;quot;font-size: 18px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;font size=&amp;quot;1&amp;quot; style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;i style=&amp;quot;font-size: 18px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;font size=&amp;quot;1&amp;quot; style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;i style=&amp;quot;font-size: 18px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;font size=&amp;quot;1&amp;quot; style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;i style=&amp;quot;font-size: 18px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;font size=&amp;quot;1&amp;quot; style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;i style=&amp;quot;font-size: 18px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;font size=&amp;quot;1&amp;quot; style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;i style=&amp;quot;font-size: 18px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;font size=&amp;quot;1&amp;quot; style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;i style=&amp;quot;font-size: 18px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;font size=&amp;quot;1&amp;quot; style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;i style=&amp;quot;font-size: 18px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;font size=&amp;quot;1&amp;quot; style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;i style=&amp;quot;font-size: 18px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;font size=&amp;quot;1&amp;quot; style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;i style=&amp;quot;font-size: 18px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;font size=&amp;quot;1&amp;quot; style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;i style=&amp;quot;font-size: 18px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;font size=&amp;quot;1&amp;quot; style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;i style=&amp;quot;font-size: 18px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;ul style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;b&amp;gt;Polynomial Levelling Progression&amp;lt;/b&amp;gt;:&amp;lt;b&amp;gt;&amp;amp;nbsp;&amp;lt;/b&amp;gt;The required XP increases according to a power of the player&amp;#39;s level. This is similiar to games like (FFXIV, POE, Diablo 3, Skyrim, Oblivion)&amp;lt;/li&amp;gt;&amp;lt;/ul&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;font style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;font-size: 21px;&amp;quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;p&amp;gt;&amp;lt;/p&amp;gt;\&quot; style=\&quot;text;html=1;strokeColor=none;fillColor=none;spacing=5;spacingTop=-20;whiteSpace=wrap;overflow=hidden;rounded=0;align=center;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;-1555\&quot; y=\&quot;-390\&quot; width=\&quot;900\&quot; height=\&quot;4400\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-103\&quot; value=\&quot;\&quot; style=\&quot;ellipse;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;210\&quot; y=\&quot;360\&quot; width=\&quot;10\&quot; height=\&quot;10\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-106\&quot; value=\&quot;\&quot; style=\&quot;endArrow=none;dashed=1;html=1;dashPattern=1 3;strokeWidth=2;rounded=0;exitX=1;exitY=0;exitDx=0;exitDy=0;opacity=20;\&quot; edge=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot; source=\&quot;uOGT53f4ggUUIF5St2bJ-3\&quot;&gt;\n          &lt;mxGeometry width=\&quot;50\&quot; height=\&quot;50\&quot; relative=\&quot;1\&quot; as=\&quot;geometry\&quot;&gt;\n            &lt;mxPoint x=\&quot;1300\&quot; y=\&quot;310\&quot; as=\&quot;sourcePoint\&quot; /&gt;\n            &lt;mxPoint x=\&quot;1350\&quot; y=\&quot;260\&quot; as=\&quot;targetPoint\&quot; /&gt;\n          &lt;/mxGeometry&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-107\&quot; value=\&quot;&amp;lt;strike&amp;gt;Underwhemling Edition&amp;lt;/strike&amp;gt;\&quot; style=\&quot;text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;350\&quot; y=\&quot;-240\&quot; width=\&quot;80\&quot; height=\&quot;30\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-109\&quot; value=\&quot;\&quot; style=\&quot;shape=image;verticalLabelPosition=bottom;labelBackgroundColor=default;verticalAlign=top;aspect=fixed;imageAspect=0;image=data:image/png,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;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;-1328.21\&quot; y=\&quot;1603\&quot; width=\&quot;412.22\&quot; height=\&quot;70\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-110\&quot; value=\&quot;\&quot; style=\&quot;shape=image;verticalLabelPosition=bottom;labelBackgroundColor=default;verticalAlign=top;aspect=fixed;imageAspect=0;image=data:image/png,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OIIZJp9uqRPQmRhEgPGNjuSRCzD5dEudgM7EIALDbKwwHrkAg0W31AnoTAwiMAzGiuNYgHbRLXUCOhODCHTBWHE8cgG6QbfUCehMDCIwqMYK4fEWYDjoljoBnYlBBCbTWPE73gIwmm6pE9CZdHkQu/6PzP61W1f2b6zwXd/SBWaz3exfu3V9/3oloBt07bXXppe97GVp++23T89//vPTOeecU16yri4Poh8i7Wb/mjVWzDaxjMfPlvayf+1m/4aLgG7IihUr0syZM9MXv/jFtGrVqnTNNdekGTNmpFtvvbW8Rl2XB9EPkXYb1v0bK1KbWCabny3tZf/azf4NFwHdkIsvvjjNnj27XFvj7W9/e/roRz9artV1eRD9EGm3JvZvrJAc9KUr/GxpL/vXbvZvuAjohpx66qnpjW98Y7m2xkknnZQOOeSQcq0uBnGiy1i/7C2WQV7GmmOLxWKxtHthLQHdkJNPPjkdfPDB5doan/3sZ9Mb3vCGcg0AgC4Q0A35/Oc/v04sx+kbhx56aLkGAEAXCOiGLFmyZJ1zoN/61remj3/84+UaAABdIKAb8uSTT6add945nX766empp55Kl112Wdp6663THXfcUV4DAIAuENANuuGGG9LLX/7ytM0226QXvvCFadGiReUlAAB0hYAGAIAeCGgAAOiBgAYAgB4I6EkULy48/vjj03Of+9y04447pje/+c3p/vvvLy9tv8997nNps802S1OnTn16edvb3lZe2l5nnnlmmjZtWjrttNPKLWv88Ic/THvttVfafvvt02677ZbOPvvs8pL2GG/f4gWwI+/HWG655Zby0na46qqrivsnXpMQL/CN+ax04b5b3/514f777ne/m+bOnVvs3y677FK8QLvShftvffvXhfsvPPTQQ2mnnXZKIzujC/ddZaz968J9t9VWW62zD7feemtxWZfuv00loCdRxMoLXvCCdO+996YVK1akI444ohOBWfnIRz6S3vWud5Vr3XDsscemww47LM2bN68WmU888USaNWtW8Utv1apV6dprry1+EbbpB+V4+xYP9OIvTi1btqzc0j4PPvhgmjFjRvra175WrMcP/XigENHZhftuffvXhfsvvvfYn8WLFxfr1113Xdpyyy2L+6oL99/69q8L91/lne98Z/H2rlVndOG+G2n0/nXhvov7KPbhvvvuK7es1bX7b1MJ6Em09957p69+9avlWkp33XVX8cju8ccfL7e023vf+950wgknlGvdED8gwmtf+9paZF5yySXFUb+R4ofphz/84XJt8I23bw888EDxA/TRRx8tt7RP/PA/66yzyrU14oHCl7/85U7cd+vbvy7cfxEg559/frm2xotf/OLiaFcX7r/17V8X7r9w0UUXFTO5YMGCpwOzC/ddZaz968J9t3z58mIf4iDfaF26/5ogoCfRDjvskK655ppybY0tttgi3XTTTeVau8UR9XiQEE9Lzpw5Mx144IGdeR/s0ZEZj8Bf//rXl2trxJ9zP+igg8q19hi9b3GfxQ/Q+CuacbThRS96Ue3yNrr77ruLI3633XZbp+67ysj969r9t3LlyiI24+fnPffc07n7b/T+deH+i5CMI7NLly5NJ5100tOB2ZX7brz968J9F6dqTJky5el92GOPPdIZZ5xRXNbFn52bQkBPojiv6MYbbyzX1th2223TD37wg3Kt3eLPmccPk4cffjg98sgjxekccVQlnuppu9GR+elPf7p4gDDSqaeemvbff/9yrT1G71vEWBxVuPLKK4v7LuZzu+22W+eIWVvE0b74JXDKKacU612678Lo/evS/feNb3yjeF1FxOWFF15YbOvS/TfW/nXh/jv88MPTpz71qeLjkYHZlftuvP3rwn0Xz4wfeeSR6eqrry72If4bp2nEfHbtZ+emEtCTKF44ODKWYzjjFI6bb7653NItcZ5mPBrvwlHo0ZEZj8hH/9D4xCc+kd7ylreUa+0xet/G8r73va94hqFt4tzSeMoxTm2odOm+G2v/xtLW+y/EEdo4tzuOhl1wwQWduv/C6P0bS5vuv/gDYvEis9ivMDIwu3DfrW//xtLmf3uV+fPnp6OOOqpz//Y2lYCeRK961atqv+h+/OMfF6dwjHWuURvF6Skj31WkOpeqzS+oqIyOzO9///vFu6mMFE95xflwbTN63+L82gizkd7znve07gWiMY/xCvn4s/ojdeW+G2//unD/xYuSqiOylXe/+93p6KOP7sT9t779a/v9F/fFc57znOKBXSxx9HL69OnpNa95TSfuu/XtXxf+7cWbHFx//fXl2hrHHHNM8aLzLv3ea4KAnkTxAsI5c+YUQfnYY4+lt771rcXTPV1xwAEHFP+Y4gUU8cLI+KERj9S7YHRkxtGHOAcunr6KV15ffvnlxdsXxTmobTN63yLM4nzaeBoyxC+E+CURb7vVFjGD8cvt0ksvLbes1YX7bn3714X7L47Ixj5cccUVxfqdd95Z3GdxBKwL99/69q8L999II4/QdunnZmXk/nXhvovvPR4QxKkbIV5sHvfRkiVLOnn/bQoBPYnilI0PfvCDxVGjOJ0jYjPeR7IrfvaznxXnR8X5fLF/8XG8KKat4odF9R6YcZ5ivLAiPo6ns0Kcz/6KV7yi+AEZD4zadJ7bhvYt3uEh3uMz3ipt99133+ApAoNm4cKFxbMf1T5Wy3HHHVdc3ub7Lmxo/9p+/4XYh7hv4j6KFyXHe+jH3Ia2339hffvXhfuvMvoUhy7cdyON3r8u3Hdf+cpX0q677lrsQ9xHsU+Vrt1/m0JAAwBADwQ0AAD0QEADAEAPBDQAAPRAQAMAQA8ENAAA9EBAAwBADwQ0AAD0QEADUNh///1rfxQCgLEJaIABse+++6bDDz+8XJt8AhpgYgQ0wIAQ0ADtIKABBsSGAvqpp55Kp5xySnr+85+fttxyyzR79uz06U9/urjskksuSc94xjPS7bffXqxXjjrqqLTXXnsVHz/00ENp/vz56bnPfW7x+S95yUvS4sWLi8uCgAaYGAENMCA2FNAf/ehH084775xuuOGGIqavvvrqtO2226azzz67WN9pp53SySefXF47pRUrVhSXf+ELXyjWX/3qVxeRvGzZsuKyL33pS2nKlCnpjjvuKC4X0AATI6ABBsSGAnrHHXdMp59+erm2xgknnJD23nvv4uMPfOADae7cucXH4dvf/naaOnVqeuCBB9Itt9xSHKGO/440b968dOKJJxYfC2iAiRHQAANifQH94IMPFgE81jJz5sziOjfffHOxfttttxXrb3vb29LBBx9cfLxo0aJ1Pq9aDjvssOI6AhpgYgQ0wIBYX0DHKRcRuwsXLiy3jC2OQH/84x9Pjz76aJo+fXq66KKLiu0XX3xx8fnLly8v1scioAEmRkADDIgNncIxa9as9MEPfrBcWyPOZ3788cfLtZQ+85nPpJe+9KXpvPPOS8961rPSk08+WWyP85wjoCOkR4rtq1atKj4W0AATI6ABBkQE9IEHHpjuvPPO2hKRHD772c+mGTNmpCVLlhRhfNNNN6VddtklfexjHysuD3HdeGFgvGDw/e9/f7l1jTe96U1pjz32KE7xWLlyZbrwwguLd+O4/PLLi8sFNMDECGiAAREBXZ2XPHKJSA4RvQsWLCjehi5eHBhvYxfr8Q4cI73uda8rPu/GG28st6xx//33pyOOOCJtt912adq0acXpHt/85jfLSwU0wEQJaAAA6IGABgCAHghoAADogYAGAIAeCGgAAOiBgAYAgB4IaAAA6IGABgCAHghoAADogYAGAIAeCGgAAOiBgAYAgB4IaAAA6IGABgCAHghoAADogYAGAIAeCGgAAOiBgAYAgB4IaAAAmLCU/j8fXxMdecUSwgAAAABJRU5ErkJggg==;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;-1465\&quot; y=\&quot;2670\&quot; width=\&quot;720\&quot; height=\&quot;527\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-111\&quot; value=\&quot;\&quot; style=\&quot;shape=image;verticalLabelPosition=bottom;labelBackgroundColor=default;verticalAlign=top;aspect=fixed;imageAspect=0;image=data:image/png,iVBORw0KGgoAAAANSUhEUgAAAZMAAAA1CAYAAACELgYmAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAA/KSURBVHhe7Z0FbORGFIZPZWZWSVVZrVRUmRlUZm6vzCoz05WZmZkZr8ykMjMzc6f6Zuclb117dxP3cnb6f1J0a2edtWc97380vgFBCCGEKInERAghRGkkJkIIIUojMRFCCFEaiYkQQojSSEyEEEKURmIihBCiNBITIYQQpZGYCCGEKI3ERAghRGkkJkIIIUojMRFCCFEaiYkQolZ8+eWX4Y8//khb/YfPP/88vaonEhMhRG348MMPw6BBg8Lff/+d9oTw2GOPheOOOy489NBDac+Q49prrw1HHnlkPI8y/Pzzz+lVN2eccUZ47bXX0lb9kJgIIWrBb7/9FlZdddXw+++/pz0Nvvvuu7DQQguFSy65JO0Zcnz00Udh1FFH7ZWYfPvtt+Gmm24Ke++9d5hlllnS3mbWXnvt8M0336SteiExEULUgqOPPjrccMMNaauZiSeeuHS00AmvvvpqmGaaadJWz0AknnzyyXDbbbeF6aefPu1t5qmnngq77LJL2qoXEhMhRC2YeeaZY3SSpZWB/+uvv9KrbnyKDPLeA3n7Tz/99LDZZpulrd5x9913F4oJcJ2//PJL2qoPEhMhROV54YUXwtJLL522mskz8M8880zYfvvtw7nnnht222238Oabb8b9jz/+eIxwllhiia4i/myzzRajBaPoWFhrrbVKp9PaicnAgQPDnXfembbqg8REiP8B9957bzjiiCPCzjvvHD7++OO0tz5cddVVYZNNNklbzWQN/EsvvRSmnnrqWKOAiy66qCs9tvXWW4c///wzTDDBBOGLL76I+7baaqtw5ZVXxtetjoWJJpqodDqtnZjsu+++saGgbkhMhOhnUKB+66230laDDz74IOyzzz5h2GGHDd9//33aO/T4+uuvw2effZa22kOnE1FCHlkDv+6664blllsuRhYnn3xyjFwsZYWAEIUsssgicRvozrLoo9Wx2XTaPffcE1ZbbbWWP6ecckp6dzftxOSEE04I++23X9qqDxITIfoZhx56aFh88cXTVjcHHHBAmGuuudLW0IU00yGHHJK22nPppZeGbbbZJm114w281VNmmGGGMHjw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;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;-1350\&quot; y=\&quot;2400\&quot; width=\&quot;555.08\&quot; height=\&quot;73\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-112\&quot; value=\&quot;\&quot; style=\&quot;shape=image;verticalLabelPosition=bottom;labelBackgroundColor=default;verticalAlign=top;aspect=fixed;imageAspect=0;image=data:image/png,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;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;-1470\&quot; y=\&quot;1690\&quot; width=\&quot;695.81\&quot; height=\&quot;530\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-113\&quot; value=\&quot;\&quot; style=\&quot;shape=image;verticalLabelPosition=bottom;labelBackgroundColor=default;verticalAlign=top;aspect=fixed;imageAspect=0;image=data:image/png,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;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;-1292.1\&quot; y=\&quot;3350\&quot; width=\&quot;340\&quot; height=\&quot;45\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-114\&quot; value=\&quot;\&quot; style=\&quot;shape=image;verticalLabelPosition=bottom;labelBackgroundColor=default;verticalAlign=top;aspect=fixed;imageAspect=0;image=data:image/png,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ArtgBhWAthHX9aVbMoFdMIMKQJuI63rTLZnALphBBaAtxHX96ZZMYBfMoALQBuK6GXRLJrALZlABaAOB3Qy6JRPYBTOoADSduG4O3ZIJ7IIZVACaTFw3i27JBHbBDCoATSWum0e3ZAK7YAYVgKYS2M2jWzKBXTCDCkATietm0i2ZwC6YQQWgacR1c+mWTGAXzKAC0CTiutl0SyawC2ZQAWgKcd18uiUT2AUzqAA0hcBuPt2SCeyCGVQAmkBct4NuyQR2n5x77rlp1qxZ6eyzz+7csrHvfe971fDNnDlz/TJ37tzOvRszqADUnbhuD92SCew+OOGEE9IxxxyTFi5cOGpgX3PNNWnXXXftrI3NoAJQZ+K6XXRLJrD74Kabbqp+PfDAA0cN7GXLllURPl4GFYC6Etfto1sygd1HYwX2+eefn+bPn58OOOCA6tSQffbZpzqqPRKDCkBdCez20S2ZwO6jsQL7qquuSosXL0733ntvWr16dRXccd72/fff33nEhmJQhy8AUDpx3Xy9GiUW1hHYfTRWYPeyYMGCdMEFF3TWNmRQAagbcd1euiUT2H00VmCvWLEi/fCHP+ysrbPnnnumCy+8sLO2IYMKQJ2I63bTLZnA7qNegX3ppZemO++8s/r49NNPT3vssUd64IEH0rPPPlsduZ49e3Z68MEHq/uHM6gA1InAbjfdkgnsSVqzZs36a1pvvvnmacaMGdXHca512HvvvdOnP/3p6uN47Iknnph23HHHNGfOnLRo0aJ0ww03VPf1YlABqAtxjW7JBHbBDCoAdSCuCbola11gf/3rX09Lly4dc7n44ovT2rVrO581GAYVgNKJa7p0S9a6wI7TN5773OeuX2IYhi9xmkecwhGndAxS/F0AoFTimqF0S9bqU0SuuOKKdNhhh6Xbb7+9etHhU089lW655ZZ06KGHpm984xudRw2OQQWgZAKboXRL1urAjit6/OQnP+msZXGVj1122aWzNjgGFYBSiWuG0y1ZqwN7m222SY8//nhnLXvssceqU0kGzaACUCJxTS+6JWt1YO+7777p8MMPT7fddlt64okn0pNPPllds/qoo46qLq83aAYVgNKIa0aiW7JWB/Zdd92Vdt9992oghi477LBDdS72oBlUAEoirhmNbslaHdghLsV38803V5fvu+iii9J1112XVq1a1bl3sAwqAKUQ14xFt2StD+wf//jHacmSJem4446rriQSrr/++urXQTOoAJRAXDMeuiVrdWAvX768ejHjggULqqFYvXp1FdxbbrlluuSSSzqPGhyDCsCgiWvGS7dkrQ7shQsXprPPPrv6ON50JgI7LFu2rIruQTOoAAySuGYidEvW6sDeeuut09NPP119PDSw41SRWbNmVR8PkkEFYJAENhOhW7JWB/ZOO+2UVq5cWX08NLB/9KMfVdfIHjSDCsCgiGsmSrdkrQ7sxYsXp0MOOSStWLGiCuyHH344XX311dXpIUcffXTnUYNjUAEYBHHNptAtWasD+9FHH0377bdfNRBDl4MOOig99NBDnUcNjkEFYLqJazaVbslaHdhd8U6OS5cuTZdffnl1NLsUBhWA6SSumQzdkgnsghlUAKaLuGaydEvWusCOd2yMo9VjLRdffHH1Lo+DZFABmA7imn7QLVnrAjveWCZe0NhdYhiGLzNmzEhz5sxJa9as6XzWYMTfBQCmkrimX3RL1upTRK644op02GGHpdtvv7269vVTTz2VbrnllnTooYemb3zjG51HDY5BBWAqiWv6SbdkrQ7sPfbYI/3kJz/prGUPPPBA2mWXXTprg2NQAZgq4pp+0y1ZqwM73kzm8ccf76xljz32WHUqyaAZVACmisCm33RL1urA3nfffdPhhx9eXabviSeeSE8++WS6884701FHHZX23nvvzqMGx6ACMBXENVNBt2StDuy77ror7b777tVADF122GGH6lzsQTOoAPSbuGaq6Jas1YEd4lJ8N998c3X5vosuuihdd911adWqVZ17B8ugAtBP4pqppFuy1gf2j3/847RkyZJ03HHHVVcSCddff33166AZVAD6RVwz1XRL1urAXr58efVixgULFlRDsXr16iq4t9xyy3TJJZd0HjU4BhWAfhDXTAfdkrU6sBcuXJjOPvvs6uN405kI7LBs2bIqugfNoALQDwKb6aBbslYH9tZbb52efvrp6uOhgR2nisyaNav6eJAMKgCTJa6ZLrola3Vg77TTTmnlypXVx0MD+0c/+lF1jexBM6gATIa4ZjrplqzVgb148eJ0yCGHpBUrVlSB/fDDD6err766Oj3k6KOP7jxqcAwqAJtKXDPddEvW6sB+9NFH03777VcNxNDloIMOSg899FDnUYNjUAHYFOKaQdAtWasDuyveyXHp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adGiRWn77bdPu+66a/ryl7/cuac+Rtq2eIHu0P0Yy/e///3OvfVwww03VPsnXhMRL0CO+exqwr4bbfuasP/++7//Oy1YsKDavvnz51cvIO9qwv4bbfuasP/C448/nubNm7dBZzRh33X12r4m7Lutttpqo21YsWJFdV+T9t9kCOzCRMzsueee6cEHH0yrVq1Kxx13XCMCtOujH/1oesc73tFZa4YTTjghHXPMMWnhwoUbROjPfvaztNNOO1X/Ka5duzbddNNN1X+UdfpGOtK2xQ+C8Y5dK1eu7NxSP4899liaPXt2+tKXvlStx38K8YNERGkT9t1o29eE/Rd/99ieK664olq/+eab05Zbblntqybsv9G2rwn7r+ttb3tbdfnabmc0Yd8NNXz7mrDvYh/FNjz00EOdW7Km7b/JENiF2XfffdMFF1zQWUvpvvvuq34yfOaZZzq31Nt73vOe9IEPfKCz1gzxDSQceOCBG0To1VdfXR01HCq+2X7kIx/prJVvpG179NFHq2+wTz31VOeW+on/HL74xS921taJHyTOO++8Ruy70bavCfsvAuVrX/taZ22dl770pdXRsibsv9G2rwn7L1x++eXVTC5ZsmR9ZzRh33X12r4m7LuHH3642oY4CDhck/bfZAnswjz/+c9PN954Y2dtnS222CLdfvvtnbV6iyPy8UNEPO05d+7cdNhhhzXmOuDDIzR+gn/d617XWVsn3i7/8MMP76zVx/Bti30W32DjXUjjaMVLXvKSDe6vo/vvv786Ynj33Xc3at91Dd2+pu2/NWvWVDEa3z8feOCBxu2/4dvXhP0XoRlHdu+66650yimnrO+Mpuy7kbavCfsuTgWZMWPG+m3Ya6+90mc/+9nqviZ+79xUArswcV7Tbbfd1llbZ86cOek73/lOZ63e4u3i45vNE088kZ588snqdJE4KhNPJdXd8Aj9xCc+Uf0AMdRZZ52VDj744M5afQzftoi1OCpx/fXXV/su5nO77bbb6IhbXcTRwvhP4swzz6zWm7TvwvDta9L++8pXvlK9riPi89JLL61ua9L+67V9Tdh/b3nLW9Lpp59efTw0QJuy70bavibsu3hm/V/+5V/St7/97Wob4tc4DSTms2nfOydDYBcmXtg4NKZjeOMUkTvuuKNzS7PEeaLx03wTjmIPj9D4iX74N5WPfexj6U1velNnrT6Gb1sv733ve6tnKOomzm2NpzTj1ImuJu27XtvXS133X4gjvHFueRxN+/rXv96o/ReGb18vddp/8QZr8SK42K4wNECbsO9G275e6vxvr2vx4sXp+OOPb9y/vckQ2IV59atfvcF/hD/4wQ+qU0R6netUR3H6y9CronTP5arzCz66hkfoN7/5zepqMEPFU2pxPl7dDN+2OL83wm2od7/73bV7AWvMY7zC/9prr+3csk5T9t1I29eE/Rcvmuoe0e1617veld7+9rc3Yv+Ntn1133+xL3bcccfqB79Y4ujn1ltvnV7zmtc0Yt+Ntn1N+LcXF2G45ZZbOmvrvPOd76xeFN+k//cmS2AXJl7guMcee1TB+fTTT6cjjjiiejqpKQ455JDqH1u8wCNeuBnfVOIn/SYYHqFx9CLOwYunx+KV49ddd111eaY4B7Zuhm9bhFuczxtPc4b4DyP+E4nLitVFzGD853fNNdd0bsmasO9G274m7L84ohvb8K1vfatav/fee6t9FkfQmrD/Rtu+Juy/oYYe4W3S982uodvXhH0Xf/f4gSFODQnxYvjYR8uXL2/k/ttUArswcUrIhz70oeqoU5wuEjEa19Fsip/+9KfV+VlxPmFsX3wcL9qpq/hm0r0GaJwnGS/8iI/j6bIQ59O/6lWvqr6Bxg9OdTrPbqxtiytUxDVO41Jwu++++5inIJRm6dKl1bMn3W3sLu973/uq++u878JY21f3/RdiG2LfxD6KF03HewjE3Ia6778w2vY1Yf91DT+Fogn7bqjh29eEfXf++eenf/zHf6y2IfZRbFNX0/bfphLYAADQRwIbAAD6SGADAEAfCWwAAOgjgQ0AAH0ksAEAoI8ENgAA9JHABgCAPhLYAIzbwQcf7P8EgDEIbIAa2X///dNb3vKWztr0E9gAYxPYADUisAHKJ7ABamSswH722WfTmWeemXbbbbe05ZZbpl122SV94hOfqO67+uqr03Oe85z0ox/9qFrvOv7449OiRYuqjx9//PG0ePHi9KIXvaj6/Je97GXpiiuuqO4LAhtgbAIboEbGCuyTTjop7bzzzunWW2+tYvvb3/52mjNnTvryl79crc+bNy+ddtppnUentGrVqur+z33uc9X6AQccUEX0ypUrq/u+8IUvpBkzZqR77rmnul9gA4xNYAPUyFiBvcMOO6Rzzjmns7bOBz7wgbTvvvtWH3/wgx9MCxYsqD4Ol112WZo5c2Z69NFH0/e///3qCHf8OtTChQvThz/84epjgQ0wNoENUCOjBfZjjz1WBXKvZe7cudVj7rjjjmr97rvvrtbf/OY3pyOPPLL6eNmyZRt9Xnc55phjqscIbICxCWyAGhktsOOUjojhpUuXdm7pLY5gn3rqqempp55KW2+9dbr88sur26+88srq8x9++OFqvReBDTA2gQ1QI2OdIrLTTjulD33oQ521deJ86meeeaazltInP/nJ9PKXvzxdcskl6QUveEFavXp1dXucZx2BHaE9VNy+du3a6mOBDTA2gQ1QIxHYhx12WLr33ns3WCKiwxlnnJFmz56dli9fXoXz7bffnubPn59OPvnk6v4Qj40XLsYLGk888cTOresceuihaa+99qpOIVmzZk269NJLq6uJXHfdddX9AhtgbAIboEYisLvnRQ9dIqJDRPGSJUuqy+zFixfjMn2xHlcQGeq1r31t9Xm33XZb55Z1HnnkkXTcccel7bbbLs2aNas6neSrX/1q516BDTAeAhsAAPpIYAMAQB8JbAAA6COBDQAAfSSwAQCgjwQ2AAD0kcAGAIA+EtgAANBHAhsAAPpIYAMAQB8JbAAA6COBDQAAfSSwAQCgjwQ2AAD0kcAGAIA+EtgAANBHAhsAAPpIYAMAQB8JbAAA6COBDQAAfSSwAQCgjwQ2AAD0kcAGAIC+Sen/AVW0wW/0xxpLAAAAAElFTkSuQmCC;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;-1486.09\&quot; y=\&quot;3410\&quot; width=\&quot;728\&quot; height=\&quot;541\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-115\&quot; value=\&quot;\&quot; style=\&quot;shape=image;verticalLabelPosition=bottom;labelBackgroundColor=default;verticalAlign=top;aspect=fixed;imageAspect=0;image=data:image/png,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;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;-1060\&quot; y=\&quot;2570\&quot; width=\&quot;158.63\&quot; height=\&quot;60\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n        &lt;mxCell id=\&quot;uOGT53f4ggUUIF5St2bJ-116\&quot; value=\&quot;\&quot; style=\&quot;shape=image;verticalLabelPosition=bottom;labelBackgroundColor=default;verticalAlign=top;aspect=fixed;imageAspect=0;image=data:image/png,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;\&quot; vertex=\&quot;1\&quot; parent=\&quot;WIyWlLk6GJQsqaUBKTNV-1\&quot;&gt;\n          &lt;mxGeometry x=\&quot;-1194.5\&quot; y=\&quot;2490\&quot; width=\&quot;179\&quot; height=\&quot;59\&quot; as=\&quot;geometry\&quot; /&gt;\n        &lt;/mxCell&gt;\n      &lt;/root&gt;\n    &lt;/mxGraphModel&gt;\n  &lt;/diagram&gt;\n&lt;/mxfile&gt;\n&quot;}"></div>
<script type="text/javascript" src="https://viewer.diagrams.net/js/viewer-static.min.js"></script>

<h3 id="the-map-anatomy">The Map Anatomy</h3>

<p>At first glance it may be difficult to understand the map, so I’ll break it down:</p>

<ul>
  <li>The whole system of network levelling is a child of an abstract network statistic class for the server, since levelling should be tracked, this also means we’ll be able to easily manipulate other statistics, especially with boosters.</li>
</ul>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
 * This class represents a network statistic.
 */</span>
<span class="kd">public</span> <span class="kd">abstract</span> <span class="kd">class</span> <span class="nc">NetworkStatistic</span> <span class="o">{</span>

	<span class="kd">protected</span> <span class="kd">static</span> <span class="kd">final</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">&gt;</span> <span class="n">availableStats</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ArrayList</span><span class="o">&lt;&gt;();</span>

	<span class="kd">protected</span> <span class="kt">int</span> <span class="n">value</span><span class="o">;</span>
	<span class="kd">protected</span> <span class="nc">String</span> <span class="n">name</span><span class="o">;</span>
	<span class="kd">protected</span> <span class="nc">String</span> <span class="n">type</span><span class="o">;</span>
	<span class="kd">protected</span> <span class="no">UUID</span> <span class="n">player</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>

<ul>
  <li>Most of the features we discussed earlier are then a child of network levelling or listen in some way to network levelling.</li>
</ul>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">Booster</span><span class="o">&lt;</span><span class="no">T</span> <span class="kd">extends</span> <span class="nc">NetworkStatistic</span><span class="o">&gt;</span> <span class="o">{</span>

	<span class="kd">private</span> <span class="kd">final</span> <span class="nc">String</span> <span class="n">boosterName</span><span class="o">;</span>
	<span class="kd">private</span> <span class="kd">final</span> <span class="no">UUID</span> <span class="n">playerUUID</span><span class="o">;</span>
	<span class="kd">private</span> <span class="kd">final</span> <span class="no">T</span> <span class="n">statistic</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Notice how I didn’t use a raw type of NetworkStatistic, this was peril not to do. Having a generic type of NetworkStatistic allow us to instantiate boosting for different types of network statistics, which also helps to be proactive for any future additions of network statistics, and this was the basis for how I started the project.</p>

<h2 id="player-psychology">Player Psychology</h2>

<p>It’s important to me that the systems I create, are as fun, intuitive, and enjoyable as possible for players. I think of players as customers, and so understanding your target audience is very important.</p>

<p>Here are the steps I took to create an engaging system:</p>

<ul>
  <li>Horizontal progression over vertical (unlock new abilities, rather than making players more powerful; make them feel special)</li>
  <li>Visual progression system with available tracking will give small amounts of dopamine</li>
  <li>Rewards for levelling give an incentive to keep investment</li>
  <li>Purchasing boosters can offer great benefits to players of the server to achieve rewards faster (increasing ROI)</li>
</ul>

<h2 id="discord-integration">Discord Integration</h2>

<p>This was simply achieved through a HTTPS connection to the url of a discord channel. All the functionality to post was customizable for admins (thumbnails, footers, content, titles, rgb support, and more).</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="no">URL</span> <span class="n">url</span> <span class="o">=</span> <span class="k">new</span> <span class="no">URL</span><span class="o">(</span><span class="k">this</span><span class="o">.</span><span class="na">url</span><span class="o">);</span>
<span class="nc">HttpsURLConnection</span> <span class="n">connection</span> <span class="o">=</span> <span class="o">(</span><span class="nc">HttpsURLConnection</span><span class="o">)</span> <span class="n">url</span><span class="o">.</span><span class="na">openConnection</span><span class="o">();</span>
</code></pre></div></div>

<h2 id="conclusion">Conclusion</h2>

<ul>
  <li>Be ready to make vast changes; concepts aren’t final.</li>
  <li>Over the years creation has become more trivial, but creating something that’s meaningful requires a lot more dedication.</li>
  <li>Research, and then research some more</li>
</ul>

<p>You can find a link to my repository, containing fully documented code of a basic implementation, similar to how I’ve incorporated network levelling for servers in the past <a href="https://github.com/qbb84/NetworkLevelling">View Repo</a></p>]]></content><author><name>qbb84</name></author><category term="Minecraft" /><category term="Spigot" /><category term="Minigames" /><category term="DBMS" /><summary type="html"><![CDATA[This is a technical post regarding Network Levelling, and the tools I used to design a rigorous plugin for Minecraft networks.]]></summary></entry><entry><title type="html">Creative Raid Abilities</title><link href="https://qbb84.github.io/creative-raid-abilities" rel="alternate" type="text/html" title="Creative Raid Abilities" /><published>2022-07-22T00:00:00+00:00</published><updated>2022-07-22T00:00:00+00:00</updated><id>https://qbb84.github.io/Creative-Raid-Abilities</id><content type="html" xml:base="https://qbb84.github.io/creative-raid-abilities"><![CDATA[<p>If you enjoy MMOs, and visual wizardry, this should be of interest to you.</p>

<p>I had an idea about creating a ‘raid’ minigame for Minecraft, similar to MMOs like WOW, FFXIV, Destiny 2, and then I thought it’d be even more fun to create raid abilities, as I’d be able to flesh out the abilities much faster, and a lot of people enjoy seeing cool animations.</p>

<p>Here I’m going to discuss one of the abilities I called “Torture”, and show early development footage.</p>

<h2 id="torture-raid-ability">Torture (raid ability)</h2>

<p>Torture is a high mana ability due to it’s power, use carefully.</p>

<p>This was the initial adage I had in mind when creating, but first some Math.</p>

<h3 id="why-quadratic-equations">Why Quadratic Equations</h3>

<p>Quadratic equations are mathematical expressions of the form <code class="language-plaintext highlighter-rouge">ax^2+bx+c=0</code>, representing parabolic curves. In Minecraft, they can be useful for visual effects by simulating realistic projectile motion, creating aesthetic designs, and adding dynamic elements to abilities or spells. The parabolic nature of quadratic equations suits the trajectory of particles, enhancing the visual experience in the game.</p>

<p>Knowing this, I incorporated a few equations to calculate certain parameters related to trajectory, positions, and timing of particle effects.</p>

<h3 id="particle-effects">Particle Effects</h3>

<p>This can be achieved using NMS (Net Minecraft Server), which is used to access the server code of Minecraft, allowing the sending of packets with bundled data for more control. Here’s what a basic packet of data relating to particle effects might look like:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">PacketPlayOutWorldParticles</span> <span class="n">packet</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">PacketPlayOutWorldParticles</span><span class="o">(</span><span class="n">particleType</span><span class="o">,</span> <span class="kc">true</span><span class="o">,</span>
                <span class="n">particleX</span><span class="o">,</span> <span class="n">particleY</span><span class="o">,</span> <span class="n">particleZ</span><span class="o">,</span> <span class="n">offsetX</span><span class="o">,</span> <span class="n">offsetY</span><span class="o">,</span> <span class="n">offsetZ</span><span class="o">,</span> <span class="n">speed</span><span class="o">,</span> <span class="n">count</span><span class="o">);</span>

<span class="o">((</span><span class="nc">CraftPlayer</span><span class="o">)</span> <span class="n">player</span><span class="o">).</span><span class="na">getHandle</span><span class="o">().</span><span class="na">playerConnection</span><span class="o">.</span><span class="na">sendPacket</span><span class="o">(</span><span class="n">packet</span><span class="o">);</span>
</code></pre></div></div>

<h3 id="the-design">The Design</h3>

<p>I initially drew a sketch of the ability, it was going to be used on an entity. When used the blocks around the entity within a radius rise, and then the blocks that rise are chosen pseudo-randomly to fly and cause destruction where the ability was used.</p>

<p>There also contains a circle for the ability location, and a square inside the circle for where most the damage is taken.</p>

<p>This was my original design, and there were iterations which contained a large square which was a region of containment, inside the region there would be totems that rise from the ground to inhibit damage from an explicit range using ray-tracing, this became the design of another ability.</p>

<h3 id="early-development-footage">Early Development Footage</h3>

<iframe width="560" height="315" src="https://www.youtube.com/embed/u-O7jM90qtQ?si=b2Vs4xYRW4AixWD2" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen=""></iframe>]]></content><author><name>qbb84</name></author><category term="Raid" /><category term="Quadratic Equations" /><category term="Math" /><category term="Game Development" /><summary type="html"><![CDATA[If you enjoy MMOs, and visual wizardry, this should be of interest to you.]]></summary></entry></feed>