<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>stafford williams</title>
    <description>spacetraders-v2 dev</description>
    <link>https://staffordwilliams.com/dev/</link>
    <pubDate>Sun, 01 Nov 2026 10:13:19 GMT</pubDate>
    <lastBuildDate>Sun, 01 Nov 2026 10:13:19 GMT</lastBuildDate>
    <generator>Astro</generator>
    <item>
      <title>spacetraders-v2: More data browser</title>
      <description>&lt;p&gt;&amp;lt;h2 id=&amp;quot;v2-14&amp;quot;&amp;gt;&amp;lt;time datetime=&amp;quot;2024-05-29&amp;quot;&amp;gt;May 29&amp;lt;/time&amp;gt; more data browser &amp;lt;span&amp;gt;v2.14&amp;lt;/span&amp;gt;&amp;lt;/h2&amp;gt;&lt;/p&gt;&lt;p&gt;I&apos;ve continued down the &lt;a href=&quot;/spacetraders&quot;&gt;data browser&lt;/a&gt; rabbit hole and still have not yet built the pathing visualisation which was the purpose of its creation.&lt;/p&gt;&lt;p&gt;&amp;lt;figure style=&apos;text-align: center; font-style: italic;&apos;&amp;gt; &amp;lt;img src=&amp;quot;/assets/spacetraders/data-browser-market.png&amp;quot; alt=&amp;quot;spacetraders data browser - market screenshot&amp;quot;/&amp;gt; &amp;lt;figcaption&amp;gt;spacetraders &amp;lt;a href=&apos;/spacetraders&apos;&amp;gt;data browser&amp;lt;/a&amp;gt; - market&amp;lt;/figcaption&amp;gt; &amp;lt;/figure&amp;gt;&lt;/p&gt;&lt;p&gt;Instead, I&apos;ve built out most of the ship and system waypoint views and surfaced a good chunk of the api data. Considering most of the api calls are very similar, I was able to create a few components that can be reused across the different views.&lt;/p&gt;&lt;p&gt;All API calls the data browser makes are via async &lt;a href=&quot;https://jotai.org/&quot;&gt;jotai atoms&lt;/a&gt;. Most of them use &lt;a href=&quot;https://jotai.org/docs/utilities/async#loadable&quot;&gt;loadable&lt;/a&gt; and so I wrote &lt;a href=&quot;https://github.com/staff0rd/spacetraders-again/blob/e8b9f1fb66cc7827ce9e36b79010786e43686a02/web/src/shared/RenderLoadableAtom.tsx&quot;&gt;RenderLoadableAtom&lt;/a&gt; to take care of the loading, error and success states of components that display that data.&lt;/p&gt;&lt;p&gt;All of the actual calls these atoms make are via the same &lt;a href=&quot;https://github.com/staff0rd/spacetraders-again/blob/e8b9f1fb66cc7827ce9e36b79010786e43686a02/src/apiFactory.ts&quot;&gt;api factory&lt;/a&gt; I wrote over the generated openapi output. This factory wraps every call with &lt;a href=&quot;https://www.npmjs.com/package/bottleneck&quot;&gt;bottleneck&lt;/a&gt; to globally rate limit any call and &lt;a href=&quot;https://caolan.github.io/async/v3/docs.html#retryable&quot;&gt;retryable from the async library&lt;/a&gt; to handle and retry any 429s. This allows logic in both &lt;a href=&quot;https://github.com/staff0rd/spacetraders-again&quot;&gt;my automated backend&lt;/a&gt; and the standalone &lt;a href=&quot;https://github.com/staff0rd/spacetraders-again/tree/main/web&quot;&gt;data browser&lt;/a&gt; to make requests without needing to worry about rate limiting or retries.&lt;/p&gt;&lt;p&gt;&amp;lt;figure style=&apos;text-align: center; font-style: italic;&apos;&amp;gt; &amp;lt;img src=&amp;quot;/assets/spacetraders/data-browser-ship.png&amp;quot; alt=&amp;quot;spacetraders data browser - ship screenshot&amp;quot;/&amp;gt; &amp;lt;figcaption&amp;gt;spacetraders &amp;lt;a href=&apos;/spacetraders&apos;&amp;gt;data browser&amp;lt;/a&amp;gt; - ship&amp;lt;/figcaption&amp;gt; &amp;lt;/figure&amp;gt;&lt;/p&gt;&lt;p&gt;Finally, I added a &lt;a href=&quot;https://github.com/staff0rd/spacetraders-again/blob/e8b9f1fb66cc7827ce9e36b79010786e43686a02/web/src/shared/TabStructure.tsx&quot;&gt;TabStructure component&lt;/a&gt; to split data returned by endpoints into tabs and hooked it into &lt;a href=&quot;https://github.com/staff0rd/spacetraders-again/blob/e8b9f1fb66cc7827ce9e36b79010786e43686a02/web/src/router.tsx&quot;&gt;react router&lt;/a&gt;. This component is also dependent on a loadable atom and includes an automatically appended &lt;a href=&quot;https://github.com/staff0rd/spacetraders-again/blob/e8b9f1fb66cc7827ce9e36b79010786e43686a02/web/src/shared/Raw.tsx&quot;&gt;Raw&lt;/a&gt; tab which displays the raw json returned by the api - this comes in handy when viewing data that hasn&apos;t been bound to a component yet.&lt;/p&gt;&lt;p&gt;With easy data access and a reusable component pattern I&apos;ve ended up spending too much time building it out rather than focusing on the path visualisation which will be my next task.&lt;/p&gt;</description>
      <pubDate>Wed, 29 May 2024 00:00:00 GMT</pubDate>
      <link>https://staffordwilliams.com/dev/spacetraders-v2/2024-w22/</link>
      <guid isPermaLink="true">https://staffordwilliams.com/dev/spacetraders-v2/2024-w22/</guid>
      <category>spacetraders-v2</category>
    </item>
    <item>
      <title>spacetraders-v2: Data browser</title>
      <description>&lt;p&gt;&amp;lt;h2 id=&amp;quot;v2-13&amp;quot;&amp;gt;&amp;lt;time datetime=&amp;quot;2024-05-16&amp;quot;&amp;gt;May 16&amp;lt;/time&amp;gt; data browser &amp;lt;span&amp;gt;v2.13&amp;lt;/span&amp;gt;&amp;lt;/h2&amp;gt;&lt;/p&gt;&lt;p&gt;My ship pathfinding is not working great and my command ship (and haulers) are constantly flying to locations without fuel and then spending a bunch of time drifting to the next location. Trying to visualise pathing (and eventually supply chains) in Grafana is proving too difficult with the format Grafana expects things to be in, so, I decided to build a front-end data browser to help understand what is going on.&lt;/p&gt;&lt;p&gt;&amp;lt;figure style=&apos;text-align: center; font-style: italic;&apos;&amp;gt; &amp;lt;img src=&amp;quot;/assets/spacetraders/data-browser.png&amp;quot; alt=&amp;quot;spacetraders data browser&amp;quot;/&amp;gt; &amp;lt;figcaption&amp;gt;spacetraders &amp;lt;a href=&apos;/spacetraders&apos;&amp;gt;data browser&amp;lt;/a&amp;gt;&amp;lt;/figcaption&amp;gt; &amp;lt;/figure&amp;gt;&lt;/p&gt;&lt;p&gt;This ended up turning into a rabbit hole that saw the creation of &lt;a href=&quot;/spacetraders&quot;&gt;this data browsing tool&lt;/a&gt; which so far does not visualise pathing or supply chains, but is proving handy to surface and explore data from my existing api code. Eventually I intend to build out mapping and pathfinding functionality into the tool.&lt;/p&gt;</description>
      <pubDate>Thu, 16 May 2024 00:00:00 GMT</pubDate>
      <link>https://staffordwilliams.com/dev/spacetraders-v2/2024-w20/</link>
      <guid isPermaLink="true">https://staffordwilliams.com/dev/spacetraders-v2/2024-w20/</guid>
      <category>spacetraders-v2</category>
    </item>
    <item>
      <title>spacetraders-v2: Reset 2024-04-09</title>
      <description>&lt;p&gt;&amp;lt;h2 id=&amp;quot;v2-12&amp;quot;&amp;gt;&amp;lt;time datetime=&amp;quot;2024-05-04&amp;quot;&amp;gt;May 4&amp;lt;/time&amp;gt; reset 2024-04-09 &amp;lt;span&amp;gt;v2.12&amp;lt;/span&amp;gt;&amp;lt;/h2&amp;gt;&lt;/p&gt;&lt;p&gt;SpaceTraders resets every ~2 weeks with all players required to re-register their agents and start from scratch. The end of reset 2024-04-09 saw my agent finish up just under 12 million which was enough to have it appear on the leaderboard, no where near the top as I continue to implement basic systems.&lt;/p&gt;&lt;p&gt;&amp;lt;figure style=&apos;text-align: center; font-style: italic;&apos;&amp;gt; &amp;lt;img src=&amp;quot;/assets/spacetraders/2024-04-09-leaderboard.png&amp;quot; alt=&amp;quot;2024-04-09 Most Credits leaderboard&amp;quot;/&amp;gt; &amp;lt;figcaption&amp;gt;Screenshot from &amp;lt;a href=&amp;quot;https://flwi-spacetraders-leaderboard-crimson-waterfall-7968.fly.dev/&amp;quot;&amp;gt;FloWi&apos;s Leaderboard app&amp;lt;/a&amp;gt;&amp;lt;/figcaption&amp;gt; &amp;lt;/figure&amp;gt;&lt;/p&gt;&lt;p&gt;Now that I am &lt;a href=&quot;/devlog/spacetraders-v2/v2.11/&quot;&gt;monitoring markets&lt;/a&gt; I&apos;ve implemented trading where ships will attempt to buy low and sell high. This reset has lasted more than the expected couple of weeks however and other agents in my starter system have already contributed to market prices being less profitable.&lt;/p&gt;&lt;p&gt;The leader in most credits for the reset was &lt;code&gt;whyando - Justin&lt;/code&gt; and &lt;a href=&quot;https://discord.com/channels/792864705139048469/792864705139048472/1231875080355840021&quot;&gt;they shared an excellent overview of their approach on discord&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;!&lt;a href=&quot;/assets/spacetraders/reset-2024-04-09.png&quot;&gt;most credits - reset 2024-04-09&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Off the back of this I&apos;ve started to explore the supply/demand mechanics myself and saw the price of &lt;code&gt;EXPORT IRON&lt;/code&gt; drop as I supplied the same waypoint with its &lt;code&gt;IMPORT IRON_ORE&lt;/code&gt;. I implemented &lt;a href=&quot;https://github.com/staff0rd/spacetraders-again/commit/61eb9e452bff5f9e92f905a417d023d43746735b&quot;&gt;surveyor logic&lt;/a&gt; to facilitate improved extraction, but noticed that the price and trade volumes change over time gradually so I&apos;ll need to limit my logic for over-supply.&lt;/p&gt;&lt;p&gt;!&lt;a href=&quot;/assets/spacetraders/iron-ore-supply.png&quot;&gt;iron ore supply&lt;/a&gt;&lt;/p&gt;</description>
      <pubDate>Sat, 04 May 2024 00:00:00 GMT</pubDate>
      <link>https://staffordwilliams.com/dev/spacetraders-v2/2024-w18/</link>
      <guid isPermaLink="true">https://staffordwilliams.com/dev/spacetraders-v2/2024-w18/</guid>
      <category>spacetraders-v2</category>
    </item>
    <item>
      <title>spacetraders-v2: Trading contracts, monitoring markets</title>
      <description>&lt;p&gt;&amp;lt;h2 id=&amp;quot;v2-10&amp;quot;&amp;gt;&amp;lt;time datetime=&amp;quot;2024-04-18&amp;quot;&amp;gt;Apr 18&amp;lt;/time&amp;gt; trading contracts &amp;lt;span&amp;gt;v2.10&amp;lt;/span&amp;gt;&amp;lt;/h2&amp;gt;&lt;/p&gt;&lt;p&gt;With my hourly income going into the negatives due to bottoming out the price of ore, I&apos;ve spent some time implementing a trading approach for the command ship so I can complete contracts that require trade goods. This required at least a lap of the markets in the system to probe the price details of each trade good. This recon went well until the final waypoint that appeared to have a market but no fuel - the ship promptly ran out of gas and I had to write code to drift to the closest waypoint with a fuel supply.  After the recon was complete, contract trading appeared to work until the ship got stuck in a loop between waypoints.&lt;/p&gt;&lt;p&gt;On investigation it appeared the current contract required the ship to move through a distant waypoint that expended most of the fuel, and had no fuel supply. Drifting back to the nearest waypoint with fuel available executed correctly, but then the logic would push the ship back through the same distant waypoint and the cycle would repeat. I&apos;ll need to update the navigation logic to be aware of fuel requirements and availability so the ship can buy extra fuel and store it in cargo should a route require it.&lt;/p&gt;&lt;p&gt;To help with this, I&apos;ve added a Grafana panel that allows me to visualise the layout of waypoints in the system. I was unable to find a cartesian plane or similar visualisation in Grafana, so instead i&apos;ve hacked the Geomap visualisation to achieve this. I&apos;ve chosen an empty point in the ocean, zoomed in as far as it&apos;ll go, and used that point as the origin. I&apos;ve then plotted the waypoints of the system as offsets from this origin. Perhaps in the future I&apos;ll add ship position to this panel.&lt;/p&gt;&lt;p&gt;!&lt;a href=&quot;/assets/spacetraders/waypoint-layout.png&quot;&gt;waypoint layout&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;lt;h2 id=&amp;quot;v2-11&amp;quot;&amp;gt;&amp;lt;time datetime=&amp;quot;2024-04-21&amp;quot;&amp;gt;Apr 21&amp;lt;/time&amp;gt; monitoring markets &amp;lt;span&amp;gt;v2.11&amp;lt;/span&amp;gt;&amp;lt;/h2&amp;gt;&lt;/p&gt;&lt;p&gt;Contracts have proved profitable enough to get me onto the leaderboard, though there&apos;s still a few problems.&lt;/p&gt;&lt;p&gt;&amp;lt;figure style=&apos;text-align: center; font-style: italic;&apos;&amp;gt; &amp;lt;img src=&amp;quot;/assets/spacetraders/leaderboard.png&amp;quot; alt=&amp;quot;leaderboard&amp;quot;/&amp;gt; &amp;lt;figcaption&amp;gt;leaderboard&amp;lt;/figcaption&amp;gt; &amp;lt;/figure&amp;gt;&lt;/p&gt;&lt;p&gt;There were still a few routing issues that mean the ship was flying through areas with no fuel. I was able to pull the routing code from my &lt;a href=&quot;https://github.com/staff0rd/spacetraders&quot;&gt;earlier work for v1&lt;/a&gt; and adapt it for v2 so the ship is now less likely to to navigate through areas without fuel. This still happens when there is no direct route however, and I still need to write code to buy fuel and store it in cargo to reduce the amount of legs the ship needs to drift&lt;/p&gt;&lt;p&gt;Additionally, there was at least one contract where the earnings were negative - for now I&apos;ll just wear this cost but there could be opportunities to source the goods cheaper in other systems or via refining.&lt;/p&gt;&lt;p&gt;Now that contracting is working, I&apos;ll need to start using the data collected from markets to increase profits by trading goods. I&apos;ve built another Grafana dashboard to help monitor market goods and prices, and, I&apos;ve implemented code to buy and navigate satellites to market waypoints to monitor prices.&lt;/p&gt;&lt;p&gt;&amp;lt;figure style=&apos;text-align: center; font-style: italic;&apos;&amp;gt; &amp;lt;img src=&amp;quot;/assets/spacetraders/market-dashboard.png&amp;quot; alt=&amp;quot;market dashboard&amp;quot;/&amp;gt; &amp;lt;figcaption&amp;gt;market dashboard&amp;lt;/figcaption&amp;gt; &amp;lt;/figure&amp;gt;&lt;/p&gt;</description>
      <pubDate>Sun, 21 Apr 2024 00:00:00 GMT</pubDate>
      <link>https://staffordwilliams.com/dev/spacetraders-v2/2024-w16/</link>
      <guid isPermaLink="true">https://staffordwilliams.com/dev/spacetraders-v2/2024-w16/</guid>
      <category>spacetraders-v2</category>
    </item>
    <item>
      <title>spacetraders-v2: Increased mining, over supply, waypoint monitoring</title>
      <description>&lt;p&gt;&amp;lt;h2 id=&amp;quot;v2-7&amp;quot;&amp;gt;&amp;lt;time datetime=&amp;quot;2024-03-26&amp;quot;&amp;gt;Mar 26&amp;lt;/time&amp;gt; increased mining activity &amp;lt;span&amp;gt;v2.7&amp;lt;/span&amp;gt;&amp;lt;/h2&amp;gt;&lt;/p&gt;&lt;p&gt;After purchasing a &lt;code&gt;SHIP_LIGHT_SHUTTLE&lt;/code&gt; to transport mining results from the mining drones to their import markets I found that the round trip was too long and mining drones were filling up their cargo holds before the shuttle has delivered all the goods and returned. The immediate resolution for this was to jettison non-ore results, meaning the shuttle needs ferry between the asteroid and a single market. After automating the shuttle I realised my command ship also has similar cargo space so the same shuttle logic could be applied to it when it&apos;s not otherwise doing anything.&lt;/p&gt;&lt;p&gt;The big drops in Credits/hour below represent the automation buying new ships.&lt;/p&gt;&lt;p&gt;!&lt;a href=&quot;/assets/spacetraders/increased-mining.png&quot;&gt;increased mining activity&lt;/a&gt;&lt;/p&gt;&lt;p&gt;With increased mining I&apos;m seeing a slow decrease in Credits/hour which I presume is the result of constant selling ore. I can confirm this once i&apos;ve implemented some improved market monitoring, though I also want to see what effect &lt;code&gt;SHIP_SURVEYOR&lt;/code&gt; can have on my mining operations.&lt;/p&gt;&lt;p&gt;&amp;lt;h2 id=&amp;quot;v2-8&amp;quot;&amp;gt;&amp;lt;time datetime=&amp;quot;2024-03-28&amp;quot;&amp;gt;Mar 28&amp;lt;/time&amp;gt; over supply &amp;lt;span&amp;gt;v2.8&amp;lt;/span&amp;gt;&amp;lt;/h2&amp;gt;&lt;/p&gt;&lt;p&gt;The shuttle logic was modular enough that it was &lt;a href=&quot;https://github.com/staff0rd/spacetraders-again/commit/d8f64aef88fa2ae09ab5b3985596fad166b3c6a3&quot;&gt;trival to refer the command ship to it&lt;/a&gt; should the command ship have already performed its logic. Turns out the command ship has a much larger engine and with 10x the speed I needed more mining probes to keep the transports busy. The result of this was a plummeting ore price as I over-supplied the market.&lt;/p&gt;&lt;p&gt;!&lt;a href=&quot;/assets/spacetraders/over-supply.png&quot;&gt;increased mining activity&lt;/a&gt;&lt;/p&gt;&lt;p&gt;I do not know at this stage what causes the price to bounce back.&lt;/p&gt;&lt;p&gt;My grafana dashboards are becoming complex, and I need to implement some kind of backup/restore for them - to de-risk this in the short-term I&apos;ve started to commit my more &lt;a href=&quot;https://github.com/staff0rd/spacetraders-again/commit/d0ae044f78fa343d2e7f9d71170d06a14eb3aadd&quot;&gt;complex queries as views&lt;/a&gt; to the database.&lt;/p&gt;&lt;p&gt;&amp;lt;h2 id=&amp;quot;v2-9&amp;quot;&amp;gt;&amp;lt;time datetime=&amp;quot;2024-03-31&amp;quot;&amp;gt;Mar 31&amp;lt;/time&amp;gt; improved waypoint monitoring &amp;lt;span&amp;gt;v2.9&amp;lt;/span&amp;gt;&amp;lt;/h2&amp;gt;&lt;/p&gt;&lt;p&gt;Increasing the mining drone count to 20 eventually caused the price of all ore in the system to bottom out and I had to stop the automation as it was slowly losing credits. I&apos;ll need to improve how I monitor the market across waypoints so I&apos;ve added &lt;a href=&quot;https://github.com/staff0rd/spacetraders-again/commit/ad6c13e6edb74c905ec37f08f2dcc9f261fa3aef&quot;&gt;a bunch of code to do this&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;!&lt;a href=&quot;/assets/spacetraders/bottomed-out-ore.png&quot;&gt;price of ore drops to one&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Ultimately i&apos;ll use probes to periodically check each waypoint, but I need to write the probe automation to do this. I&apos;ll have to purchase probes over time and slowly send them out across the system, starting with the waypoints closest to the &lt;code&gt;ENGINEERED_ASTEROID&lt;/code&gt;.  A quick route to euclidian distance in Postgres is to use the &lt;a href=&quot;https://www.postgresql.org/docs/current/cube.html&quot;&gt;cube extension&lt;/a&gt;:&lt;/p&gt;&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;sql with originCTE as ( select cube(array[x,y]) as position from waypoint where reset_date =&apos;2024-03-24&apos; and type = &apos;ENGINEERED_ASTEROID&apos; ), distanceCTE as ( select waypoint.*, cube(array[waypoint.x, waypoint.y]) &amp;lt;-&amp;gt; originCTE.position as distance from waypoint join originCTE on 1=1 where reset_date =&apos;2024-03-24&apos; ) select * from distanceCTE where &apos;SHIPYARD&apos; = any(traits) or &apos;MARKETPLACE&apos; = any(traits) order by distance; &lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;</description>
      <pubDate>Sun, 31 Mar 2024 00:00:00 GMT</pubDate>
      <link>https://staffordwilliams.com/dev/spacetraders-v2/2024-w13/</link>
      <guid isPermaLink="true">https://staffordwilliams.com/dev/spacetraders-v2/2024-w13/</guid>
      <category>spacetraders-v2</category>
    </item>
    <item>
      <title>spacetraders-v2: First automation, first contract delivered</title>
      <description>&lt;p&gt;&amp;lt;h2 id=&amp;quot;v2-4&amp;quot;&amp;gt;&amp;lt;time datetime=&amp;quot;2024-03-19&amp;quot;&amp;gt;Mar 19&amp;lt;/time&amp;gt; first automation &amp;lt;span&amp;gt;v2.4&amp;lt;/span&amp;gt;&amp;lt;/h2&amp;gt;&lt;/p&gt;&lt;p&gt;I&apos;ve implemented some fairly rudimentary automation that covers the first five of the &lt;a href=&quot;https://docs.spacetraders.io/quickstart/new-game&quot;&gt;six quickstart steps&lt;/a&gt;. This includes:&lt;/p&gt;&lt;p&gt;- Registering a new agent should one not be persisted for the current reset date - Accepting a contract - Purchasing a mining drone and sending it out the an asertoid - Refueling and mining the asteroid - Transiting to markets to sell the ore&lt;/p&gt;&lt;p&gt;I went down a particularly unpleasant &lt;a href=&quot;https://stackoverflow.com/questions/56188573/permission-issue-with-postgresql-in-docker-container&quot;&gt;PostgreSQL docker container permission issue&lt;/a&gt; and was ultimately unable to solve it. I&apos;ve improved the error handling and have stack traces available in Seq, and solved &lt;a href=&quot;https://github.com/TypeStrong/ts-node/issues/2053#issuecomment-1883459397&quot;&gt;wrong line numbers in ts-node/Node v20 stack traces&lt;/a&gt;. I&apos;m now persisting market data in postgres to reduce api calls and have also introduced &lt;a href=&quot;https://www.npmjs.com/package/bottleneck&quot;&gt;bottleneck&lt;/a&gt; to stay within the &lt;a href=&quot;https://docs.spacetraders.io/api-guide/rate-limits&quot;&gt;rate limits of the spacetraders api&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;To complete this first round of automation I still need to:&lt;/p&gt;&lt;p&gt;- Add some routing capability so ships can move between waypoints for journeys that otherwise can&apos;t be made directly due to fuel constraints - Deliver contract goods to their destination and fulfil the contract&lt;/p&gt;&lt;p&gt;&amp;lt;h2 id=&amp;quot;v2-5&amp;quot;&amp;gt;&amp;lt;time datetime=&amp;quot;2024-03-21&amp;quot;&amp;gt;Mar 21&amp;lt;/time&amp;gt; first contract delivered &amp;lt;span&amp;gt;v2.5&amp;lt;/span&amp;gt;&amp;lt;/h2&amp;gt;&lt;/p&gt;&lt;p&gt;I&apos;ve completed the first round automation such that a new agent can be spawned and it will complete all actions of the Quickstart including &lt;a href=&quot;https://docs.spacetraders.io/quickstart/last-steps&quot;&gt;Fulfilling the contract&lt;/a&gt;. I&apos;ve also added code to pickup subsequent contracts but the first time this occurred the contract required a resource that is not the result of mining, so I&apos;ll need to add further automation to cater for that case.&lt;/p&gt;&lt;p&gt;I&apos;m saving state from some of the api responses to postgres and using the existing types the api returns in combination with postgres jsonb columns to store the data. By default &lt;a href=&quot;https://www.adminer.org/&quot;&gt;Adminer&lt;/a&gt; truncates long JSON columns. While a &lt;a href=&quot;https://github.com/pematon/adminer-plugins#adminerjsonpreview&quot;&gt;plugin exists to solve this&lt;/a&gt; the &lt;a href=&quot;https://hub.docker.com/_/adminer/&quot;&gt;adminer docker container&lt;/a&gt; only includes official plugins. To solve for this, i&apos;ll use the docker compose feature &lt;a href=&quot;https://docs.docker.com/compose/compose-file/build/#dockerfile_inline&quot;&gt;dockerfile_inline&lt;/a&gt;:&lt;/p&gt;&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;yaml adminer: build: dockerfile_inline: | FROM adminer ADD --chmod=644 https://raw.githubusercontent.com/staff0rd/adminer-plugins/master/AdminerJsonPreview.php /var/www/html/plugins/AdminerJsonPreview.php restart: unless-stopped ports: - &apos;8080:8080&apos; environment: ADMINER_PLUGINS: &apos;AdminerJsonPreview&apos; &lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;&lt;p&gt;This approach allows me to extend the adminer container without having to have a &lt;code&gt;Dockerfile&lt;/code&gt; on disk, and thankfully &lt;a href=&quot;https://docs.docker.com/reference/dockerfile/#add&quot;&gt;ADD&lt;/a&gt; supports fetching files from the internet, so I don&apos;t need the plugin on disk either.&lt;/p&gt;&lt;p&gt;&amp;lt;h2 id=&amp;quot;v2-6&amp;quot;&amp;gt;&amp;lt;time datetime=&amp;quot;2024-03-23&amp;quot;&amp;gt;Mar 23&amp;lt;/time&amp;gt; extracting ship automation &amp;lt;span&amp;gt;v2.6&amp;lt;/span&amp;gt;&amp;lt;/h2&amp;gt;&lt;/p&gt;&lt;p&gt;I&apos;ve written logic to automate negotiation of new contracts, but the first time this executed it resulted in a contract that required a resource that is not the result of mining. I&apos;ll need to add further automation to cater for this case.&lt;/p&gt;&lt;p&gt;I have extracted the mining drone logic out such that a similar logic loop can be used with any ship:&lt;/p&gt;&lt;p&gt;1. If in transit, wait for the ship to arrive 2. Perform some action based on inspecting current state 3. Repeat&lt;/p&gt;&lt;p&gt;The command ship now uses this same logic and additonally spawns additional actors, in this case the single mining drone. I&apos;m logging a bunch more data, like credits and waypoint status and am now set to choose the next optimisation to apply.&lt;/p&gt;&lt;p&gt;!&lt;a href=&quot;/assets/spacetraders/credits.png&quot;&gt;credit charts&lt;/a&gt;&lt;/p&gt;&lt;p&gt;The mining drone logic is very slow as it uses the same ship to both extract and once the cargo hold is full, deliver the excess trade goods. I intend to add additional mining drones to the fleet, but before I do this I&apos;ll add shuttle logic so the mining drones can focus on mining, while cheaper shuttles perform the delivery.&lt;/p&gt;</description>
      <pubDate>Sat, 23 Mar 2024 00:00:00 GMT</pubDate>
      <link>https://staffordwilliams.com/dev/spacetraders-v2/2024-w12/</link>
      <guid isPermaLink="true">https://staffordwilliams.com/dev/spacetraders-v2/2024-w12/</guid>
      <category>spacetraders-v2</category>
    </item>
    <item>
      <title>spacetraders-v2: SpaceTraders again, Grafana, MikroORM</title>
      <description>&lt;p&gt;&amp;lt;h2 id=&amp;quot;v2-0&amp;quot;&amp;gt;&amp;lt;time datetime=&amp;quot;2024-03-11&amp;quot;&amp;gt;Mar 11&amp;lt;/time&amp;gt; spacetraders again &amp;lt;span&amp;gt;v2.0&amp;lt;/span&amp;gt;&amp;lt;/h2&amp;gt;&lt;/p&gt;&lt;p&gt;Three years after &lt;a href=&quot;/notes/#spacetraders-v1&quot;&gt;my first attempt&lt;/a&gt; at building against the &lt;a href=&quot;https://spacetraders.io&quot;&gt;SpaceTraders API&lt;/a&gt; I&apos;ve returned for another go, starting from the ground up. Where the &lt;a href=&quot;https://github.com/staff0rd/spacetraders&quot;&gt;last one&lt;/a&gt; was browser-based and mostly UI, for &lt;a href=&quot;https://github.com/staff0rd/spacetraders-again&quot;&gt;this approach&lt;/a&gt; I&apos;ll be focussing on automation that is mostly server-based.&lt;/p&gt;&lt;p&gt;The stack so far is a node/typescript &lt;a href=&quot;https://www.npmjs.com/package/commander&quot;&gt;commander&lt;/a&gt; application with &lt;a href=&quot;https://docs.bullmq.io/&quot;&gt;bullmq&lt;/a&gt; for job queueing, &lt;a href=&quot;https://www.influxdata.com/&quot;&gt;influxdb&lt;/a&gt; for time series persistence and &lt;a href=&quot;https://grafana.com/&quot;&gt;grafana&lt;/a&gt; for visualisation. A &lt;a href=&quot;https://github.com/winstonjs/winston&quot;&gt;winston&lt;/a&gt; and &lt;a href=&quot;https://datalust.co/seq&quot;&gt;seq&lt;/a&gt; combo will handle logging concerns. &lt;a href=&quot;https://redis.io/&quot;&gt;redis&lt;/a&gt; is in there too, but only because bullmq needs it. All of this is &lt;a href=&quot;https://github.com/staff0rd/spacetraders-again/blob/main/docker-compose.yml&quot;&gt;shipped via containers&lt;/a&gt; so I can pull the result into my ubuntu server where it&apos;ll run 24/7.&lt;/p&gt;&lt;p&gt;I&apos;m calling a single SpaceTraders API endpoint so far and persisting the leaderboard to the timeseries database.&lt;/p&gt;&lt;p&gt;!&lt;a href=&quot;/assets/spacetraders/spacetraders-leaderboard.png&quot;&gt;Screenshot of grafana dashboard displaying Most Credits&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Similar to the &lt;a href=&quot;https://github.com/staff0rd/spacetraders&quot;&gt;last one&lt;/a&gt;, this one is also &lt;a href=&quot;https://github.com/staff0rd/spacetraders-again&quot;&gt;open source&lt;/a&gt;, and I &lt;a href=&quot;post:getting-started-programming-spaceships&quot;&gt;blogged about getting started here&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;&amp;lt;h2 id=&amp;quot;v2-1&amp;quot;&amp;gt;&amp;lt;time datetime=&amp;quot;2024-03-12&amp;quot;&amp;gt;Mar 12&amp;lt;/time&amp;gt; grafana dashboarding &amp;lt;span&amp;gt;v2.1&amp;lt;/span&amp;gt;&amp;lt;/h2&amp;gt;&lt;/p&gt;&lt;p&gt;With close to 24 hours of leaderboard data I can improve my Grafana dashboard.&lt;/p&gt;&lt;p&gt;By default the tags in an influxdb query like &lt;code&gt;SELECT &amp;quot;credits&amp;quot; FROM &amp;quot;most-credits&amp;quot; WHERE $timeFilter GROUP BY &amp;quot;agent&amp;quot;::tag&lt;/code&gt; results in the legend displaying the tag names like this: &lt;code&gt;most-credits.credits { agent: 100L-TRADER }&lt;/code&gt;. This redundant information can be removed in the dashboard by going to _Edit Panel &amp;gt; Transform data_ and adding a _Rename fields by regex_ transformation. I used &lt;code&gt;.*agent: (.*) }&lt;/code&gt; as the regex.&lt;/p&gt;&lt;p&gt;I wanted a visualisation that would display the rate of change of credits over time, and influxdb&apos;s [&lt;code&gt;DERIVATIVE&lt;/code&gt; function](https://docs.influxdata.com/influxdb/v1/query_language/functions/#derivative) can perform this.&lt;/p&gt;&lt;p&gt;!&lt;a href=&quot;/assets/spacetraders/rate-of-change.png&quot;&gt;Screenshot of Most Credits - all players&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Finally, adding a Dashboard variable allows filtering all panels in the dashboard by the selected variable. Under _Dashboard settings &amp;gt; Variables_ I added a variable &lt;code&gt;agent&lt;/code&gt; with the query &lt;code&gt;show tag values from &amp;quot;most-credits&amp;quot; with key=&amp;quot;agent&amp;quot;&lt;/code&gt;. Each panel&apos;s query then can be updated to include a &lt;code&gt;WHERE (&amp;quot;agent&amp;quot;::tag =~ /^$agent$/)&lt;/code&gt; clause.&lt;/p&gt;&lt;p&gt;!&lt;a href=&quot;/assets/spacetraders/rate-of-change-filtered.png&quot;&gt;Screenshot of Most Credits - filtered by agent&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;lt;h2 id=&amp;quot;v2-2&amp;quot;&amp;gt;&amp;lt;time datetime=&amp;quot;2024-03-13&amp;quot;&amp;gt;Mar 13&amp;lt;/time&amp;gt; maintenance items &amp;lt;span&amp;gt;v2.2&amp;lt;/span&amp;gt;&amp;lt;/h2&amp;gt;&lt;/p&gt;&lt;p&gt;I was hoping to hit some new endpoints and try out &lt;a href=&quot;https://mikro-orm.io/&quot;&gt;MikroORM&lt;/a&gt; tonight but instead some fairly boring quality-of-life improvements took up my time.&lt;/p&gt;&lt;p&gt;- I added a job queuing feature that will remove existing queues if they don&apos;t match the pattern currently configured. This allows me to change queue scheduling and know the old queues will be cleaned up - I added authentication to Seq - turns out it will block querying for ten minutes if it thinks multiple users are accessing it - I added update scripts to pull, rebuild and restart the app docker container - I increased the leaderboard polling to 10 minutes, this resolves an issue where the rate of change had zero delta every second poll:&lt;/p&gt;&lt;p&gt;!&lt;a href=&quot;/assets/spacetraders/zero-delta.png&quot;&gt;alt text&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;lt;h2 id=&amp;quot;v2-3&amp;quot;&amp;gt;&amp;lt;time datetime=&amp;quot;2024-03-14&amp;quot;&amp;gt;Mar 14&amp;lt;/time&amp;gt; initialising mikro orm &amp;lt;span&amp;gt;v2.3&amp;lt;/span&amp;gt;&amp;lt;/h2&amp;gt;&lt;/p&gt;&lt;p&gt;I&apos;ve been on the lookout for a replacement for &lt;a href=&quot;https://typeorm.io/&quot;&gt;typeorm&lt;/a&gt; for some time and &lt;a href=&quot;https://mikro-orm.io/&quot;&gt;mikro orm&lt;/a&gt; looks promising.&lt;/p&gt;&lt;p&gt;The &lt;a href=&quot;https://mikro-orm.io/docs/quick-start&quot;&gt;quickstart&lt;/a&gt; does not have enough information to get the tool running end-to-end in a typescript environment, so the longer &lt;a href=&quot;https://mikro-orm.io/docs/guide/first-entity&quot;&gt;Getting Started - Chapter 1&lt;/a&gt; is required reading too. Even so, there were some additional gotchas that meant a bit of googling, a bit of debugging, and a few hours in total to get the tool running. These commits (&lt;a href=&quot;https://github.com/staff0rd/spacetraders-again/commit/447cb180240fb252b085533e4fed5f89e50eb909&quot;&gt;one&lt;/a&gt;, &lt;a href=&quot;https://github.com/staff0rd/spacetraders-again/commit/5dd0e91348810c306f4347da67408f79cfa91a9e&quot;&gt;two&lt;/a&gt;) show what was changed to add mikro-orm.&lt;/p&gt;&lt;p&gt;I had to swap out &lt;code&gt;tsx&lt;/code&gt; for &lt;code&gt;ts-node&lt;/code&gt;, considering mikro (like typeorm) also uses typescript decorators that esbuild does not support. There&apos;s a bunch of &lt;code&gt;package.json&lt;/code&gt;/&lt;code&gt;tsconfig.json&lt;/code&gt; settings that need to be correct for this to work, and ultimately the only way I could make &lt;code&gt;ts-node&lt;/code&gt; happy was by starting the app with &lt;code&gt;node --experimental-specifier-resolution=node --loader ts-node/esm ./src/index.ts&lt;/code&gt;. This however does not allow the tool to detect correctly that &lt;code&gt;ts-node&lt;/code&gt; is in use (&lt;a href=&quot;https://github.com/mikro-orm/mikro-orm/blob/60b2c9197249c8f982423ef320463cc8357b6542/packages/core/src/utils/Utils.ts#L759&quot;&gt;source&lt;/a&gt;) at dev time, and confusingly it will return a &lt;code&gt;No entities found&lt;/code&gt; error as it&apos;s actually looking in &lt;code&gt;dist&lt;/code&gt; for the entities and not &lt;code&gt;src&lt;/code&gt;.  Explicitly setting &lt;code&gt;{ tsNode: true }&lt;/code&gt; in config solves for this though finding this solution required debugging into the library and before fixing it my app was silently exiting without any error message.&lt;/p&gt;&lt;p&gt;The tool has a CLI and one of it&apos;s features, which, once installed is executed via &lt;code&gt;npx mikro-orm&lt;/code&gt;, however, in the case of typescript it must be executed via &lt;code&gt;npx mikro-orm-esm&lt;/code&gt;. One of the nice features of the CLI is that it confirms your configuration. Although a working configuration at CLI time can still stuffer from the &lt;code&gt;No entities found&lt;/code&gt; error at runtime without the fix above.&lt;/p&gt;&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;bash $ npx mikro-orm-esm debug Current MikroORM CLI configuration - dependencies: - mikro-orm 6.1.9 - node 20.10.0 - knex 3.1.0 - pg 8.11.3 - typescript 5.4.2 - package.json found - ts-node enabled - searched config paths: - /home/stafford/git/spacetraders-again/src/mikro-orm.config.ts (found) - /home/stafford/git/spacetraders-again/mikro-orm.config.ts (not found) - /home/stafford/git/spacetraders-again/src/mikro-orm.config.js (not found) - /home/stafford/git/spacetraders-again/mikro-orm.config.js (not found) - configuration found - database connection succesful - &lt;/code&gt;tsNode&lt;code&gt; flag explicitly set to true, will use &lt;/code&gt;entitiesTs&lt;code&gt; array (this value should be set to &lt;/code&gt;false&lt;code&gt; when running compiled code!) - could use &lt;/code&gt;entities&lt;code&gt; array (contains 0 references and 1 paths) - /home/stafford/git/spacetraders-again/dist/**/*.entity.js (not found) - will use &lt;/code&gt;entitiesTs&lt;code&gt; array (contains 0 references and 1 paths) - /home/stafford/git/spacetraders-again/src/**/*.entity.ts (found) &lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;&lt;p&gt;There is a heap of documentation and google might be required to find docs specific to a given error message. An example is &lt;a href=&quot;https://stackoverflow.com/a/72799993/469777&quot;&gt;this monster stackoverflow answer&lt;/a&gt; where the author of the tool explains one of the error messages I encountered. There&apos;s almost a little too much to learn, such that the early getting started documentation almost presumes you can make decisions about topics that you haven&apos;t yet learned about, for example the &lt;a href=&quot;https://mikro-orm.io/docs/metadata-providers&quot;&gt;Metadata Providers&lt;/a&gt; and &lt;code&gt;ts-morph&lt;/code&gt; which is used to infer more schema via type information rather than decorator annotations.&lt;/p&gt;&lt;p&gt;Once the CLI was configured, and the separate migrations library installed and referenced, &lt;a href=&quot;https://mikro-orm.io/docs/migrations&quot;&gt;migrations&lt;/a&gt; appeared to Just Work™️.  Once runtime was configured, &lt;a href=&quot;https://github.com/staff0rd/spacetraders-again/commit/5dd0e91348810c306f4347da67408f79cfa91a9e#diff-455033e6685d7db2ae5e0a0529d2bd1384e1a1b050827cd51c6127842d1dded9R5-R11&quot;&gt;read/write appeared simple enough&lt;/a&gt;. With the gotchas out of the way and the setup time spent, I&apos;m looking forward to using the query functionality further as I build out more of my app.&lt;/p&gt;</description>
      <pubDate>Thu, 14 Mar 2024 00:00:00 GMT</pubDate>
      <link>https://staffordwilliams.com/dev/spacetraders-v2/2024-w11/</link>
      <guid isPermaLink="true">https://staffordwilliams.com/dev/spacetraders-v2/2024-w11/</guid>
      <category>spacetraders-v2</category>
    </item>
  </channel>
</rss>
