Ok… it’s been a while. I could blame it on school, but to be honest I just could never find the motivation to write a post. That being said, I have not abstained from programming these past… 3 months (wow that’s a long time). As the title lets on, there are three small projects I’d like to share, and then a little afterword for what I’m looking to do going forward (other than, you know, posting consistently again). Here we go!

D&D(Discord and D&D(Dungeons and Dragons))

Okay, first small project: a Dungeons and Dragons (D&D) Discord bot. In case you don’t know what D&D is, it’s a role-playing game in which the Dungeon Master (DM) sets the scene and controls the story for the players. It’s totally open world, and all in the imagination. And everything is dependant on the roll of the dice. So, my friends and I play D&D, and while it’s better in person, that doesn’t always work out due to scheduling. Thanks to the marvels of technology, however, we can play virtually by just joining a Discord call. We also found this absolutely amazing tool that I use for all my character sheets (the page with all your stats for your in-game player) now, called Adventurer’s Codex (AC). It’s pretty amazing, but I wanted more.

We already had a Discord bot that can do dice rolls, but I wanted a Discord bot that could integrate with AC and then do dice rolls from there. For example, all characters have an Athletics score. If you’re making an Athletics Check, say to shove a boulder, you would roll a 20-sided dice, then add your Athletics score. If my Athletics were a +3, the shorthand for that would be 1d20+3, or just d20+3. The general formula is: number_of_dicedsides_on_dice±extra. Of course, it is pretty easy to just check your character sheet then roll the dice, but I needed a project. Thus, I set out to make a D&D utility bot that would integrate AC.

That’s what I set out to do, anyway, but my 3318 line program says I did so much more. I’m not going to get into everything I did, but I will showcase the parts that could be applicable to other scenarios (not just for a D&D Discord bot). The first of those will be integrating with AC, the second is how I decided to store information, and the third is fetching monster stats, which I’ll explain more later.

AC Integration

My first inclination was to be lazy; work smarter not harder. AC provides a feature called a share page, where you can send other people a view-only version of your character sheet. So, everyone could just provide the bot a link to a share page. This benefits both sides: players don’t have to provide credentials, and I don’t have to reverse-engineer the AC login page. I just fetch the share page, use some RegEx (if you don’t know what that is, you should Google it, it’s amazing), and bam. Have all the stats I need. But I wasn’t quite happy.

Two things drove me to use their API anyway. First, I kind of wanted to try the entire time. The point of my projects tend to be one of two things: try my hand at something new, or make something useful. When they overlap is perfect, but sometimes they’re more one thing than the other. In this case, as mentioned previously, we could already do everything the bot’s going to do manually, so while it will make things easier, a large reason I’m doing it is to branch out a bit. The second is that, it’s just better. It’s a cleaner, more elegant solution, even if it is more complicated. So here’s how I did it.

First, I needed to figure out how AC gets the information from its API to display on the page. Thankfully, Chrome developer tools are amazing! All modern browsers have them, but I’m partial to Chrome myself. You may have not heard of them by the name ‘developer tools’, but it’s the window that opens when you inspect on a webpage. However, it can do so much more than just the inspect window. There’s an awesome tool on the ‘Network’ page, which allows you to see any outgoing network requests. The reason this is so important is that any time it gets data from the API, it has to make one of those network requests. Since that’s exactly what I want to be doing, I want to see the format of those requests.

So I pull up the network page and reload, and look at the headers sent when it makes an API request. As expected, there’s some form of authentication token, but it looks like that’ll be the only hard(ish) part. To get that auth token, I’m going to need to try and copy what their login page does, because obviously to log in and get the token, you have to… log in. So I go there, log out, open the network page, and then log back in. Unfortunately when you log in it immediately redirects you to another page, which clears the log of network requests, but I just turn off JavaScript in Chrome, do it again, and voila. A perfect log of what it does to log in.

I’m not going to go through exactly what I had to do, it was a fair amount of just trial and error, but here’s the full path if you want it. This was very reminiscent of when I made the headless Minecraft client, and figuring out the Microsoft auth flow.

1. GET request to https://app.adventurerscodex.com/accounts/login/ to get cookies and csrfmiddlewaretoken
2. send cookies and csfrmiddlewaretoken and username/password back to https://app.adventurerscodex.com/accounts/login/ in a POST request, disabling redirects to get cookies and headers
3. send cookies and headers in a GET request to https://app.adventurerscodex.com to get a specific JavaScript file that that webpage includes in a script tag
4. make a GET request to the source of that JavaScript file to get the client id
5. send client id and previous cookies in a GET request to https://app.adventurerscodex.com/api/o/authorize/, allowing redirects
6. get the access token from the resulting URL

Data Storage

This one’s real quick, just figured I’d mention how I decided to store data in case anyone’s curious. Since I want the bot to work on multiple servers at once, and be able to store various user-specific data, I just had it use a JSON file, and store a dictionary in the code. Every time it modifies that dict, it saves it to the JSON, and when it starts up it reads from the JSON. That’s it!

Monster Fetching

