<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: ARIAN</title>
    <description>The latest articles on DEV Community by ARIAN (@arianlavi).</description>
    <link>https://dev.to/arianlavi</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4050659%2F919c28f6-327d-496d-833b-783984906451.png</url>
      <title>DEV Community: ARIAN</title>
      <link>https://dev.to/arianlavi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/arianlavi"/>
    <language>en</language>
    <item>
      <title>CS2 Matchmaking Fixing Your Ping, I Built a Tool That Picks Your Servers</title>
      <dc:creator>ARIAN</dc:creator>
      <pubDate>Mon, 03 Aug 2026 10:14:45 +0000</pubDate>
      <link>https://dev.to/arianlavi/cs2-matchmaking-fixing-your-ping-i-built-a-tool-that-picks-your-servers-1i32</link>
      <guid>https://dev.to/arianlavi/cs2-matchmaking-fixing-your-ping-i-built-a-tool-that-picks-your-servers-1i32</guid>
      <description>&lt;p&gt;How I built CS2 Armory a Python tool that gives you full control over which Steam relay servers Counter-Strike 2 connects to, using nothing but Windows Firewall rules&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9inbtet4oxsr6tkgtamt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9inbtet4oxsr6tkgtamt.png" alt="a Python tool that gives you full control over which Steam relay servers Counter-Strike 2" width="800" height="618"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  CS2 Matchmaking Keeps Putting You on the Wrong Servers? I Built a Fix
&lt;/h1&gt;

&lt;p&gt;You queue up for a CS2 match The game picks a server, Your ping is 120ms You didnt ask for this.&lt;/p&gt;

&lt;p&gt;Valves matchmaking system chooses your Steam Datagram Relay (SDR) servers based on a ping estimate that doesnt always match what you actually experience, Sometimes it works fine Sometimes it routes you through a relay on the other side of the planet.&lt;/p&gt;

&lt;p&gt;I got tired of this. So I built &lt;strong&gt;CS2 Armory&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What CS2 Armory Does
&lt;/h2&gt;

&lt;p&gt;It pulls the live list of SDR relay servers directly from Steams API, groups them by region, and lets you &lt;strong&gt;block the ones you dont want&lt;/strong&gt; using native Windows Firewall rules.&lt;/p&gt;

&lt;p&gt;Thats it, No config hacks, No game file modifications, No third-party proxies, Just outbound firewall rules that Steams matchmaking is forced to respect&lt;/p&gt;

&lt;h2&gt;
  
  
  How It Actually Works
&lt;/h2&gt;

&lt;p&gt;Under the hood, CS2 Armory manages outbound block rules in Windows Firewall, These rules target the IP ranges of specific relay servers, When Steams matchmaking tries to connect to a blocked relay, it cant reach it so it falls back to the servers you've allowed.&lt;/p&gt;

&lt;p&gt;The app operates in its own dedicated firewall namespace, It won't touch your other software, your system rules, or anything else, When you click Unblock, every rule it created gets cleanly deleted.&lt;/p&gt;

&lt;p&gt;Here's the flow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. App fetches live SDR config from Steam API
2. Servers are grouped by region (EU, US, Asia, etc)
3. You pick which regions to keep
4. App creates firewall block rules for everything else
5. CS2 matchmaking is forced to use your allowed servers
6. Click "Unblock" to restore default behavior
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Key Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Live Server Sync&lt;/strong&gt; Pulls current SDR configurations straight from Steam's API. Updates automatically after Valve pushes changes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Smart Clustering&lt;/strong&gt; Groups nearby relay servers together. No scrolling through 200 individual entries&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One-Click Controls&lt;/strong&gt; Block everything except your target region, or pick specific servers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom Presets&lt;/strong&gt; Save configurations like "EU Only" or "No Asia" and load them instantly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Built-in Ping Tool&lt;/strong&gt; Test latency to each server before deciding.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Firewall Diagnostics&lt;/strong&gt; Check your Windows Firewall status and restore defaults in one click&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why Not Just Edit Game Configs?
&lt;/h2&gt;

&lt;p&gt;A few reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Valve overrides config changes&lt;/strong&gt; when the game updates. You lose your settings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Game configs dont target SDR relays directly&lt;/strong&gt; they affect connection quality settings, not server selection.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Firewall rules are the only thing Steam cannot bypass&lt;/strong&gt; The client respects outbound rules at the OS level&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Running from Source
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Arianlavi/cs2armory.git
&lt;span class="nb"&gt;cd &lt;/span&gt;cs2armory
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
python main.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Requirements:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Windows 10 or 11&lt;/li&gt;
&lt;li&gt;Python 3.9+&lt;/li&gt;
&lt;li&gt;Administrator privileges (for firewall rules)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Or just grab the prebuilt &lt;code&gt;.exe&lt;/code&gt; from the &lt;a href="https://github.com/Arianlavi/cs2armory/releases" rel="noopener noreferrer"&gt;Releases&lt;/a&gt; page and run it&lt;/p&gt;

