<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.8.5">Jekyll</generator><link href="http://localhost:4000/feed.xml" rel="self" type="application/atom+xml" /><link href="http://localhost:4000/" rel="alternate" type="text/html" /><updated>2020-01-15T19:44:26+00:00</updated><id>http://localhost:4000/feed.xml</id><title type="html">William Robb</title><subtitle>A blog about technology and what I do with it! From 3D printing to web development to VR and Gaming.</subtitle><entry><title type="html">ZFS SMB Share Guest Access</title><link href="http://localhost:4000/2020/01/15/zfs-smb-share-guest-access.html" rel="alternate" type="text/html" title="ZFS SMB Share Guest Access" /><published>2020-01-15T00:00:00+00:00</published><updated>2020-01-15T00:00:00+00:00</updated><id>http://localhost:4000/2020/01/15/zfs-smb-share-guest-access</id><content type="html" xml:base="http://localhost:4000/2020/01/15/zfs-smb-share-guest-access.html">&lt;p&gt;To make things easy I’ve set up a SMB share on my ZFS pool with guest access so I don’t need logins to access the share.&lt;/p&gt;

&lt;p&gt;Heres how to set it up.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;root@alba:~# zfs get sharesmb
root@alba:~# zfs get sharesmb lomond/share
NAME                  PROPERTY  VALUE     SOURCE
lomond/share  sharesmb  -         -
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;root@alba:~# zfs set sharesmb=on lomond/share
root@alba:~# zfs share lomond/share
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;root@alba:~# zfs get sharesmb lomond/share
NAME          PROPERTY  VALUE     SOURCE
lomond/share  sharesmb  on        local
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To enable guest access navigate to&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/var/lib/samba/usershares
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There will be a file with the name of the share you created, in this case: &lt;strong&gt;lomond/share&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Change the &lt;strong&gt;guest_ok=n&lt;/strong&gt; to &lt;strong&gt;guest_ok=y&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;root@alba:/var/lib/samba/usershares# cat lomond_share
#VERSION 2
path=/lomond/share
comment=Comment: /lomond/share
usershare_acl=S-1-1-0:F
guest_ok=y
sharename=lomond_share
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</content><author><name></name></author><summary type="html">To make things easy I’ve set up a SMB share on my ZFS pool with guest access so I don’t need logins to access the share.</summary></entry><entry><title type="html">ESP8266 Indoor location trilateration</title><link href="http://localhost:4000/2019/06/29/esp01.html" rel="alternate" type="text/html" title="ESP8266 Indoor location trilateration" /><published>2019-06-29T00:00:00+01:00</published><updated>2019-06-29T00:00:00+01:00</updated><id>http://localhost:4000/2019/06/29/esp01</id><content type="html" xml:base="http://localhost:4000/2019/06/29/esp01.html">&lt;p&gt;I wanted to get into electronics and IoT devices. I was pointed to the ESP8266 chipset.&lt;/p&gt;

&lt;p&gt;I’m really interested in indoor location services, which 5G is bringing about. I had an idea of creating an indoor location service for my house which could see where my phone was and could pipe that informational data into an amazon alexa or similar skill for location specific  automatic execution of switching on lights etc.&lt;/p&gt;

&lt;h2 id=&quot;iot&quot;&gt;IoT&lt;/h2&gt;

&lt;p&gt;I purchased a set of ESP8266 ESP-01S modules from &lt;a href=&quot;https://www.amazon.co.uk/gp/product/B0728CBGKT&quot;&gt;amazon&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So how to go about this? I would be using the ESP-01 to use promiscuous wifi scanning to pick up the surrounding wifi enabled devices.
I would need multiple nodes to pick up the signal strength from the devices and calculate, through trilateration, the estimated location of the devices.&lt;/p&gt;

&lt;p&gt;Why trilateration? The 802.11 protocol has an RSSI field which indicates signal strength. A node sampling a target device’s 802.11 packets can use the RSSI data as a rough indicator of how far away the target device is. By using multiple nodes to sample the targets signal strength to them , an estimate can be given based on the overlap of these different ranges on a 2d plane.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://upload.wikimedia.org/wikipedia/commons/thumb/c/c3/3spheres.svg/500px-3spheres.svg.png&quot; alt=&quot;trilateration&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;circuits&quot;&gt;Circuits&lt;/h2&gt;
&lt;p&gt;These small ESP-01S modules don’t have much to them, to flash them I needed to create a flashing circuit.
I prototyped it first then used a perf board to make something a bit longer lasting.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/esploc/proto.jpg&quot; alt=&quot;&quot; /&gt;&lt;img src=&quot;/assets/esploc/protoplugged.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/esploc/perffront.jpg&quot; alt=&quot;&quot; /&gt;&lt;img src=&quot;/assets/esploc/perfback.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;implementation&quot;&gt;Implementation&lt;/h2&gt;

&lt;p&gt;Plan for collecting RSSI data:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Listen and collect client RSSI information for random range between 15-60 seconds per node.&lt;/li&gt;
  &lt;li&gt;Connect to MQTT network and publish client data, hopefully in this time the other nodes will sense this node so they can find each others location.&lt;/li&gt;
  &lt;li&gt;Go back into monitor mode and continue collecting data.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;My main source of reference for doing this is &lt;a href=&quot;https://www.hackster.io/rayburne/esp8266-mini-sniff-f6b93a&quot;&gt;Ray Burnette’s Mini Sniff sketch&lt;/a&gt;.
I tweaked it to pick up all wifi packet types rather than just data and QoS.&lt;/p&gt;

&lt;p&gt;I used the &lt;a href=&quot;https://pubsubclient.knolleary.net/&quot;&gt;Ardunio Client for MQTT&lt;/a&gt; for connecting to a Mosquitto service running on a raspberry pi&lt;/p&gt;

&lt;p&gt;I want to be able to process and visualise the data to see if it is estimating locations correctly.
To do this im using &lt;a href=&quot;https://github.com/mqttjs&quot;&gt;MQTT.js&lt;/a&gt; to create a browser based MQTT client and will be using &lt;a href=&quot;https://p5js.org/&quot;&gt;P5.js&lt;/a&gt; to visualise the data.&lt;/p&gt;

&lt;p&gt;I integrated the sniffing sketch with the publishing of data to MQTT and listened for the data on the browser client.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/esploc/data.PNG&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Sources:&lt;/p&gt;