Again I’m going to keep this a little short, although it does need a little introduction. In D&D there are various monsters, and while you can create your own, there is a huge compendium of statblocks (like player sheets but for monsters) already made. Technically doing a little bit of pirating, but 5e.tools has compiled them all into an awesome website. I wanted to make it so you could run a command in Discord, and it would send you an image of the statblock for the corresponding monster.

The best way to make that happen would be to do what I did previously: go to the website, see where it gets the images it displays from, and then do that myself. However, to my horror, I soon saw that they don’t use images. They store the stats as text, and then just use fancy HTML and CSS to make it look like a statblock. Yet I was not deterred. I looked into how to save HTML elements as an image, and lo and behold, I found something. The issue with that is, it’s a JavaScript command. I didn’t find anything that could just do it in Python (what I’m coding the bot in), so I’ll have to have an active browser running to run the script on.

I can’t just have it open a browser whenever someone runs the command though. Not only would that be slow, if I’m running this bot in the background on my computer, I don’t want it to just randomly open windows sometimes. So instead, I need it to do it all at once, beforehand, then cache them. So, I write up a quick Selenium script. Selenium is an awesome Python library that can run a browser window. The final hurtle for this was that 5e tools has some bot protection, but some easy Googling got me undetected_chromedriver, a fork of Selenium to get around such things. So it queries all the monsters, saves there names and a couple stats, and downloads the statblocks as images which it then puts in a ZIP to save storage. When you run the command, it unzips the specific file, sends it, then deletes it from the filesystem. Easy!

That’s it for the D&D bot, it does a bunch more stuff, but I figure I’ve talked about it more than enough already. The next part is related, but a bit different.

Linux Server

So this was spurred by the D&D Discord bot, but I’ve wanted to do it for some time. I have an old computer which is running Windows 11 right now, but is missing several keys. Rather annoying to use, but it does have another, unused, SSD. As you may or may not know, Linux tends to be rather annoying to use for your personal computer, but is pretty awesome for hosting servers. Since there are things, such as Discord bots, that I want running 24/7, but I don’t want to run my personal computer all the time, it’d be nice to have a dedicated computer which just runs various programs for me.

What I did was a process called dual-booting, where I installed Linux on that extra hard drive, so that I can keep my installation of Windows in case I ever need it. Now what I would like to have done would be set up an SSH server which would allow me to connect to it remotely, but that comes with some, albeit small, risks for an attacker to access important information such as bank details. Unlikely, but still a danger if I were to leave a port open to SSHing. That small reason paired with what I said earlier about branching out? It’s time to get creative.

The solution I ended up going with was having a repository on GitHub which has a file that I can add to. In it, I provide links to repos that I want the server to run, and then those repos have a run.sh file in them, which will get it started. Then I made a Bash (the command line interpreter Linux uses) script that goes through that list of things, checks to see if there are any updates on GitHub it needs to get, and then runs the run.sh files for all those projects if they aren’t already running. If there are updates it needs to get, it will stop the previous process and relaunch it.

Not too complicated of a script, but Bash can be a finicky language at best, and at worst it can be almost impossible to debug nicely. Took most of several afternoons, but eventually got it figured out, and I’m honestly very happy with it. Currently have two Discord bots running on it, but I can add whatever I want, whenever I want, wherever I happen to be. That’s all for this, the basic concept is relatively simple, it just took a fair amount of time to execute.

CyberStart

Forewarning, final section is basically just a plug for CyberStart. If you haven’t heard of it before, which is relatively likely, CyberStart is an online capture the flag (CTF) hacking competition. Lots of big words, but don’t just skim over the rest of the section, I’ll explain! A capture the flag competition is a type of hacking competition in which they give you challenges, and then you have to get some sort of ‘flag’. They can in their form, but are a combination of letters, numbers, and symbols, to prevent brute-forcing.

I’ve done several of these CTFs before, so I know some of the stuff to look for, and have completed most of the CyberStart challenges over the past couple of months. However, that’s not to say it’s only for experts! The early level challenges are designed to help you learn the sorts of things to look for, and they have a Field Manual to guide you throughout, as well as hints you can pay points for. However, if you’re already a CTF expert, never fear! I can tell you from my experience, the challenges get significantly harder. On top of just being a ton of fun (and helping pass the time in school), as 11th and 12th graders you can get scholarships through the National Cyber Scholarship Foundation!

I truly enjoy it, and would recommend giving it a try over the break. You can get access completely free as a student (https://register.cyberstartamerica.org/student/), so if you don’t like it, no harm. If you need any help setting it up or want to know more about it, feel free to contact me as always using the methods on the About page.

Wrapup

Well that’s it! First post in forever. Thank you so much if you’ve read to the end, and hopefully you learned a thing or two. As promised earlier, here’s a quick snapshot into what my plans are at the moment. If you’re a student or parent, you’ve probably been frustrated with the Frontline/TEAMS interface, so a friend and I are working on Scorecard, which will completely revamp the UI. I’ll talk more about that next post, probably, but aside from that I’m hoping to get back into ReLife. I know I’ve said that countless times before, but this time I have extra motivation. My brother is going to college next summer, and he’s been helping me come up with ideas, solve problems, and find bugs every step of the way. I really want to get it done before he leaves so we can see our hard work come to fruition together. Finally, if you don’t want to miss the next post (hopefully with ReLife updates) then subscribe below!