&lt;h2&gt;
  
  
  What the Tool Looks Like
&lt;/h2&gt;

&lt;p&gt;The GUI shows all available SDR relay locations, grouped by country/region You can ping servers directly from the app, save presets, and toggle rules with a single button&lt;/p&gt;

&lt;p&gt;Everything is designed around speed, open the app, pick your region, hit Block, queue up&lt;/p&gt;

&lt;h2&gt;
  
  
  Important Disclaimer
&lt;/h2&gt;

&lt;p&gt;CS2 Armory only manages local Windows Firewall rules on your machine. It doesn't modify game files, inject into the CS2 process, or touch any server-side components. It doesn't guarantee lower ping, it influences which relays your client is allowed to connect to. Use it responsibly&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It Out
&lt;/h2&gt;

&lt;p&gt;The project is fully open source under the MIT license:&lt;/p&gt;

&lt;p&gt;🔗 &lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/Arianlavi/cs2armory" rel="noopener noreferrer"&gt;github.com/Arianlavi/cs2armory&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If it made your matchmaking experience better, drop a ⭐ on the repo. It takes 2 seconds and means a lot&lt;/p&gt;

</description>
      <category>python</category>
      <category>gamedev</category>
      <category>opensource</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>I Got Tired of PyInstaller CLI, So I Built a GUI for It With Built-in Source Protection</title>
      <dc:creator>ARIAN</dc:creator>
      <pubDate>Tue, 28 Jul 2026 08:20:13 +0000</pubDate>
      <link>https://dev.to/arianlavi/i-got-tired-of-pyinstaller-cli-so-i-built-a-gui-for-it-with-built-in-source-protection-4olg</link>
      <guid>https://dev.to/arianlavi/i-got-tired-of-pyinstaller-cli-so-i-built-a-gui-for-it-with-built-in-source-protection-4olg</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnbjwdvtjhah5249eaa2k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnbjwdvtjhah5249eaa2k.png" alt="PyPack main interface with project path, build options, and PyPack Crypt toggle" width="800" height="791"&gt;&lt;/a&gt;&lt;br&gt;
if you've ever tried to package a Python project into a &lt;code&gt;.exe&lt;/code&gt;, you've probably wanted to throw your laptop out the window.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pyinstaller --onefile&lt;/code&gt; works great for a hello-world script. But the second your project gets real custom icons, data files, hidden imports, two different Qt bindings somehow it all falls apart. No helpful error messages either. Just a blank window staring back at you.&lt;/p&gt;

&lt;p&gt;I dealt with this for way too long. Eventually I just decided to fix it myself. That's how &lt;strong&gt;PyPack&lt;/strong&gt; was born.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why PyInstaller Made Me Cry
&lt;/h2&gt;

&lt;p&gt;My project was a desktop app. CustomTkinter UI, custom &lt;code&gt;.ico&lt;/code&gt;, a couple of config files bundled in. Nothing crazy. But to build it with PyInstaller, I needed something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pyinstaller &lt;span class="nt"&gt;--onefile&lt;/span&gt; &lt;span class="nt"&gt;--windowed&lt;/span&gt; &lt;span class="nt"&gt;--icon&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;app.ico &lt;span class="nt"&gt;--name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;MyApp &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--add-data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"assets:assets"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--hidden-import&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;module1 &lt;span class="nt"&gt;--hidden-import&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;module2 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--exclude-module&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;PyQt5 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--exclude-module&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;PyQt6 &lt;span class="se"&gt;\&lt;/span&gt;
  ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Forget one hidden import? Build breaks. No error. Just silence. Then you spend an hour on Stack Overflow figuring out that &lt;code&gt;tkinter.ttk&lt;/code&gt; needs a separate flag.&lt;/p&gt;

&lt;p&gt;Yeah, I got real tired of that.&lt;/p&gt;

&lt;h2&gt;
  
  
  So What Does PyPack Actually Do?
&lt;/h2&gt;

&lt;p&gt;It wraps PyInstaller in a GUI. Pick your project, pick your settings, click Build. Done.&lt;/p&gt;