&lt;p&gt;https://www.hackster.io/rayburne/esp8266-mini-sniff-f6b93a
https://www.hackster.io/kosme/esp8266-sniffer-9e4770
https://www.carvesystems.com/news/writing-a-simple-esp8266-based-sniffer/&lt;/p&gt;

&lt;p&gt;https://www.instructables.com/id/MQTT-Bare-Minimum-Sketch/&lt;/p&gt;

&lt;p&gt;https://learn.adafruit.com/diy-esp8266-home-security-with-lua-and-mqtt/configuring-mqtt-on-the-raspberry-pi&lt;/p&gt;</content><author><name></name></author><summary type="html">I wanted to get into electronics and IoT devices. I was pointed to the ESP8266 chipset.</summary></entry><entry><title type="html">Replacing the battery on a Sony PSP 1000</title><link href="http://localhost:4000/2019/03/26/replacing-the-battery-on-a-sony-psp-1000.html" rel="alternate" type="text/html" title="Replacing the battery on a Sony PSP 1000" /><published>2019-03-26T00:00:00+00:00</published><updated>2019-03-26T00:00:00+00:00</updated><id>http://localhost:4000/2019/03/26/replacing-the-battery-on-a-sony-psp-1000</id><content type="html" xml:base="http://localhost:4000/2019/03/26/replacing-the-battery-on-a-sony-psp-1000.html">&lt;p&gt;I’ve had an original PSP since it’s release in the UK in 2005, the battery in it has since deteriorated and can’t hold a charge more than half a hour.
After seeing various posts of others hardmodding their PSP to replace the stock battery with a higher capacity LIPO by removing the UMD drive, I decided to give it a shot.&lt;/p&gt;

&lt;p&gt;I bought &lt;a href=&quot;https://www.aliexpress.com/item/White-Black-Color-Full-Housing-Shell-Cover-Case-Replacement-for-PSP1000-PSP-1000-Game-Console-with/32862251759.html?spm=a2g0s.9042311.0.0.2c7a4c4dHiZR10&quot;&gt;a full replacement shell from aliexpress&lt;/a&gt; since my faceplate had a chip in it and a &lt;a href=&quot;https://www.amazon.co.uk/gp/product/B07DMCNXQK/ref=oh_aui_search_asin_title?ie=UTF8&amp;amp;psc=1&quot;&gt;cheap lipo from amazon&lt;/a&gt; with the primary goal being the largest capacity which would fit my estimated dimensions of the PSP’s interior once removing the UMD drive.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/psp/parts.jpg&quot; alt=&quot;parts&quot; /&gt;&lt;/p&gt;

&lt;p&gt;To remove the UMD drive, I had to remove the battery, faceplate, home/volume buttons and LCD screen just to get to two tiny screws holding the UMD drive door in. Afterwards it should have been as simple as popping the drive door out its hinges to access the UMD drive, unfortunatly I broke the door. Thankfully I had the full replacement shell.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/psp/faceplate_remove.jpg&quot; alt=&quot;faceplate&quot; /&gt;&lt;/p&gt;

&lt;p&gt;After removing the UMD drive I had to cut some of the plastic shell to provide more space for the replacement battery.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/psp/removed_umd_cuts.jpg&quot; alt=&quot;removedumd&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I did a test fit to get an idea of the fit. I also had to cut the edges of the replacement UMD Drive door so it wouldn’t pierce the battery when closed.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/psp/fit.jpg&quot; alt=&quot;fit&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Next, in order to use my replacement battery I would need to reuse the original protection circuit as apparently it has some form of DRM or at least some microcontroller to inform the PSP of the batteries stats.
&lt;img src=&quot;/assets/psp/original_battery.jpg&quot; alt=&quot;original_battery&quot; /&gt;&lt;/p&gt;

&lt;p&gt;So I cut the battery open and salvaged the circuit and disposed of the old LIPO cell.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/psp/opened_battery.jpg&quot; alt=&quot;battery&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I then soldered the terminals of the battery to the protection circuit, please forgive my poor soldering.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/psp/soldered_battery.jpg&quot; alt=&quot;soldered_battery&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Here it is testing the fit and connection
&lt;img src=&quot;/assets/psp/fit2.jpg&quot; alt=&quot;fit2&quot; /&gt;&lt;/p&gt;

&lt;p&gt;After fitting the new UMD drive door, you can see how sleak it could look, it hides the battery perfectly. The hook mechanism which holds the UMD drive door closed still works.
&lt;img src=&quot;/assets/psp/battery_hidden.jpg&quot; alt=&quot;battery_hidden&quot; /&gt;&lt;/p&gt;

&lt;p&gt;To make it look a bit nicer and more stable, I reused the old battery shell and stuffed it with some cardboard to hold the circuit in place.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/psp/battery_reused.jpg&quot; alt=&quot;battery_reused.jpg&quot; /&gt;&lt;/p&gt;

&lt;p&gt;After putting it all back together it works! With the removed UMD drive.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/psp/finished.jpg&quot; alt=&quot;finished&quot; /&gt;&lt;/p&gt;</content><author><name></name></author><summary type="html">I’ve had an original PSP since it’s release in the UK in 2005, the battery in it has since deteriorated and can’t hold a charge more than half a hour. After seeing various posts of others hardmodding their PSP to replace the stock battery with a higher capacity LIPO by removing the UMD drive, I decided to give it a shot.</summary></entry><entry><title type="html">Jenkins and Jekyll</title><link href="http://localhost:4000/2019/02/11/jenkins-and-jekyll.html" rel="alternate" type="text/html" title="Jenkins and Jekyll" /><published>2019-02-11T00:00:00+00:00</published><updated>2019-02-11T00:00:00+00:00</updated><id>http://localhost:4000/2019/02/11/jenkins-and-jekyll</id><content type="html" xml:base="http://localhost:4000/2019/02/11/jenkins-and-jekyll.html">&lt;p&gt;For this blog, I’m using &lt;a href=&quot;https://jekyllrb.com&quot;&gt;Jekyll&lt;/a&gt;, a Ruby based static site generator that uses markup pages to generate static html pages.&lt;/p&gt;

&lt;p&gt;I wanted to automate the build and deployment process using Jenkins.&lt;/p&gt;

&lt;p&gt;As i’m using Proxmox in my &lt;a href=&quot;/2019/02/07/building-a-homelab.html&quot;&gt;homelab&lt;/a&gt;, I can install various container images, one of which is Turnkey linux Jenkins which simplfies the setup.&lt;/p&gt;

&lt;p&gt;After deploying the container and logging in as root and I can begin setting up the &lt;a href=&quot;https://jekyllrb.com/docs/&quot;&gt;prerequisites for Jekyll&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;prerequsites-for-jekyll&quot;&gt;Prerequsites for Jekyll&lt;/h3&gt;
&lt;p&gt;Install Ruby dev env and lftp&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;sudo apt-get install ruby-full build-essential lftp&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Install Jekyll gem&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;gem install jekyll bundler&lt;/code&gt;&lt;/p&gt;

&lt;h3 id=&quot;local-development-site&quot;&gt;Local Development site&lt;/h3&gt;

&lt;p&gt;I want to have a local development site to view changes before pushing to the live site. For this I am using Jenkins pipelines to configure a local deployment on the develop branch.
Turnkey linux Jenkins image includes apache2 which is proxying the Jenkins tomcat instance which I can use to host the development Jekyll blog.&lt;/p&gt;

&lt;p&gt;Add a site configuration and create a directory to hold our development site that is writable by the jenkins user: &lt;code class=&quot;highlighter-rouge&quot;&gt;drwxrwxr-x 2 jenkins  www-data 2 Feb 13 21:21 jekyll-dev&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;/etc/apache2/sites-available/jekyll-dev.conf&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Listen 8000

&amp;lt;VirtualHost *:8000&amp;gt;
    DocumentRoot &quot;/var/www/jekyll-dev&quot;