&lt;p&gt;Sounds simple, but here's where it gets interesting — it's not just a paint job over CLI commands. It actually fixes things PyInstaller gets wrong.&lt;/p&gt;

&lt;h3&gt;
  
  
  It catches imports PyInstaller misses
&lt;/h3&gt;

&lt;p&gt;PyInstaller uses &lt;code&gt;modulefinder&lt;/code&gt; under the hood. Problem is, &lt;code&gt;modulefinder&lt;/code&gt; is kinda bad at its job. It misses &lt;code&gt;tkinter&lt;/code&gt; submodules, for example, and then your build silently breaks.&lt;/p&gt;

&lt;p&gt;PyPack runs a full AST scan on your project instead. Catches way more stuff. Builds don't break for random mysterious reasons anymore.&lt;/p&gt;

&lt;h3&gt;
  
  
  It handles the Qt binding mess
&lt;/h3&gt;

&lt;p&gt;You know that thing where you have a &lt;code&gt;try/except&lt;/code&gt; for PyQt5 and PyQt6 fallback?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;PyQt6&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;QtWidgets&lt;/span&gt;
&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;ImportError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;PyQt5&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;QtWidgets&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PyInstaller sees both and just gives up. PyPack notices it, keeps only the one you're actually using, and moves on.&lt;/p&gt;

&lt;h3&gt;
  
  
  Real-time build log
&lt;/h3&gt;

&lt;p&gt;No more guessing if the build is frozen or actually working. You see every command, every step, and at the end you get a real success or failure status.&lt;/p&gt;

&lt;h2&gt;
  
  
  PyPack Crypt — The Thing I'm Actually Excited About
&lt;/h2&gt;

&lt;p&gt;This started as a side experiment but it ended up being the most useful part.&lt;/p&gt;

&lt;p&gt;Here's the problem nobody talks about: when you ship a PyInstaller &lt;code&gt;.exe&lt;/code&gt;, your raw &lt;code&gt;.py&lt;/code&gt; source files are sitting right inside it. Anyone with a tool like &lt;code&gt;pyinstxtractor&lt;/code&gt; can pull them out in seconds&lt;/p&gt;

&lt;p&gt;PyPack Crypt does this instead:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Compiles all your modules to bytecode&lt;/li&gt;
&lt;li&gt;Encrypts them with AES-256-GCM&lt;/li&gt;
&lt;li&gt;At runtime, decrypts straight into memory never writes to disk&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What makes it different from other obfuscation tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;New encryption key every build&lt;/strong&gt; no shared key hiding in a DLL somewhere&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Randomized container format&lt;/strong&gt; two builds of the same project look totally different under a hex editor&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GCM authentication&lt;/strong&gt; if someone tampers with the file, it won't decrypt at all&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Look, I'll be honest: nothing that runs Python bytecode on someone else's computer is truly unbreakable, But this kills the "download one tool, extract all source files in 30 seconds" approach. And for most real-world situations, that's enough.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Start
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Arianlavi/PyPack.git
&lt;span class="nb"&gt;cd &lt;/span&gt;PyPack
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
python pypack.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Point it at your project folder and entry script&lt;/li&gt;
&lt;li&gt;Add an icon if you have one&lt;/li&gt;
&lt;li&gt;Pick one-file or one-folder, windowed or console&lt;/li&gt;
&lt;li&gt;Flip on PyPack Crypt if you want source protection&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Build&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Your &lt;code&gt;.exe&lt;/code&gt; shows up in &lt;code&gt;dist/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you'd rather script it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pypack.builder&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;

&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;project_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/path/to/my/project&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;entry_script&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;main.py&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;icon&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app.ico&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;one_file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;windowed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;crypt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What's Coming
&lt;/h2&gt;

&lt;p&gt;Things I'm working on or thinking about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Batch builds for multiple projects at once&lt;/li&gt;
&lt;li&gt;[ ] PyArmor as an alternative encryption backend&lt;/li&gt;
&lt;li&gt;[ ] Auto-update mechanism&lt;/li&gt;
&lt;li&gt;[ ] Linux and macOS support&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Grab It
&lt;/h2&gt;

&lt;p&gt;Fully open source, MIT license, No strings attached&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/Arianlavi/PyPack" rel="noopener noreferrer"&gt;https://github.com/Arianlavi/PyPack&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Star it if it helps you out. Open an issue if something's broken, I actually read them.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Made with Python, CustomTkinter, and an unhealthy amount of late nights fighting PyInstaller&lt;/em&gt; 🐍&lt;/p&gt;

</description>
      <category>python</category>
      <category>beginners</category>
      <category>opensource</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