&amp;lt;/VirtualHost&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then symlink it to the sites-enabled folder.
&lt;code class=&quot;highlighter-rouge&quot;&gt;root@jenkins .../apache2/sites-enabled# ln -s ../sites-available/jekyll-dev.conf jekyll-dev.conf&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Restart apache with &lt;code class=&quot;highlighter-rouge&quot;&gt;apachectl restart&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Double check apache is listening on the new port&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;root@jenkins .../apache2/sites-enabled# netstat -altp | grep 8000
tcp6       0      0 [::]:8000               [::]:*                  LISTEN      340/apache2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In Jenkins create new job that is a multibranch pipeline and configure it to use our GIT repo with our Jekyll blog, I’m selfhosting a&lt;a href=&quot;https://gogs.io&quot;&gt; gogs.io&lt;/a&gt; GIT server.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/gogs_jekyll.PNG&quot; alt=&quot;gogs&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The branches must have a Jenkins pipeline file in the root of the repo.
I’ll be using rsync to copy the generated static html files over to our web directory. For deployment to production i’ll be using lftp.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Jenkinsfile&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;pipeline {
    agent any

    stages {

		stage('Install Bundles') {
            steps {
                echo 'Installing bundles..'
sh 'bundle install --path ~/.gem'
            }
        }
        stage('Building site') {
            steps {
                echo 'Building..'
sh 'bundle exec jekyll build'
            }
        }
        stage('Deploy') {
			when {
                branch 'develop'
            }
            steps {
                echo 'Deploying to dev....'
sh 'rsync -avzh ./_site/ /var/www/jekyll-dev/
            }
			
			when {
                branch 'master'
            }
            steps {
                echo 'Deploying....'
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;dev-deployment&quot;&gt;Dev deployment&lt;/h3&gt;

&lt;p&gt;Assuming the above configuration goes correctly, upon triggering the Jenkins build it should build our site and rsync it to our local web directory&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/jenkins_blog_develop.png&quot; alt=&quot;jenkins_blog_build&quot; /&gt;
&lt;img src=&quot;/assets/dev_site.png&quot; alt=&quot;dev_site&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;prod-deployment&quot;&gt;Prod deployment&lt;/h3&gt;

&lt;p&gt;To deploy to my webserver I need to FTP the site over, rsync won’t work for this.
On my webhost I have created an FTP user to send the site files.
I then need to add the FTP user credentials to Jenkins.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/ftp_jenk_cred.png&quot; alt=&quot;dev_site&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Finallly, within our Jenkinsfile, we need to reference the Jenkins credentials to FTP our site by the id we used when setting up the credentials: &lt;strong&gt;ftp_prod_blog&lt;/strong&gt;.
Using the withCredentials function, we can pass the username and password to the lftp command to mirror the local site to the remote webserver.&lt;/p&gt;

&lt;p&gt;Within the Jenkins file in our step for master branch deployment add the following:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;withCredentials([[$class: 'UsernamePasswordMultiBinding', credentialsId:'ftp_prod_blog', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD']]) {
					sh 'lftp -e &quot;mirror -R ./_site/ ~/&quot; -u $USERNAME,$PASSWORD &amp;lt;FTPSITE&amp;gt;:21'
				}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Hopefully as you are now reading this, the prod deployment was successful!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/master_prod.png&quot; alt=&quot;prod_site&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now my deployment is automated via Jenkins I no longer need to manually generate the static html files and FTP them to my host.&lt;/p&gt;</content><author><name></name></author><summary type="html">For this blog, I’m using Jekyll, a Ruby based static site generator that uses markup pages to generate static html pages.</summary></entry><entry><title type="html">Building a homelab</title><link href="http://localhost:4000/2019/02/07/building-a-homelab.html" rel="alternate" type="text/html" title="Building a homelab" /><published>2019-02-07T00:00:00+00:00</published><updated>2019-02-07T00:00:00+00:00</updated><id>http://localhost:4000/2019/02/07/building-a-homelab</id><content type="html" xml:base="http://localhost:4000/2019/02/07/building-a-homelab.html">&lt;p&gt;I wanted to set up a home lab for development, tinkering and learning. I got myself a HP Microgen 8 and upgraded it with some more ram and a better cpu.
In order to use it effectively and test multiple OSs and software, I wanted to set up virtualisation, for this I chose &lt;a href=&quot;https://www.proxmox.com/en/&quot;&gt;Proxmox&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/proxmox-dashboard.png&quot; alt=&quot;My Proxmox Homelab&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;server-hardware&quot;&gt;Server Hardware&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;HP Microserver Gen8&lt;/li&gt;
  &lt;li&gt;16GB (2x 8GB) DDR3 1600Mhz M391B1G73QH0-CK0Q 2Rx8 PC3-12800E&lt;/li&gt;
  &lt;li&gt;Intel Xeon E3-1265L 2.4GHz Quad Core CPU SR0G0 LGA1155 Gen8&lt;/li&gt;
  &lt;li&gt;4 x 2TB WD drives&lt;/li&gt;
  &lt;li&gt;1 x 120GB 2.5Inch hitachi drive&lt;/li&gt;
  &lt;li&gt;1 x 2GB MicroSD card&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;issues&quot;&gt;Issues&lt;/h2&gt;

&lt;h4 id=&quot;raid-problems&quot;&gt;RAID problems.&lt;/h4&gt;

&lt;p&gt;The first issue I ran into was the RAID card installed a HP B120i has spotty driver support in newer kernal versions in Debian, which Proxmox is based on. As such I had to disable the RAID card and and boot using AHCI rather than RAID.&lt;/p&gt;

&lt;p&gt;However, a caveat of the HP MicroGen 8 is while I had 4x4TB drives installed, I wanted to use the ODD port which is reserved normally for the Optical Disk Drive as the OS drive and does not &lt;strong&gt;support booting to in AHCI mode&lt;/strong&gt;. You can normally boot to the ODD sata port if in RAID mode.&lt;/p&gt;

&lt;p&gt;To solve this, I used the onboard MicroSD slot with a 2GB card to have the &lt;code class=&quot;highlighter-rouge&quot;&gt;/boot&lt;/code&gt; partition installed on it, including GRUB, and then boot to the MicroSD card slot which will point to the 120GB drive in the ODD sata port to load the OS.&lt;/p&gt;

&lt;h4 id=&quot;custom-partitions&quot;&gt;Custom partitions.&lt;/h4&gt;

&lt;p&gt;Unfortunatly Proxmox’s installer does not give you full control over partition creation to install the &lt;code class=&quot;highlighter-rouge&quot;&gt;/boot&lt;/code&gt; partition on the MicroSD card.&lt;/p&gt;

&lt;p&gt;To solve this, I used a standard Debian 9 installation and when prompted for parititons selected the MicroSD card as the &lt;code class=&quot;highlighter-rouge&quot;&gt;/boot&lt;/code&gt; partition and everything else went on the 120GB drive.&lt;/p&gt;

&lt;p&gt;Finally after the Debian installation complete I could &lt;a href=&quot;https://pve.proxmox.com/wiki/Install_Proxmox_VE_on_Debian_Stretch&quot;&gt;install Proxmox VE on top&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;raid-configuration&quot;&gt;RAID configuration&lt;/h2&gt;

&lt;p&gt;I will primarily be using this server for development, backups and media sharing. 
I settled on a RAID10 configuration, which strips a pair of disks and mirrors it to the other pair. This reduces the available diskspace by half, but the redundancy and performance is acceptable.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/480px-RAID_10_01.svg.png&quot; alt=&quot;RAID 10 - wikipedia&quot; /&gt;&lt;/p&gt;

&lt;p&gt;As I’m not using the HP RAID card, I settled on ZFS to create a software raid.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;root@alba:~# zpool status
  pool: lomond
 state: ONLINE
  scan: scrub repaired 0B in 4h27m with 0 errors on Sun Jan 13 04:52:01 2019
config:

        NAME                                          STATE     READ WRITE CKSUM
        lomond                                        ONLINE       0     0     0
          mirror-0                                    ONLINE       0     0     0
            ata-WDC_WD20EFRX-68AX9N0_WD-WMC1T3197358  ONLINE       0     0     0
            ata-WDC_WD20EFRX-68EUZN0_WD-WCC4M5XA9YJT  ONLINE       0     0     0
          mirror-1                                    ONLINE       0     0     0
            ata-WDC_WD20EFRX-68AX9N0_WD-WCC300355187  ONLINE       0     0     0
            ata-WDC_WD20EFRX-68AX9N0_WD-WCC300377214  ONLINE       0     0     0

errors: No known data errors

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Doing a quick benchmark of theoretical performance against a 20GB file, I get write speeds of 350 MB/s and read speeds of 7.4GB/s&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;root@alba:/lomond# dd if=/dev/zero of=tmp.dat bs=2048k count=10k
10240+0 records in
10240+0 records out
21474836480 bytes (21 GB, 20 GiB) copied, 61.2908 s, 350 MB/s
root@alba:/lomond# dd of=/dev/zero if=tmp.dat bs=2048k count=10k
10240+0 records in
10240+0 records out
21474836480 bytes (21 GB, 20 GiB) copied, 2.8936 s, 7.4 GB/s
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With the configuration of the RAID I can set up Proxmox to utilise it for VMs, containers, image storage and data storage.&lt;/p&gt;

&lt;p&gt;I’ll detail my Proxmox setup in another post.&lt;/p&gt;</content><author><name></name></author><summary type="html">I wanted to set up a home lab for development, tinkering and learning. I got myself a HP Microgen 8 and upgraded it with some more ram and a better cpu. In order to use it effectively and test multiple OSs and software, I wanted to set up virtualisation, for this I chose Proxmox</summary></entry><entry><title type="html">Finding Performance Bottlenecks in Games</title><link href="http://localhost:4000/2017/05/12/finding-performance-bottlenecks-in-games.html" rel="alternate" type="text/html" title="Finding Performance Bottlenecks in Games" /><published>2017-05-12T00:00:00+01:00</published><updated>2017-05-12T00:00:00+01:00</updated><id>http://localhost:4000/2017/05/12/finding-performance-bottlenecks-in-games</id><content type="html" xml:base="http://localhost:4000/2017/05/12/finding-performance-bottlenecks-in-games.html">&lt;p&gt;Too often we have got a new game and found performance is lacking. Sometimes it’s easy enough to turn down some settings but other times it feels like your PC is holding you back. Here I will show you how you can determine what your bottleneck is and how you could re-mediate it.&lt;/p&gt;

&lt;h2 id=&quot;initial-checks&quot;&gt;Initial checks&lt;/h2&gt;

&lt;p&gt;First things first, make sure all your drivers are updated correctly. You can visit your motherboard manufacturers website to download chipset, audio, SATA and bios updates.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Grab your Nvidia drivers from &lt;a href=&quot;http://www.nvidia.com/Download/index.aspx&quot;&gt;here&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Grab your AMD drivers from &lt;a href=&quot;https://www.amd.com/en/support&quot;&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There’s no point looking for hardware bottlenecks that are actually driver issues.&lt;/p&gt;

&lt;p&gt;In the case of GPUs, ensure you are gaming using your dedicated GPU and not the on board graphics.&lt;/p&gt;

&lt;h2 id=&quot;what-were-testing-and-why&quot;&gt;What were testing and why?&lt;/h2&gt;

&lt;p&gt;The four main components we will be looking at are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;CPU&lt;/li&gt;
  &lt;li&gt;GPU&lt;/li&gt;
  &lt;li&gt;RAM&lt;/li&gt;
  &lt;li&gt;Storage device&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each of these components will affect your performance directly. You could have the best GPU and CPU out but if your running the game off a USB 2.0 drive and the game streams in textures or models then you will find lots of “pop in” happening during game and and very long loading times.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/gamebottle/XF7hIdk.gif&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A common thing within our group is people have a great GPU and disk but only shell out for the absolute minimum CPU. What then happens is things like physics or AI which is computed mainly on the processor slows down the rest of the game. Not only that if the CPU can’t process commands quick enough to hand off data to the GPU it causes a bottleneck. Again if you don’t have enough RAM you’ll find your PC hitting your disk more often to load models/textures/sounds into RAM and using  swap space on the disk, this can cause FPS dips.&lt;/p&gt;

&lt;h2 id=&quot;how-to-test&quot;&gt;How to test&lt;/h2&gt;

&lt;p&gt;Now let’s find a game that you have problems with, to an extent we need to stress the PC under real world conditions to find the problem.&lt;/p&gt;

&lt;p&gt;For me I will be using GTA V, a game that looks pretty and can scale up well using some advanced graphics options that invariably tank my frame rate. The initial test will be turning everything to as high as I can until I start to get consistently less than 60fps.&lt;/p&gt;

&lt;p&gt;Next we need to download &lt;a href=&quot;http://www.guru3d.com/files-details/msi-afterburner-beta-download.html&quot;&gt;MSI Afterburner&lt;/a&gt; so we can see stats about our system during the game.&lt;/p&gt;

&lt;p&gt;Go ahead and install Afterburner and start it up and open the settings panel and click the Monitor tab. What we need to do now is go through the list of Graph metrics, GPU Usage, CPU Usage, Power, RAM Usage etc and include them in the onscreen display using the “Show in On-Screen Display” checkbox for each metric.
Afterburner settings&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/gamebottle/afterburner-settings.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now we can start up the game and see how our computers handling it. You can see in the image below from GTA V that my RAM usage is pretty high and my CPU usage is hovering around 65%, this isn’t too bad with these graphics settings. With the FPS around 40FPS, it is less than our ideal 60FPS but the GPU is doing all it can and the CPU isn’t being overly taxed. You can also see the RAM isn’t hitting its max 16GB yet.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/gamebottle/base.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;So overall here the initial bottleneck is my GPU as the system just can’t hit 60FPS. If I upgrade my GPU from a GTX 970 to something like a GTX 1080 and capped the framerate at 60FPS you may see the GPU usage dropping since it might not get maxed out, if my CPU could handle it that is.&lt;/p&gt;

&lt;h2 id=&quot;but-what-does-a-bottleneck-look-like&quot;&gt;But what does a bottleneck look like?&lt;/h2&gt;

&lt;p&gt;I have artificially impacted the components so you can see what their usage would look like if there was a bottleneck.&lt;/p&gt;

&lt;h1 id=&quot;disk&quot;&gt;Disk&lt;/h1&gt;

&lt;p&gt;I have GTA V installed three 2.5inch 5400RPM 1TB drives in RAID 0, purely for games. I know about RAID 0s lack of redundancy, don’t judge. While I’m playing GTA V to slow down my drive I ran Crystal Disk Mark to benchmark my disks while I’m playing. The result is that with the increased read latency and slower read speeds, the disk can’t keep up as I’m flying around and as such some of the textures don’t load in right away, highlighted in blue below.
&lt;img src=&quot;/assets/gamebottle/Slow-Disk-Pop-In-1024x577.png&quot; alt=&quot;&quot; /&gt;
Whats interesting to note is that the GPU, CPU and RAM usage don’t look much different in the afterburner overlay from my initial screenshot. The easiest way to see if your disk is running slow is to check Task Manager or Resource Monitor. You would see things like High Active time, a high average response time, below shows it as 5.4ms which is fine but if you see times of 500ms or more your disk may have a problem.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/gamebottle/disk2.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Resource monitor can give you more information about what is actually doing the reading and writing on the disk. Things to look out for again are a high disk queue length that is high for a sustained amount of time. If it jumps up to 5-10 for a second or two don’t worry, but if it stays like that for a few minutes the disk isn’t processing read or write requests fast enough to serve the applications. You can also see if any other applications are hitting the disk and causing slow downs, like downloading a game in the background or your antivirus doing a scan can impact disk performance.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/gamebottle/disk-1024x561.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;ram&quot;&gt;RAM&lt;/h1&gt;

&lt;p&gt;In order to consume a load of RAM, I opened up Photoshop and put a gradient on a 8K image, which ate up the rest of my 16GB RAM. The result is that because there is so little space in memory for the game to load files into, it resources to putting files on disk in the pagefile, which you can see has increased as well. The FPS has dropped considerably to 16FPS, the GPU usage has also dropped, probably because its trying to grab data from the disk instead of RAM which is taking a long time. If you didn’t meet the minimum specification of RAM or it was being used by other applications, this is the sort of stats you would see for a RAM bottleneck.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/gamebottle/RAM.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;gpu--cpu&quot;&gt;GPU &amp;amp; CPU&lt;/h1&gt;

&lt;p&gt;The GPU and CPU can affect each other and often one is the bottleneck for the other. You would see CPU utilisation as high and GPU utilisation low if you had a CPU bottleneck and you would see the opposite pattern for a GPU bottleneck.&lt;/p&gt;

&lt;p&gt;The CPU does a lot of the AI processing, physics and requests for data to be moved to RAM from disk. If your CPU couldn’t keep up with the requests it would have high usage, meanwhile the GPU is waiting around for data to be made available for it to process.However if your GPU isn’t all that powerful or had little VRAM it would take longer to process shaders, load textures and draw them. The CPU then doesn’t need to work as hard to serve the GPU up data to process.&lt;/p&gt;

&lt;p&gt;Turning on Dynamic Scale Resolution in GTA V renders the game at a higher resolution than my screen can display natively, which eats up GPU resources. The image below shows the high GPU usage and just about all of my 4GB of VRAM gone, but there is relatively average CPU utilisation. The FPS sits at 29FPS, the GPU is clearly the bottleneck in this situation.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/gamebottle/GPU-Scale.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;To hinder the CPU I ran a CPU stress test in the background, eating away at our precious cycles. The GPU can have all the power in the world, but if the CPU is to slow to process requests to move data to RAM of the GPU, it hinders performance and the FPS drops. When testing on my i5-4670k @ 4GHz running Prime95 on all cores, with 100% CPU usage, the FPS dropped down to 31FPS from our base of 40fps.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/gamebottle/cpu.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Hopefully this has been a useful tutorial on how to find and identify bottlenecks when gaming!&lt;/p&gt;</content><author><name></name></author><summary type="html">Too often we have got a new game and found performance is lacking. Sometimes it’s easy enough to turn down some settings but other times it feels like your PC is holding you back. Here I will show you how you can determine what your bottleneck is and how you could re-mediate it.</summary></entry><entry><title type="html">Micro Quadcopter Build</title><link href="http://localhost:4000/2017/05/05/micro-quadcopter-build.html" rel="alternate" type="text/html" title="Micro Quadcopter Build" /><published>2017-05-05T00:00:00+01:00</published><updated>2017-05-05T00:00:00+01:00</updated><id>http://localhost:4000/2017/05/05/micro-quadcopter-build</id><content type="html" xml:base="http://localhost:4000/2017/05/05/micro-quadcopter-build.html">&lt;p&gt;&lt;img src=&quot;/assets/microquadcopter/kit.jpg&quot; alt=&quot;kit&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;a-micro-quadcopter&quot;&gt;A Micro Quadcopter!&lt;/h2&gt;
&lt;p&gt;Outside of the usual gaming content, we have a brief quadcopter build . If you haven’t had a shot at one yet, I urge you to get a small one to get used to flying and just mess around with it! To get more practice flying quadcopters before I go back to my 250 quad, I got a &lt;a href=&quot;https://www.banggood.com/Eachine-E010-Frame-Beecore-F3-Flight-Controller-Chaoli-615-59000RPM-Motor-TX03-72CH-VTX-Camera-Set-p-1114191.html?p=S720069885032014123U&amp;quot;&quot;&gt;Eachine e010 “tiny whoop” clone&lt;/a&gt; kit from &lt;a href=&quot;https://www.banggood.com/?p=S720069885032014123U&quot;&gt;banggood.com&lt;/a&gt;. These tiny things are great for flying around the house and get some practice with the sticks.&lt;/p&gt;

&lt;p&gt;This kit has everything you need to build a tiny quad with FPV capability. The main parts are the frame, the propellers, the flight controller with built in transmitter, motors and a camera with a transmitter. But remember you need some batteries, make sure you get a few as you only get 3-4 minutes flight time for each one. I got this set of &lt;a href=&quot;https://www.banggood.com/5X-Charsoon-3_7V-220mAh-50C-Lipo-Battery-for-Blade-Inductrix-Tiny-Whoop-RC-Quadcopter-p-1118882.html?p=S720069885032014123U&quot;&gt;5 Charsoon 220mAh stick style batteries&lt;/a&gt; which have been working great.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/microquadcopter/batteries.jpg&quot; alt=&quot;batteries&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;what-else-do-you-need&quot;&gt;What else do you need?&lt;/h2&gt;
&lt;p&gt;You do need a few staple items for your quadcopter. It’s recommended to buy a decent controller, as you can use it with multiple aircraft. This is one of those things were you can spend a small amount of money and find your self needing to upgrade in the future or you can go all out and get something decent. I’ve got a Spectrum DX6i, which doesn’t appear to be available in retail anywhere, the next one up is the DX6e.&lt;/p&gt;

&lt;p&gt;If your going to be doing FPV (First Person View) you will need a receiver to receive the video feed coming from your camera and either a screen or headset. There are again a range of options here, you can spend as little as £40 or go all out at £300 plus. You can get headsets, like VR headsets that have built in receivers, or ones that are just screens and require a separate receiver. From Banggood again, I grabbed a quite decent FPV headset, the &lt;a href=&quot;href=&amp;quot;https://www.banggood.com/Eachine-EV800-5-Inches-800x480-FPV-Goggles-5_8G-40CH-Raceband-Auto-Searching-Build-In-Battery-p-1053357.html?p=S720069885032014123U&quot;&gt;Eachine EV800&lt;/a&gt; for £40.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/microquadcopter/fpv.jpg&quot; alt=&quot;fpv&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A decent &lt;a href=&quot;https://www.banggood.com/SKYRC-iMAX-B6AC-V2-Professional-Balance-ChargerDischarger-SK-100090-p-945684.html?p=S720069885032014123U&quot;&gt;lipo charger&lt;/a&gt; is required for safety reasons and so you can effectively charge your batteries and get the most out of them.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/microquadcopter/charger.jpg&quot; alt=&quot;charge&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;how-to-put-it-all-together&quot;&gt;How to put it all together?&lt;/h2&gt;
&lt;p&gt;The mini quads are really easy to build, the larger ones are a bit more complicated.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/microquadcopter/b1.jpg&quot; alt=&quot;build1&quot; /&gt;
&lt;img src=&quot;/assets/microquadcopter/b2.jpg&quot; alt=&quot;build2&quot; /&gt;&lt;/p&gt;

&lt;p&gt;For this kit however:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The four motors slot into the frame.&lt;/li&gt;
  &lt;li&gt;They are then plugged into the flight controller.&lt;/li&gt;
  &lt;li&gt;I soldered the FPV camera power wires onto the flight controller.&lt;/li&gt;
  &lt;li&gt;Stick the FPV camera onto the flight controller with some double sided foam or use a mount.&lt;/li&gt;
  &lt;li&gt;Then you screw the flight controller to the frame.&lt;/li&gt;
  &lt;li&gt;Once you’ve tested it you can finally put your props on, it’s just good practice especially with larger copters!&lt;/li&gt;
  &lt;li&gt;I also replaced the circular polarised antenna on the camera with a linear antenna that is less likely to break.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After flying this little thing for a couple of weeks, dinking off the walls, myself and scaring the cat, the frame cracked. Gluing it back together with some model glue worked for a while, but in the end I bought a the new E010s frame which is lighter, and makes the whole thing feel more zippy.  I will cover it in a review later.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/microquadcopter/b3.jpg&quot; alt=&quot;build3&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;now-what&quot;&gt;Now what?&lt;/h2&gt;
&lt;p&gt;Get flying! Get experience using the controller, its a bit different to the usual Xbox or PS4 controllers us gamers are used to. Don’t be afraid to crash, but be careful at the same time. The larger quads can be pretty dangerous if handled incorrectly, thats why I would recommend starting off with a smaller one you can fly indoors and not damage yourself or anything else with.&lt;/p&gt;

&lt;p&gt;I’ve  also designed a microquad t-shirt! You can buy it &lt;a href=&quot;https://www.redbubble.com/people/wullyr/works/26280833-mini-fpv-quadcopter&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you like the design and would like to see more hit me up on twitter @WullyRobb
&lt;img src=&quot;/assets/microquadcopter/quadtee.png&quot; alt=&quot;quadtee&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Happy flying!&lt;/p&gt;</content><author><name></name></author><summary type="html">A Micro Quadcopter! Outside of the usual gaming content, we have a brief quadcopter build . If you haven’t had a shot at one yet, I urge you to get a small one to get used to flying and just mess around with it! To get more practice flying quadcopters before I go back to my 250 quad, I got a Eachine e010 “tiny whoop” clone kit from banggood.com. These tiny things are great for flying around the house and get some practice with the sticks.</summary></entry><entry><title type="html">Tile Based Map Generation with SabreCSG</title><link href="http://localhost:4000/2017/02/19/tile-based-map-generation-with-sabrecsg.html" rel="alternate" type="text/html" title="Tile Based Map Generation with SabreCSG" /><published>2017-02-19T00:00:00+00:00</published><updated>2017-02-19T00:00:00+00:00</updated><id>http://localhost:4000/2017/02/19/tile-based-map-generation-with-sabrecsg</id><content type="html" xml:base="http://localhost:4000/2017/02/19/tile-based-map-generation-with-sabrecsg.html">&lt;p&gt;Now that i’m finished with my &lt;a href=&quot;/2017/02/07/metaballs-in-unity.html&quot;&gt;metaballs implementation&lt;/a&gt; I’ve started working on creating map assets and building out test levels for my game. Since I’m creating this myself I tried to find a tool or asset pack that could help me speed up the creation of the tile assets for the map.&lt;/p&gt;

&lt;p&gt;To keep things easy and reusable I decided the level design would be a 3D tile based.&lt;/p&gt;

&lt;p&gt;So I needed to find something that could:&lt;/p&gt;
&lt;ul&gt;
 	&lt;li&gt;Create tile based models&lt;/li&gt;
 	&lt;li&gt;Do per face texturing&lt;/li&gt;
 	&lt;li&gt;Create reusable components&lt;/li&gt;
 	&lt;li&gt;Easy to learn&lt;/li&gt;
 	&lt;li&gt;Free - if possible&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt; &lt;/p&gt;

&lt;p&gt;A brush based tool like Valves Hammer from the Source Engine seems like an easy way to build out a map. I had seen ProBuilder and ProBuilder free, but I didn’t really want to be tied to a free package that might be missing features I need down the line and force me to purchase the full version.&lt;/p&gt;

&lt;p&gt;I found &lt;a href=&quot;http://sabrecsg.com/&quot;&gt;SabreCSG&lt;/a&gt;, a brush based asset that is completely free, I didn’t get around to even testing ProBuilder free because Sabre seems to do the job for me.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;
&lt;h3&gt;Tile Models&lt;/h3&gt;
&lt;p&gt;The creation of models was pretty easy with SabreCSG, my only issue I had was with some of the weird rotations the system puts on brushes when you extrude or split them, which caused issues with my procedural generation.&lt;/p&gt;

&lt;p&gt;Once I figured out a scale that would fit the player on one tile I started building out some prototype blocks that I will be using in my maps.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/sabrecsg/prototypeModels.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;
&lt;h2&gt;Map Generation&lt;/h2&gt;
&lt;p&gt;As great as tools like probuilder and SabreCSG are for building models quickly, I wanted to have some rapid prototyping of levels. The easiest way I could implement this was to create a prefab out of each of the models I created above, then use Excel to layout my map by specifying which ID should be used in each cell, along with its Y axis Euler rotation, then iterate through the CSV file and spawn the prefabs in the correct locations.&lt;/p&gt;

&lt;p&gt;Using the Unity resources folder, I put all my prefab models in a folder called Tiles and ensured I labeled my tiles with IDs so when the resource folder was loaded into an array, all of my tiles would be in the correct position in the array.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/sabrecsg/tiles-1024x166.png&quot; alt=&quot;&quot; /&gt;
The excel file just contains the ID and the Y axis Rotation in a cell, separated by a space.
&lt;img src=&quot;/assets/sabrecsg/csv.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The magic happens in an Editor script I wrote which reads the CSV file and spawns the prefabs. It is attached to the CSGModel gameobject so the prefabs are spawned under it and become brushes. The only thing the script doesn’t do yet is clear out any existing prefabs, so if you want to make big changes, its easy enough to delete everything under the CSGModel object and generate the map again.&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MapGenerator : MonoBehaviour {

    public GameObject CSGModel;
    public GameObject[] myTiles;
    public TextAsset[] myLevels;
    public int tileSize = 3;
    public int levelId;

    private TextAsset csvFile;

    private int levelHeight;
    private int levelWidth;
    private string[,,] level; //row/column/cell information, contains (id,y) where y is rotation.

    public void GetResources()
    {
        //Get the list of tiles and put them into the array
        myTiles = Resources.LoadAll&amp;amp;lt;GameObject&amp;amp;gt;(&quot;Tiles&quot;);

        //Get the lsit of files and put them into the array
        myLevels = Resources.LoadAll&amp;amp;lt;TextAsset&amp;amp;gt;(&quot;Levels&quot;);
    }

    public void LoadLevel()
    {
        //read the csv file from the levels array into an array

        TextAsset csvFile = myLevels[levelId]; //loads the level

        string levelData = csvFile.text.Replace(&quot;\r\n&quot;,&quot;/&quot;); //save the level as a string, replacing the new lines with dashes
        
        string[] levelRows = levelData.Split('/');

        //Instantiate our level array with 
        levelHeight = levelRows.Length-1; //last line is always blank
        levelWidth = levelRows[0].Split(',').Length; //split out the first row to get the width.
        level = new string[levelHeight, levelWidth, 4];
  
        for(int h = 0; h &amp;amp;lt; levelHeight; h++)
        {
            string[] rowColumn = levelRows[h].Split(','); // split out the column

            for (int w = 0; w &amp;amp;lt; levelWidth; w++)
            {
                string[] cell = rowColumn[w].Split(' '); // split out the data

                level[(levelHeight - 1) - h, w, 0] = cell[0];
                level[(levelHeight - 1) - h, w, 1] = cell[1];

            }
        }
    }

    public void GenerateMap()
    {

        //read the csv file array and spawn prefabs
        Vector3 position = Vector3.zero;
        Vector3 rotation = Vector3.zero;
        int tileid = -1;
        position.y = 0f;

        for (int h = 0; h &amp;amp;lt; levelHeight; h++)
        {

            for (int w = 0; w &amp;amp;lt; levelWidth; w++)
            {
                position.x = w * tileSize + (tileSize);
                position.z = h * tileSize + (tileSize);
                tileid = int.Parse(level[h, w, 0]);
                if(tileid &amp;amp;gt; myTiles.Length-1)
                {
                    Debug.Log(&quot;missing tile= &quot; + tileid + &quot; reverting to tile ID 0&quot;);
                    tileid = 0;
                }
                rotation.x = 0;
                rotation.y = float.Parse(level[h, w, 1]);
                rotation.z = 0;

                if(tileid &amp;amp;gt;= 0)
                    Instantiate(myTiles[tileid], position, Quaternion.Euler(rotation), CSGModel.transform);
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To call the above functions, I made an Editor script to run them from the Editor. If you haven’t created any Editor scripts yet, you should! They’re so helpful and speed things up.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/sabrecsg/editorGenerator.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;using UnityEditor;

[CustomEditor(typeof(MapGenerator))]
public class MapGeneratorEditor : Editor
{
   

    public override void OnInspectorGUI()
    {
        MapGenerator mapGen = (MapGenerator)target;
        DrawDefaultInspector();

        if (GUILayout.Button(&quot;Get Tiles&quot;))
        {
            mapGen.GetResources();
        }

        if (GUILayout.Button(&quot;Load Level&quot;))
        {
            mapGen.LoadLevel();
        }

        if (GUILayout.Button(&quot;Generate Map&quot;))
        {
            mapGen.GenerateMap();
        }

    }

}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now I can generate some test levels quickly!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/sabrecsg/level.png&quot; alt=&quot;&quot; /&gt;
 &lt;/p&gt;</content><author><name></name></author><summary type="html">Now that i’m finished with my metaballs implementation I’ve started working on creating map assets and building out test levels for my game. Since I’m creating this myself I tried to find a tool or asset pack that could help me speed up the creation of the tile assets for the map.</summary></entry><entry><title type="html">Metaballs in Unity</title><link href="http://localhost:4000/2017/02/07/metaballs-in-unity.html" rel="alternate" type="text/html" title="Metaballs in Unity" /><published>2017-02-07T00:00:00+00:00</published><updated>2017-02-07T00:00:00+00:00</updated><id>http://localhost:4000/2017/02/07/metaballs-in-unity</id><content type="html" xml:base="http://localhost:4000/2017/02/07/metaballs-in-unity.html">&lt;p&gt;&lt;img src=&quot;https://thumbs.gfycat.com/ScaryDependableDodo-size_restricted.gif&quot; alt=&quot;Metaballs&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I’ve recently been getting into Unity to see if I could make a little basic game. My first idea has taken me down the road of procedurally generating meshes for objects in Unity . One method of doing this is creating an Isosurface using various algorithms. In my case I was trying to create Metaballs.&lt;/p&gt;

&lt;p&gt;Metaballs are points in space, which exert a “force” which decreases the further you get away from it. Where this “force” hits 0 is where the surface is drawn.
When multiple metaballs are close to each other, the force they exert on a point will be greater than a single metaball alone. And so it appears the surface of the metaballs grow towards each other like in the demo above.&lt;/p&gt;
&lt;h3 id=&quot;marching-cubes&quot;&gt;Marching cubes&lt;/h3&gt;
&lt;p&gt;An algorithm used to draw the mesh is Marching cubes. After initially looking at the example script from &lt;a href=&quot;http://wiki.unity3d.com/index.php?title=MetaBalls&quot;&gt;Unity3d community&lt;/a&gt; I thought I was a bit out of my depth, but I soon got it working and was creating blobby objects.&lt;/p&gt;

&lt;p&gt;There is plenty of material online regarding how marching cubes work and how you create a isosurface from a series of points within a 3D grid.  &lt;a href=&quot;http://paulbourke.net/geometry/polygonise/&quot;&gt;Paul Bourke’s article&lt;/a&gt; helped immensely.&lt;/p&gt;

&lt;p&gt;The performance impact increases vastly as the number of metaballs increase, as it requires traversing the full 3D grid each time to see if it was in range of the metaballs radius.&lt;/p&gt;

&lt;h3 id=&quot;reducing-grid-computation&quot;&gt;Reducing grid computation&lt;/h3&gt;
&lt;p&gt;One way to increase performance was to decrease the number of points that needed to be computed to find where the metaballs surface should be. A simple implementation will iterate through the full grid.&lt;/p&gt;

&lt;p&gt;However, we compute which of the 8 vertices of the voxel the metaball surface should intersect as per Marching Cubes. Using some fancy lookup tables we can then choose a direction to compute next based on which vertices were intersected.
Effectively this allows us to only compute the voxels which contains the surface of the metaball. Rather than all of the other voxels which are empty 90% of the time!&lt;/p&gt;

&lt;h3 id=&quot;surface-nets&quot;&gt;Surface Nets&lt;/h3&gt;
&lt;p&gt;In the past few months I tried to build in an alternative meshing method which uses Naive Surface Nets rather than the traditional meshing done by Marching Cubes. I managed to get it working, based on the work in &lt;a href=&quot;https://0fps.net/2012/07/12/smooth-voxel-terrain-part-2/&quot;&gt;Mikola Lysenko’s blog&lt;/a&gt;. This meant I could march across the same points, but generate fewer vertices and faces for the mesh, hopefully increasing performance.
I also encountered some weird bugs during my learning like the below.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://thumbs.gfycat.com/FarflungNextBobolink-size_restricted.gif&quot; alt=&quot;Bad meshing&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;metaballs&quot;&gt;Metaballs!&lt;/h3&gt;
&lt;p&gt;Finally I have managed to optimise my metaballs algorithm to create a decent amount of metaballs and generate a mesh at a good resolution that it doesn’t look too blocky.
There are much faster ways to do what I have done using the GPU through a compute shader. However since I am targeting android with my little game, I need to do it on CPU until our mobile GPUs catch up with desktops.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://thumbs.gfycat.com/BoldUnhappyDodo-size_restricted.gif&quot; alt=&quot;Optimised&quot; /&gt;&lt;/p&gt;</content><author><name></name></author><summary type="html"></summary></entry></feed>