Pathfinder Resources

Here is a repository where you can find my Pathfinder RPG compatible resources. Currently these are all Pathfinder 1e (and by extension 3.5e OGL), as I have yet to dive deeply into Pathfinder 2e or 5th edition yet!

  • Drillemont’s Guide to the Arcane Trickster: A player’s guide for optimizing playing MacGuyver or James Bond, a character that can engineer a solution to any problem with minimal resources. Currently in a pre-alpha state, but still useful in its own right. I’m actively adding more to the guide on a regular basis.
  • Carrion Crown Campaign Compendium: A compendium of additional resources that GM’s can use in Paizo’s gothic horror adventure path. I started GMing this campaign for a group online in 2020 and since one of my players has already played through the first two books, I’ve gone out of my way to modify and add quite a bit of content to the as-written modules. I’m currently in the process of compiling my notes into a release-quality compendium for any other GMs to use in their own games, but isn’t quite thorough enough yet for an initial release.
  • Carrion Crown Campaign Additional Resources: A supplement to my campaign compendium of the same name, this links to artwork, music, and such on the internet that I don’t have the copyright permissions to distribute directly. Wherever possible I attempt to link to the artist’s original pages, the most official version of music I can find, etc. Given that urls can quickly move or get lost to the ether, it made more sense to me to separate them into another document. As with the campaign compendium, this is not quite ready for release.

I also have several Pinterest boards that I use as adventure, NPC, or PC inspiration and to act as visual guides when I GM. These are the ones with the most content:

  • RPG Characters: Useful for both PCs and NPCs.
  • RPG Inspiration: Encounter, monster, and setting ideas.
  • Tactical Maps: Free maps from various artists that can be used in a virtual tabletop program or printed on a plotter.

Embed Unity3D Games in a WordPress Page with Shortcodes

If you’ve added Unity3d games using the iframe trick I talked about in my Embed Unity3d Games in a WordPress Page article, you may have come to realize, as I did, that it doesn’t work that great when the game is not fully self-enclosed (i.e. you want there to be some interaction between your game and some outside resource, such as a server-side high score table).

Granted, if your game is fully enclosed and doesn’t communicate with anything outside of the game at all, the iframe method works just fine. But you may still want to follow along here anyway, because this method is a little bit easier to use once its all set up properly.

Note that unlike that previous post though, this method requires you to have a hosted version of WordPress and have access to view and modify the PHP files that power your site. I’m sure this method could be turned into a plugin (and probably would actually work better that way, as really this is plugin-style functionality and would only require access to install plugins), or even a custom Gutenberg block. But I didn’t think of that until I had already finished, and I have zero experience developing WordPress plugins or custom Gutenberg blocks, so this is the way I did it! 😉

Why Not Just IFrame It?

The reason the iframe trick doesn’t work that great when the program is not self enclosed is due to the Same Origin Policy. As I was updating my 1945 game to include a global high scores table, I was getting an error in my browser console saying “Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at $somesite.” This indicates that the request was blocked due to violating the CORS security rules.

SOP states that one webpage can request resources from another only if both webpages have the same origin, which is defined as having the same scheme, host, and port. As I looked into why that was happening (my game is requesting a resource located on the same server, using the standard http:// port of 80), it seemed odd that the request was blocked. My best guess is that it is a limitation baked into using the <iframe> tag.

I tested out trying to fix it by adding a crossdomain.xml file, but it didn’t seem to help (i.e. it was still throwing the error for me) but I suppose its worth a shot. This is a sample crossdomain file I found on the web:

<!--?xmlversion="1.0"?-->
<cross-domain-policy>
<allow-access-fromdomain="*">
</allow-access-fromdomain="*">
</cross-domain-policy>

For what its worth, I’ve heard that using the “*” wildcard isn’t great for security purposes, so if this does work you will want to tweak it to allow access specifically from your website.

Returning from our tangent, assuming we want our games to be able to communicate with an outside resource, we need another solution for embedding our games into our WordPress websites… and shortcodes will come to the rescue!

Preparations

First off, while this process can be done using any theme, if you use a published theme such as the Twenty-Twenty theme or something else, if/when you update the theme it might erase some of your work as we are going to be directly modifying some of the theme files. Thus, to preserve your hard work I recommend you make a child theme before starting to code. I won’t go into that since there are plenty of other great tutorials on making child themes.

Create the Shortcode

To create the shortcode, we need to dig into some PHP code. WordPress was written using PHP and we’re going to hook into the existing code in order to add our additional functionality.

Where we are going to hook into the code is in the “functions.php” page in your active theme. Look for the following file, substituting the name of your active theme for [your-theme-name]:

/wp-content/themes/[your-theme-name]/functions.php

You technically could write all your extra functionality directly in this file, but I prefer keeping my custom code separate. So I created a new PHP file in the same directory and called it “custom-functions.php”.

Because WordPress doesn’t know it should use the code from our new PHP page though, we have to tell it to read our new file! At the bottom of the functions.php page, add the following line of code to tell WordPress that we have extra functions that we also want to use:

include('custom-functions.php');

This will tell WordPress to load our new functions when it reaches that line of code. Next, switch over to your new custom-functions.php file. This is the real meat of our project (or mashed potatoes, for our meat-averse friends).

custom-functions.php

Side note: If you’re familiar with PHP and want to skip my line-by-line explanations (or you don’t really want to be a web developer and just want to copy-paste the code), the full code is at the bottom of this section.

In this section, we’re going to use several WordPress functions. If you’re more curious about a function beyond my brief explanation here, all of the function are described in fuller detail within the WordPress Code Reference, and I recommend you check them out there. The Code Reference is an invaluable resource, in much the same way that the Unity Scripting Reference is for programming Unity games!

PHP files always start and end with the following syntax, so lets start by putting these into our new, blank file:

<?php

?>

Inside of those lines goes all the rest of our code we are adding. Most of our code will go in a function, which is fundamentally the same thing as a method in C#, although with slightly different syntax. So lets create our function:

function unity3d_embed_webgl_function( $atts = array() ) {

}

The keyword “function” tells PHP that you have a function (go figure!), followed by the name of your function, the arguments in parentheses, and then the curly braces that designate the function block. Woah, that argument list looks kinda weird! What it’s saying is we don’t care what we get, so long as PHP treats as if it were an array.

Next, lets start coding the function itself. Inside of the curly braces, the first part looks like this:

// Unwrap the shortcode attributes, substituting the given defaults for any undefined attributes
$args = shortcode_atts(
    array(
        'url' => '',
        'width' => '960',
        'height' => '600',
    ),
    $atts
);

$url = esc_attr( $args['url'] );
$width = esc_attr( $args['width'] );
$height = esc_attr( $args['height'] );

What we do here is take the array of shortcode attributes that we passed in and unwrapping them from the array with WordPress’ built-in shortcode function. Then we specifically look for the ‘url,’ ‘width,’ and ‘height,’ attributes. If they are present, they are saved to a new $args array. If they aren’t present, then we instead put the appropriate default value in instead. Then we save the three attributes we care about in their own variables for ease of use and escape any special characters. We escape the characters to help protect us from ourselves: inadvertent SQL injection in our shortcode editor can wreak havok on our filesystem. It also allows us to have special characters in our url, if for whatever reason you want to.

The next part is some sanity checking to make sure we put in a url. Without a url, there won’t be much to do!

// validate the directory is not blank
if ( '' === trim ( $url ) ) {
    $message = __( 'Invalid WebGL location: No location given.' );
    _doing_it_wrong( __FUNCTION__, $message, '4.4.0' );
    return '</p>Invalid WebGL location: No location given.</p>';
}

This just adds a trailing slash if it doesn’t have one already. Pretty simple. Do note that I have ‘https’ in my url. If you don’t have your website using ‘https’, you will want to switch that to ‘http’.

$fullurl = trailingslashit(site_url('/unity/', 'https') . $url);

This section tells WordPress to load the UnityLoader file that Unity creates when you build a WebGL version of your game. This is the first step that references your game files.

// add the UnityLoader javascript file to footer
wp_enqueue_script('unity3d-loader', $fullurl . 'Build/UnityLoader.js', array(), null, true);

This adds the WebGL script to your page, and runs its instantiate method, which causes your game to start.

// add the WebGL.json javascript file to footer
wp_add_inline_script('unity3d-loader', 'var gameInstance = UnityLoader.instantiate("gameContainer", "../unity/' . $url . '/Build/WebGL.json");');

It still won’t show up on the page yet, though. For that, we need this line of code:

// returns the game window html code
return '<div id="gameContainer" style="width: ' . $width . 'px; height: ' . $height . 'px; margin: auto"></div>';

That is the last bit of the function, but your game still won’t show up. What gives?

Well, just like in C#, if you don’t tell WordPress that you actually want to run the function, it just sits there unused. So we need to add one more line of code to our custom-functions script, but this time outside of the function block:

add_shortcode('unity3d_embed_webgl', 'unity3d_embed_webgl_function');

That tells WordPress that you want your function to be loaded as a valid shortcode. When you’re all finished, the full custom-functions.php file should look like this:

<?php

function unity3d_embed_webgl_function( $atts = array() ) {

    // Unwrap the shortcode attributes, substituting the given defaults for any undefined attributes
    $args = shortcode_atts(
        array(
            'url' => '',
            'width' => '960',
            'height' => '600',
        ),
        $atts
    );

    $url = esc_attr( $args['url'] );
    $width = esc_attr( $args['width'] );
    $height = esc_attr( $args['height'] );


    // validate the directory is not blank
    if ( '' === trim ( $url ) ) {
        $message = __( 'Invalid WebGL location: No location given.' );
        _doing_it_wrong( __FUNCTION__, $message, '4.4.0' );
        return '</p>Invalid WebGL location: No location given.</p>';
    }

    $fullurl = trailingslashit(site_url('/unity/', 'https') . $url);

    // add the UnityLoader javascript file to footer
    wp_enqueue_script('unity3d-loader', $fullurl . 'Build/UnityLoader.js', array(), null, true);

    // add the WebGL.json javascript file to footer
    wp_add_inline_script('unity3d-loader', 'var gameInstance = UnityLoader.instantiate("gameContainer", "../unity/' . $url . '/Build/WebGL.json");');

    // returns the game window html code
    return '<div id="gameContainer" style="width: ' . $width . 'px; height: ' . $height . 'px; margin: auto"></div>';
}

add_shortcode('unity3d_embed_webgl', 'unity3d_embed_webgl_function');

?>

The Shortcode… Code

To add your game to your page now, you first upload your game to your webhost as described in Embed Unity3D Games in a WordPress Page. Then add a shortcode block to your page:

And finally fill in the textbox with your shortcode, giving your game’s information for the url, width, and height (the order shouldn’t matter, as long as you have the name of the shortcode first). This is a sample shortcode for my 1945 game, both in image and text format:

[unity3d_embed_webgl url=1945 width=951 height=713]

And voila! Your Unity game should appear on your website in the location on your page that you put your shortcode!

Server-Side High Scores in Unity3D

When developing my 1945 game, I wanted a way for the high score that one player achieved to be visible to another player playing my game on my website as well. Not knowing where to start, I wandered about the internet for a little while (as I am wont to do on occasion) and I happened across this post on the Unify wiki: Server Side Highscores.

Looking through the code on that page, I was sad to see that it is woefully out of date, as the “tested working solutions” it lists use the deprecated mysql_* PHP functions instead of mysqli_* or PDO. In addition, the code as presented was hard coded within the game to a very specific structure of GUI elements in Unity. So while it didn’t really work for my purpose, it at least got me thinking in the right direction.

Detailed here is my solution to server-side high scores. I’ve aimed for a solution that is at least a little bit more secure and (in my opinion) a little bit more elegant as its completely independent from the GUI.

Note that I’m not going to go in detail on how to add the high score system itself to your game, as that’s going to be dependent on a lot of things within your game. In my 1945 game I have a fairly simple system consisting of two arrays: an array of TextMeshProUGUI elements for the names and another with the scores that I display on screen when the game ends. Those just get populated with the data fetched by the code I will be detailing here. If you do want to see my full scoreboard code, my 1945 project is available for perusal on my Bitbucket.

Database

First, you will want to set up and create your database. There are a lot of resources online on how to set up a database and is entirely dependent on how you are going to show off your game, so I won’t rehash that here. I’m going to assume that you’re able to set up your database and access it somehow. My web host supplies access to database management through phpMyAdmin, but as long as you can execute SQL somehow you will be fine.

The important part here is to set up a table, and the Unify wiki has a reasonable setup for this, so I’ll just paraphrase the instructions and copy the SQL code to create the table directly from there:

Run the following SQL on your database. If you get a SQL Syntax error, replace

TYPE=MyISAM;

with

ENGINE=MyISAM; 

as TYPE is deprecated.

CREATE TABLE `scores` (
   `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
   `name` VARCHAR(15) NOT NULL DEFAULT 'anonymous',
   `score` INT(10) UNSIGNED NOT NULL DEFAULT '0'
)
TYPE=MyISAM;

Server-Side Scripts

Here we will create three scripts: one that will hold our mysqli connection information, one to save scores in the database, and one to retrieve them.

mysqli-connect-gamename.php

This file contains the connection information, including the password to log on to your database, in plaintext. Therefore this file should not be placed in your “public_html/” folder. Anything in your public_html folder can be read by anyone given enough interest to do so, so this is to help protect your database.

That is important, so let me repeat that. DON’T PUT THIS FILE ANYWHERE IN YOUR “PUBLIC_HTML/” DIRECTORY.

The other scripts assume they are at the root directory of your web hosting. If you put it somewhere elsewhere, you will have to adjust the

require ('../../../mysqli_connect-gamename.php');

line in the other two PHP files appropriately. Of course, replace the database information in the script below with your actual database information.

<?php # Script 9.2 - mysqli_connect-1945.php

// This file contains the database access information.
// This file also establishes a connection to MySQL,
// selects the database, and sets the encoding.

// Set the database access information as constants:
DEFINE ('DB_USER', 'database-username');
DEFINE ('DB_PASSWORD', 'database-password');
DEFINE ('DB_HOST', 'localhost');
DEFINE ('DB_NAME', 'database-name');

// Make the connection:
$dbc = mysqli_connect (DB_HOST, DB_USER, DB_PASSWORD, DB_NAME) OR die ('Could not connect to MySQL: ' . mysqli_connect_error() );

// Set the encoding...
mysqli_set_charset($dbc, 'utf8');

addscore.php

This script saves the score sent by your game to the database. Put this in the same folder as your game (so in my case, “unity/1945/”). Make sure the secret key here and the secret key in the C# script match exactly. While not necessary, I recommend generating a key using a password generator. There are a lot of free online options such as the Lastpass or 1Password password generators (generating a password on either of their sites is completely free to use, no login needed).

<?php

require ('../../../mysqli_connect-1945.php');
 
// Strings must be escaped to prevent SQL injection attack.
$name = mysqli_real_escape_string($dbc, $_GET['name']);
$score = mysqli_real_escape_string($dbc, $_GET['score']);
$hash = $_GET['hash'];

$secretKey="mySecretKey"; # Change this value to match the value stored in the client script

$real_hash = md5($name . $score . $secretKey);
if($real_hash == $hash) {
    // Send variables for the MySQL database class.
    $query = "INSERT INTO scores VALUES (NULL, '$name', '$score');";
    $result = $dbc->query($query) or die('Query failed: ' . mysqli_error($dbc));
}
?>

display.php

This script retrieves the scores from the database to be displayed in game. It returns a tab separated list of 10 name/score pairs, with each pair on its own line. That is, it returns a list that looks like this:

Matthew Randolph    1000
Matt    950
ThatMatGuy    800
Gurravanna Drillemont    700
TheMonthOfFebruary    600
Salazar Salamander    550
MrMatt    540
SomeGuyNamedMatt    500
JustAMattPassingBy    400
TheBestKindOfMatt    100

Note that because we are escaping characters when we save them to the database, even if someone decided to try to pull a fast one on us and include a TAB character in their name, we’d still be protected from it, as it should show up as an escaped sequence of characters that represents TAB and not as a TAB itself.

 <?php

 require ('../../../mysqli_connect-1945.php');

$query = "SELECT * FROM `scores` ORDER by `score` DESC LIMIT 10";
$result = mysqli_query($dbc, $query) or die('Query failed: ' . mysqli_error($dbc));

$num_results = mysqli_num_rows($result);

for($i = 0; $i < $num_results; $i++)
{
     $row = mysqli_fetch_array($result);
     echo $row['name'] . "\t" . $row['score'] . "\n";
}
?>

Client-Side Code (a.k.a Your Game)

ScoreboardWebInterface.cs

Here we create a C# script in your game that will connect to your addscore.php and display.php scripts to send and retrieve scores within the game. Start by creating a new C# script and calling it ScoreboardWebInterface.

Lets open the script and start by adding the variables we will need. We need a reference to the secret key you created in addscore.php, string references to your addscore and highscore php scripts, and a property to hold the scores:

public class ScoreboardWebInterface : MonoBehaviour
{
    private string secretKey = "YourSecretKey"; // Edit this value and make sure it's the same as the one stored on the server
    public string addScoreURL = "https://yourwebsite.com/unity/yourgame/addscore.php?"; // be sure to add a ? to your url
    public string highscoreURL = "https://yourwebsite.com/unity/yourgame/display.php";
    
    private KeyValuePair<string, string>[] scores;
    public KeyValuePair<string, string>[] Scores
    {
        get { return scores; }
    }

Next we write the method to send a new score to the database. Because we’re using web resources, we need to call it as a coroutine so that our game doesn’t lock up while we’re waiting around for the response from the server about whether it worked or not.

// Send the new score to the database
public IEnumerator PostScore(string name, int score)
{
    //This connects to a server side php script that will add the name and score to a MySQL DB.
    // Supply it with a string representing the players name and the players score.
    string hash = Utility.Md5Sum(name + score + secretKey);
 
    string post_url = addScoreURL + "name=" + WWW.EscapeURL(name) + "&score=" + score + "&hash=" + hash;
 
    // Post the URL to the site and create a download object to get the result.
    Debug.Log("Submitting score");
    WWW hs_post = new WWW(post_url);
    yield return hs_post; // Wait until the download is done
    Debug.Log("Score submitted");
 
    if (hs_post.error != null)
    {
        Debug.Log("There was an error posting the high score: " + hs_post.error);
    }
}

To fetch the scores from the database, we will use this next method.

// Get the scores from the database
public IEnumerator GetScores(Action<int> returnCode)
{
    scores = new KeyValuePair<string, string>[1];
    scores[0] = new KeyValuePair<string, string>("Loading Scores","");
        
    WWW hs_get = new WWW(highscoreURL);
    yield return hs_get;

    if (hs_get.error != null)
    {
        Debug.Log("There was an error getting the high score: " + hs_get.error);
        scores[0] = new KeyValuePair<string, string>("There was an error getting the high score", hs_get.error);
        returnCode(1);
    }
    else
    {
        // split the results into an array
        Regex regex = new Regex(@"[\t\n]");
        string[] rawScores = regex.Split(hs_get.text);

        // Restructure the string array into an array of KeyValuePairs
        scores = new KeyValuePair<string, string>[rawScores.Length / 2];
        int rawScoreIndex = 0;
        for (int i = 0; i < rawScores.Length / 2; i++)
        {
            scores[i] = new KeyValuePair<string, string>(rawScores[rawScoreIndex], rawScores[rawScoreIndex + 1]);
            rawScoreIndex += 2;
        }

        returnCode(0);
    }
}

This first fills the Scores property with the results from the database. Then, because as far as I know the return value of a Unity coroutine is consumed by the Unity engine itself, we need some other way of letting the rest of our code know the result of whether or not the GetScores function worked.

So we instead create an ‘out’ parameter of sorts with the Action<int> returnCode. You could make it more verbose by passing the result of an enum or something, but for my purposes I just wanted a pass-state (0) or a fail-state (1). Yes, I know it could be a boolean. Or a ReturnCode.Success/ReturnCode.Failure enum. And both of those would probably be better than the way I have it. Sometimes it can be hard to escape my time spent scripting with Unix. 😆

In case you want to check that you got all the code or you just want to copy the whole file, here is the entire ScoreboardWebInterface file in all its C# glory:

using System;
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;

public class ScoreboardWebInterface : MonoBehaviour
{
    private string secretKey = "YourSecretKey"; // Edit this value and make sure it's the same as the one stored on the server
    public string addScoreURL = "https://yourwebsite.com/unity/yourgame/addscore.php?"; //be sure to add a ? to your url
    public string highscoreURL = "https://yourwebsite.com/unity/yourgame/display.php";
    
    private KeyValuePair<string, string>[] scores;
    public KeyValuePair<string, string>[] Scores
    {
        get { return scores; }
    }

    // Send the new score to the database
    public IEnumerator PostScores(string name, int score)
    {
        //This connects to a server side php script that will add the name and score to a MySQL DB.
        // Supply it with a string representing the players name and the players score.
        string hash = Utility.Md5Sum(name + score + secretKey);
 
        string post_url = addScoreURL + "name=" + WWW.EscapeURL(name) + "&score=" + score + "&hash=" + hash;
 
        // Post the URL to the site and create a download object to get the result.
        Debug.Log("Submitting score");
        WWW hs_post = new WWW(post_url);
        yield return hs_post; // Wait until the download is done
        Debug.Log("Score submitted");
 
        if (hs_post.error != null)
        {
            Debug.Log("There was an error posting the high score: " + hs_post.error);
        }
    }

    // Get the scores from the database
    public IEnumerator GetScores(Action<int> returnCode)
    {
        scores = new KeyValuePair<string, string>[1];
        scores[0] = new KeyValuePair<string, string>("Loading Scores","");
        
        WWW hs_get = new WWW(highscoreURL);
        yield return hs_get;

        if (hs_get.error != null)
        {
            Debug.Log("There was an error getting the high score: " + hs_get.error);
            scores[0] = new KeyValuePair<string, string>("There was an error getting the high score", hs_get.error);
            returnCode(1);
        }
        else
        {
            // split the results into an array
            Regex regex = new Regex(@"[\t\n]");
            string[] rawScores = regex.Split(hs_get.text);

            // Restructure the string array into an array of KeyValuePairs
            scores = new KeyValuePair<string, string>[rawScores.Length / 2];
            int rawScoreIndex = 0;
            for (int i = 0; i < rawScores.Length / 2; i++)
            {
                scores[i] = new KeyValuePair<string, string>(rawScores[rawScoreIndex], rawScores[rawScoreIndex + 1]);
                rawScoreIndex += 2;
            }

            returnCode(0);
        }
    }
 
}

Scoreboard.cs

So now that we have a database and a way to read and write values into and out of our program, how do we actually use the data? For fetching the scores from the database, you are going to want these two lines of code, which need to be wrapped in a coroutine due to the yield return statement:

// Fetch the global high score list from database
int returnCode = -1;
yield return scoreboardWebInterface.GetScores(status => returnCode = status);

And to save the scores is as simple as calling:

StartCoroutine(scoreboardWebInterface.PostScores(playerName, playerScore));

Since an example is worth 1,000 words (or something like that), this is how I use these in my 1945 game. I call LoadScores when the game starts so that I know that its ready (or failed) well before we need to use the scores.

private IEnumerator LoadScores()
{
    // This initializes the default scores from Scores.cs
    scores = new Scores();

    // Fetch the global high score list from database
    int returnCode = -1;
    yield return scoreboardWebInterface.GetScores(status => returnCode = status);

    if (returnCode == 0)
    {
        highScoreLocation = HighScoreLocation.Global;
        for (int i = 0; i < scoreboardWebInterface.Scores.Length; i++)
        {
            scores.names[i] = scoreboardWebInterface.Scores[i].Key;
            scores.scores[i] = Int32.Parse(scoreboardWebInterface.Scores[i].Value);
        }
    }
    else if (returnCode == 1)
    {
        // An error occurred attempting to get the high scores, so fall back to the local high score list
        highScoreLocation = HighScoreLocation.Local;
        saveStatePath = Path.Combine(Application.persistentDataPath, "scoreboard.sgm");

        // Read the high scores from the local JSON file, if it exists
        if (File.Exists(saveStatePath))
        {
            String fileContents = File.ReadAllText(saveStatePath);
            JsonUtility.FromJsonOverwrite(fileContents, scores);
        }
    }

    for (int i = 0; i < scores.scores.Length; i++)
    {
        scoreTexts[i].text = scores.scores[i].ToString();
    }
    for (int i = 0; i < scores.names.Length; i++)
    {
        nameTexts[i].text = scores.names[i].ToString();
    }
}

And I call CommitScores after the player has completed their run. Because I have multiple ways for the commit to happen, I have a sanity check in there to make sure that it doesn’t get double-committed:

public void CommitScores()
{
    if (!scoresSubmitted)
    {
        if (highScoreLocation == HighScoreLocation.Global)
        {
            if (playerName != null && playerScore != 0)
            {
                StartCoroutine(scoreboardWebInterface.PostScores(playerName, playerScore));
                scoresSubmitted = true;
            }
            else
            {
                Debug.Log("Score has not been saved, as either the name or score values are null.");
            }
        }
        else if (highScoreLocation == HighScoreLocation.Local)
        {
            File.WriteAllText(saveStatePath, JsonUtility.ToJson(scores, true));
            scoresSubmitted = true;
        }
        else
        {
            Debug.Log("The high score location is undefined.");
        }
    }
}

And voila! You should now have the structures required to implement your own server-side high score table similar to the one I have in 1945:

Debugging Tips

The Debug.Log() command in Unity is a powerful tool for debugging problems. When you’re running a WebGL build, any Debug.Log() lines you include in your unity project will appear in the browser console, along with any other errors or warnings that occur. This is a super handy way to identify and fix problems that crop up while trying to set up your code on a website!

In Firefox, you can open the console by pressing Ctrl-Shift-K, in Internet Explorer and Edge by pressing F12, and in Chrome by pressing Ctrl-Shift-J. If you’re using a different browser, sorry, I’m not familiar with how to find your browser’s console. You’ll have to do a web search to figure it out!

You also have to be especially careful that you enter the URL’s exactly. If you type “http://” instead of “https://” or if you don’t include the “www.” in front of it when you need it, you will get an error in the console like “Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at $somesite” indicating that the request was blocked due to violating the CORS security rules.

While there could be other reasons why CORS blocks your request, the reasons I noticed were when I tried to go across from https:// to http:// or when I used an IFrame to embed my game in WordPress. IFrame has some weirdness with accessing external resources, even from the same site. If you want to publish this game on a WordPress site, you will likely want to look at my Embedding Unity Games with Shortcodes page.

Embed Unity3d Games in a WordPress Page

Edit: I have an updated method to embed Unity games in WordPress that makes use of shortcodes and doesn’t need iframes. I recommend you check that solution out first.

If you’re anything like me, you like to show others the stuff you make. And how much easier can it be to share that stuff than by hosting it on your website! Here’s how I embed the games I make with Unity on my website. Note that you have to have a hosted version of WordPress (or somewhere else you can post files to publicly, like a public Dropbox or something).

First off, we need to make a game. This exercise is left up to the reader. 😉

Next, we need to build it into a version that web engines can understand. In Unity, this is called WebGL. (In older versions they had something called “Unity Web Player”. If you’re still using a version that supports that, I recommend you go to Unity3d.com and download a newer version. I’ll even make it super easy… here’s the link!)

WebGL Build

In Unity, go to File > Build Settings… . A window will open. Make sure the checkboxes next to the scenes you want in your game are all selected, and choose WebGL for your platform (the Unity symbol marks the current platform). Since we are planning on publishing it on the web for people to play, have Development Build turned off. Then click Build.

This may take a while depending on the size of your game and the speed of your computer. ¯\_(ツ)_/¯

Once it is done building, you will have a nice folder called “Build” and an html file called index.html.

Upload to the Web

In order for it to appear on our website, we need both the folder and index.html somewhere publicly accessible. If you have your site hosted through Bluehost, they have a convenient file manager you can use (I assume other hosting services offer similar conveniences). Login to your account, click on cPanel in the top navigation menu, and click on file manager under the files section. From there, go to your public_html folder, and create a new folder. I called mine, oddly enough, “unity”. You know, since I’m uploading the games I made with Unity. Because I plan on hosting more than one game, I create a folder inside of the unity folder. Because this is my 1945 game, I call it “1945”. Once its all said and done, I have a nice little set of nested folders that I can use to keep all my web games nicely organized.

Then upload the files using the Upload button.

Now you should be able to get to your game by typing the appropriate url into your web browser. Assuming you put your game files into the public_html/unity/my_game directory, you can get to it by going to http://www.example.com/unity/my_game or https://www.example.com/unity/my_game if you’ve followed along with my SSL tutorial.

Iframe That Game!

Next, open the index.html file with a text editor (or the file viewer on Bluehost) so that we can see the html code. We aren’t making any changes to it, we just need to get some information from it. Find the line that says “gameContainer” that has a width and a height. It should look something like this:

<div id="gameContainer" style="width: 951px; height: 713px; margin: auto"></div>

Make note of the numbers for width and height.

Next, create the page you want your game to appear on. Flip over to the “Text” editor instead of the “Visual” editor. The only thing you need to add for your game to appear is this line of code (putting in the values you found in the index.html file for width and height):

<iframe id="" src="https://www.example.com/unity/my_game" name="" width="###" height="###" frameborder="0" marginheight="0" scrolling="no"></iframe>

So in my case, the code to embed my game looks like:

<iframe id="" src="https://matthewrandolph.com/unity/1945" name="" width="951" height="713" frameborder="0" marginheight="0" scrolling="no"></iframe>

Note that because we’re linking a separate webpage into this one, you technically can browse to the other link to play the game as well. It just won’t have all the fancy WordPress stuff surrounding it. In my case, I don’t mind, since sometimes its nice to be able to have it all by itself. There’s some fancy PHP stuff we can do to be able to have the game files outside of the public_html folder (and therefore inaccessible), but that is a project for another time.

Troubleshooting: If it doesn’t work, head over to the w3schools iframe Tryit Editor and make sure your link is valid. It took me a while to realize I absolutely needed to have “https://” instead of “http://” to get it to work, even though “http://” was a valid link. Double check your url!

Setting Up Google CourseBuilder in the PyCharm IDE on Windows

This is a direct follow-up to my last post, Setting Up Google CourseBuilder in the PyCharm IDE on Mac OS X.

There wasn’t a single source of information I could find to get CourseBuilder to work properly, so I decided to put together this guide in the chance that I need to go through the process again. I make no guarantee nor responsibility that it will work for anyone else. All I know is that it worked for me in my particular situation.

Step 1: Download ALL THE PROGRAMS!

CourseBuilder is based off of Python, so check to make sure Python is installed. CourseBuilder doesn’t play nice with version 3, so make sure you have a version of Python 2. I have Python 2.7.10. You can download it here.

PyCharm, my Python IDE of choice (since the others on my project are using it), can be found here.  Grab the Community Version 4.0.6. For some reason, PyCharm 4.5 doesn’t play nice with CourseBuilder.

To run CourseBuilder, you need to have the Google App Engine SDK. The Engine runs as the server of CourseBuilder. If I understand correctly, it would then be impossible to run without it. Download that here. Grab the “for Python” version.

Finally, download Google CourseBuilder here. I was having issues directly clicking “Export to GitHub,” so click on the Downloads page and download the latest zip version. At the time of writing, it was “Course Builder v1.8.0 (6 April 2015).” Check to make sure your copy has a “lib” folder. One time I downloaded it, there must’ve been a problem since it didn’t download the entire program.

Not necessarily required, but I ended up needing a basic text editor for one step. I recommend Notepad++, which you can download here.

After downloading, install the files that ask to be installed. Which should be all of them except CourseBuilder. Now time to make everything play nice together! This was far easier than it was on my Mac.

Step 2: Follow the Directions!

Here, I just followed the directions on this website. In case something happens to it, though, I’ll re-post it here.

Configure python GAE debugging

This is the minimum Run/Debug configuration that will enable you to debug your python for GAE application. It must be set on a per project basis. You’ll need a pre-existing GAE project for this to work. The prerequisites at the end of this post explain how to set up an example GAE application.

    1. Open the GAE project in PyCharm:
      1. Select menu item File > Open…
      2. Select your base project folder (the one which contains an app.yaml file). For our examples we’ll be using the folder C:myproject, which we’ll refer to as <myproject_path>.
    2. Add a new python configuration:
      1. Run > Edit Configurations…
      2. Click the green plus sign “+
      3. In the Add New Configuration list, select Python.
      4. Specify the configuration parameters:
        1. Name: GAE_config
          Choose a name, which we’ll refer to as GAE_config
        2. Script: <GAE_install_path>dev_appserver.py
          Here you need to enter the location of the dev_appserver.py file installed in your Google App Engine SDK. On Windows the default installation is C:Program Files (x86)Googlegoogle_appenginedev_appserver.py. We’ll refer to this location as <GAE_install_path>
        3. Script parameters:
          –automatic_restart=no –max_module_instances=”default:1″ .
          These are the minimum arguments needed for the debugging to work.
          Ensure you include the final argument, “.“: it means the current path, i.e. the working directory in this case.
        4. Working directory: <myproject_path>
        5. Tick the Share box.
          This creates configuration file <myproject_path>.idearunConfigurationsGAE_config.xml, which can be shared with other users and put in version control.
        6. Press OK

PyCharm python run/debug configuration for Google App Engine

  1. Check the python debugger settings:
    1. File > Settings…
    2. Expand the tree to Build, Execution, Deployment > Python Debugger
    3. Ensure the option Attach to subprocess automatically while debugging is ticked.

The basic PyCharm configuration for python GAE debugging is done. To debug, add a breakpoint in the python file and run in debug mode.

Enable code navigation for GAE libraries

To enable PyCharm’s code navigation and completion, we need to add the GAE SDK to PyCharm’s list of External Libraries.

  1. Close PyCharm
  2. Create a GAE SDK library file:
    1. In <myproject_path>.idea, create a directory named libraries.
    2. In <myproject_path>.idealibraries, create an xml file named GAE_SDK.xml
    3. Copy and paste the xml code below in GAE_SDK.xml:
      <component name="libraryTable">
        <library name="GAE_SDK" type="python">
      	<CLASSES>
      	  <root url="file://C:/Program Files (x86)/Google/google_appengine" />
      	  <root url="file://C:/Program Files (x86)/Google/google_appengine/lib/django-1.5" />
      	  <root url="file://C:/Program Files (x86)/Google/google_appengine/lib/jinja2-2.6" />
      	  <root url="file://C:/Program Files (x86)/Google/google_appengine/lib/webapp2-2.5.2" />
      	</CLASSES>
      	<SOURCES />
        </library>
      </component>
      
    4. Update the paths C:/Program Files (x86)/Google/google_appengine as needed to point to your GAE install location. See the next section if you’d like to use a per user macro path variable instead. To add more GAE libraries, add them to the list (in a similar way to webapp2, django and jinja). Save.
  3. Update the project’s .iml file with the GAE SDK reference:
    1. Open <myproject_path>.ideamyproject.iml
    2. Add the line below to the component element and save.
      	<orderEntry type="library" name="GAE_SDK" level="project" />
  4. Open PyCharm. GAE_SDK should be listed under the External Libraries in the Project viewer (View > Tool Windows > Project). In the python code, you can open class definitions (right-click on class) and code completion works.

After this, I set it up to push directly to my GitHub repository. To do so:

  1. VCS > Import into Version Control > GitHub
  2. Give PyCharm your username and password
  3. Add a master password if you have one, otherwise leave it blank
  4. Select a name for you repository (probably coursebuilder)
  5. Use VCS > Commit Changes to push modifications to your repository.

At this point, I had a “no module named lxml.html” error, the very same as when I tried with my Mac.

To fix this, I used PyCharm’s built-in library manager. And it worked this time!

  1. File > Settings…
  2. Expand Project: coursebuilder > Project Interpreter
  3. Click the green plus sign “+
  4. Typed “lxml” in the search bar and highlighted lxml in the menu
  5. Clicked Install Packages.

The library downloaded, installed, and then the program ran! How’s that for easy?

Setting Up Google CourseBuilder in the PyCharm IDE on Mac OS X

There wasn’t a single source of information I could find to get CourseBuilder to work properly, so I decided to put together this guide in the chance that I need to go through the process again. I make no guarantee nor responsibility that it will work for anyone else. All I know is that it worked for me in my particular situation.

Step 1: Download ALL THE PROGRAMS!

CourseBuilder is based off of Python, so check to make sure Python is installed. CourseBuilder doesn’t play nice with version 3, so make sure you have a version of Python 2. By default, it should be included on Mac. I have version 2.7. Perfect!

PyCharm, my Python IDE of choice (since the others on my project are using it), can be found here.  Grab the Community Version 4.0.6. For some reason, PyCharm 4.5 doesn’t play nice with CourseBuilder.

To run CourseBuilder, you need to have the Google App Engine SDK. The Engine runs as the server of CourseBuilder. If I understand correctly, it would then be impossible to run without it. Download that here. Grab the “for Python” version.

Finally, download Google CourseBuilder here. I was having issues directly clicking “Export to GitHub,” so click on the Downloads page and download the latest zip version. At the time of writing, it was “Course Builder v1.8.0 (6 April 2015).” Check to make sure your copy has a “lib” folder. One time I downloaded it, there must’ve been a problem since it didn’t download the entire program.

Not necessarily required, but I ended up needing a basic text editor for one step. I recommend TextWrangler, which you can download here.

After downloading, move the applications that ask to be moved to your Applications folder. Apple sure makes installs easy. Now time to make everything play nice together!

Step 2: Set Up Run/Debugging in PyCharm

I used a lot of information from this website to figure this step out. It was written for Windows though, so I had to change a few things.

The first thing you’ll notice after you open PyCharm is a dialogue box that says “Do you want the application “PyCharm CE.app” to accept incoming network connections?” I believe you have to select yes for it to be able to work properly with Version Control, the updater, or some other programs.

Now to set up run/debugging:

  1. Open the GAE project in PyCharm:
    1. Select menu item File > Open…
    2. Select your base project folder (the one which contains an app.yaml file). For these examples I’ll refer to it as <myproject_path>.
  1. Add a new python configuration:
    1. Run > Edit Configurations…
    2. Click the green plus sign “+
    3. In the Add New Configuration list, select Python.
    4. Specify the configuration parameters:
      1. Name: GAE_config
        Choose a name, which we’ll refer to as GAE_config
      2. Script: <GAE_install_path>dev_appserver.py
        Here you need to enter the location of the dev_appserver.py file installed in your Google App Engine SDK. On Mac OS X the default installation is /Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/dev_appserver.py. We’ll refer to this location as <GAE_install_path>
      3. Script parameters:
        –automatic_restart=no –max_module_instances=”default:1″ .
        These are the minimum arguments needed for the debugging to work. Don’t ask, I don’t know why.
        Ensure you include the final argument, “
        .“: it means the current path, i.e. the working directory in this case.
      4. Working directory: <myproject_path>
      5. Tick the Share box.
        This creates configuration file <myproject_path>.idearunConfigurationsGAE_config.xml, which can be shared with other users and put in version control.
      6. Press OKgae-mac-preferences
  1. Check the python debugger settings:
    1. PyCharm > Preferences…
    2. Expand the tree to Build, Execution, Deployment > Python Debugger
    3. Ensure the option Attach to subprocess automatically while debugging is ticked.

At this point, the basic PyCharm configuration for python GAE debugging is done. To debug, add a breakpoint in the python file and run in debug mode. However, I had a few problems when I tried to run it.

First, I got an error that said lxml was missing.

Lxml is a library of some sort. PyCharm actually has a robust library import system built directly into it. To find it:

    1. PyCharm > Preferences…
    2. Expand the tree to Project:coursebuilder > Project Interpreter
    3. Check to see if lxml is included in the list of libraries.

In my case, it was missing, so I tried to add it to the libraries.

    1. Click the little “+” in the lower-left corner
    2. Type “lxml” in the search bar, and select it
    3. Click Install Packages.

I get a “pip could not be found” error. Great.

Pip is the Python library downloader. Apparently, it’s not included in Python 2.7 by default, so open up a Terminal and put the following command in:

sudo easy_install pip

It will then ask for your password, and install pip for you!

Trying the above method to install lxml, I received another error, and the only way I could figure out to install lxml was to use a workaround, utilizing xcode—the Apple development suite. I don’t know if it will work without xcode explicitly being installed on your machine or not.

sudo CPATH=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/libxml2 CFLAGS=-Qunused-arguments CPPFLAGS=-Qunused-arguments pip install lxml

Now my CourseBuilder website runs correctly! Press the green play button to run the server. To see your website, you click one of the three links will appear in the terminal. By default, it runs on port 8080.

Setting up auto complete, on the other hand, is another project for another day.

A Beautiful Day in the Neighborhood. England, Day 20

The fire alarm works! We found this out at about 2 o’clock last night. Fortunately, there was no fire (that I was aware of, at least). I poked my head out into the hallway to see what was going on. At the same time, so did everyone else on my floor. The alarm stopped. We all simultaneously turned around and went back to bed.

Today was a free day, so I hopped on a bus down to Westminster Pier. I then bought a one-way ticket for a river cruise to Greenwich. One of the staff of the boat gave us a tour of the city as we made our way down the river. He pointed out all sorts of interesting sites and gave lots of neat information.

London is the smallest city in the world. It is only 1 square mile in size. It’s surrounded by Westminster, Greenwich, and a few other cities and towns, which is what makes it feel like a big city. We saw Sir Ian Mckellen’s pub. Also a pub called The Mayflower (which was actually owned by the family of one of the Pilgrims on the Mayflower). And the place where, in the time of pirates, criminals given the death penalty would be drowned. During low tide, they would be tied to stakes on the beach. As the tide rose, they would be trapped under the surface of the water and suffocate. Sounds pretty awful.

wpid-img_20150530_113613707

We passed under the wibbly-wobbly bridge, which was closed twelve hours after its grand opening because pedestrians walking along it would be seasick before reaching the other side. It took huge amounts of money to have it repaired.

We even passed by a few battleships!

wpid-img_20150530_114949698

We passed under a bridge financed by John Harvard (of United States fame). We saw a really cool rowboat, but I didn’t catch what the guide had said it was.

The river tour took an hour, and I’m glad I took it to get there. Highly recommended.

When I arrived in Greenwich, I was feeling peckish, so I wandered over to the Greenwich Marketplace. The marketplace was a big open-air market, with a bunch of vendors of food and homemade goods. I wandered a while—it all looked super tasty! I ended up getting Indian seafood curry and beef stir-fry on a bed of rice. Yum!

wpid-img_20150530_123916513

I then walked over to the National Maritime Museum, where I saw all sorts of cool naval stuff. There was a lot of information on the East India Trading Company. It was amazing to see how much was imported, and then after the rise of industrialization, how much more was exported.

wpid-img_20150530_130217527

After walking through the museum, I was running short on time. I made my way to the Greenwich National Rail Service Station, and bought a one-way ticket to downtown London, which on the ticket was titled “London Stations.”

I then met up with the others at the hostel, and we went to a pub to have dinner. I ordered a medium-rare steak (which arrived medium, of course—there was only one cook working and 30 meals to prepare though, so I guess it can be forgiven), and an excellent sticky toffee pudding. I didn’t realize that pudding in England is more like a cake.

I’m going to miss England.

Theatre, Why Can’t You be This Fantastic in Duluth? London, Days 18 and 19

On Thursday, the theater group and the literature group split for the day. The literature group went to a graveyard to see some famous corpses. The theater group participated in a super-awesome-cool stage combat workshop.

We learned how to slap, punch, and choke our fellow actors safely. It is completely different from martial arts. Its to be expected, of course. In martial arts, the point is to hurt the other person.

After, a few of us went to take pictures. We went by the lions outside the National Gallery, and then to Westminster so I could get a picture at one of the oversized phonebooths. For dinner I had an acceptable pot pie.

wpid-img_20150528_163909240

In the evening, we saw The Play That Goes Wrong. I had no idea what to expect. When we reached the theater, one of the reviews they had posted read “ITS AS IF THE MOUSETRAP HAS BEEN TAKEN OVER BY MONTY PYTHON.” This was going to be good.

wpid-img_20150528_185946912_hdr

My goodness, good was an understatement. I loved it so much I purchased the script at the box office. I don’t even know what words to say about it. It was hilarious. It was fun to watch. I was crying I was laughing so hard. It was amazing. And it was so much better having seen The Mousetrap beforehand too. I felt I caught more of the murder mystery nuances there, as well as the parodies of specific characters.

7 out of 5: Would Recommend to Friends.


Friday. Went to the Victoria and Albert Museum. Saw some stuff. The old statues and stuff were cool, especially the pair of statues “Valor crushes Cowardice” and “Truth slays Lies.” They even had an Oculus Rift!

wpid-img_20150529_120251675

After eating, I picked up a piece of German Crumb Cake, a piece of Clotted Cream Fudge, and Cream Fudge. They were all amazing. I also had a major sugar crash soon after. Oops.

We then went to the Tate Modern, an art gallery for modern art. I’m not much of a modern art person, so I was only there for about 20 minutes before I wandered back to the hostel to recover from my sugar crash (I did see everything before I left, promise!). Maybe I’ll check out the Tate Britain instead sometime.

Then we saw an adaptation of Everyman. Fantastic. I gave it a standing ovation, the only one I have so far this trip. If I gave The Play That Goes Wrong a “7 out of 5,” then Everyman gets a “9 out of 5.” It was thought-provoking: it makes you consider everything about yourself. I don’t want to talk too much about it, so as to avoid giving many spoilers. One thing I will say about it though, is that the adaptation was beautifully done. I was somewhat familiar with the play beforehand (remember, I learned my lesson after Les Mis!), and I was expecting a Shakespearian-style or Reconstruction-style play. Not so. Everyman blew my expectations right out of the water. This was the only play in England that I awarded a standing ovation. It deserved it.


wpid-img_20150529_212221694

Needless to say, I purchased another script from the gift shop.

Fortunately, the employee was restocking the shelf when I was looking for it, otherwise I wouldn’t have seen that it was for sale. The adapted version!

Luxury Accommodations! England, Day 17

The hotel we stayed at last night was excellent. Soft beds. Quiet atmosphere. In-room shower. Tres bien.

The bed was actually too soft for me, as I like to sleep laying on my back and there wasn’t a lot of support. I didn’t think I’d ever say that a bed was too comfortable for me to sleep comfortably!

We got a little bit later start today, having breakfast around 10:15 or so. Hot breakfast! I had the Full English Breakfast, which consisted of bacon, a sausage, mushrooms, an egg (I had it poached), and a hash-brown triangle thing, like you would get at Arby’s (except this one was actually good). Both the clotted cream and jam was fantastic, and I had about six pieces of toast just so I could have more of the toppings. Maybe that’s an exaggeration. Maybe its not.

After breakfast, we toured the house Anne Hathaway (Shakespeare’s wife, not the actress) grew up in, as well as the gardens outside the house. The house was neat to walk through, and I managed to not hit my head on anything.

wpid-img_20150527_113953962

In his will, Shakespeare had left his second-best bed to his wife after he passed on. Historians are still trying to figure out if that was a good or bad thing. Beds, in his time, were a huge wealth image, like luxury cars are today. Usually the first bed goes to the eldest son. Since he also left a third of his estate to her alone, it was probably intended to be a positive thing.

wpid-img_20150527_112446386

The gardens were pretty to walk though. There was a really cool photo opportunity, but I didn’t take it. There was a round hedge surrounding a beautifully cut lawn, with one person laying in the grass reading. The way the individual was laying contrasted with the cut of the lawn and was just off center of the circle created by the hedge. The picture would have turned out beautifully, but since there was only one person laying in the grass I didn’t feel comfortable with it. Probably for the best.

wpid-img_20150527_120946835

We then went back to London. The trip was fairly uneventful, and I think I slept through most of it.

After arriving in London, eight of us decide to see the place where Sherlock is filmed. I’ve only seen a part of one episode, so I wasn’t really sure what we were looking for. Turns out it was the external shot of the flat he lives in (in the show, of course), and the cafe he eats breakfast in every day. Now when I see the show, I’ll be able to say I’ve been there!

wpid-img_20150527_153302829

After having a bite to eat (it was a pretty terrible chicken burger with avocado with a side of not very good onion rings, but the chips were good), I went back to the hostel to change for the show.

The Elephant Man was very thought provoking. It was a short play, about an hour or so in length, about a man with a terrible disorder that makes him look mangled and have difficulty functioning. Everyone felt sorry for him by the end of the show, but I expect most people, back in the real world, will continue doing their best to avoid people like him regularly. Its quite sad, really.

wpid-img_20150527_212714029

 

Rolling Hills, Keys, and Wealthy Merchants. England, Day 16.

I can’t continue writing “London, Day X” since we aren’t in London for a few days!

The place we stayed at last night was a nice one. The guys were all in a flat in the backyard—it was probably a guest house when the building was residential. We managed to lock ourselves out. Fortunately, the manager was able to let us back in, even though we had left the key in the keyhole. Last time the key was left in, he said, a small child had to crawl through the window to open it. There were no windows open yet!

wpid-img_20150525_214021861

Today, though—super busy! In the morning, we toured a Roman bathhouse museum after a wonderful breakfast. Full service!

The bathhouse museum had a ton of neat artifacts and remains from the bathhouses. It even had the original bath, still in working order! I spent way too much time going through the museum part though, and had to rush through the bathhouse part. Oops! Here too, was an audio guide, narrated by the same individual who narrated the Stonehenge one.

wpid-img_20150526_093311751

After the bath, we were instructed to meet back at the bus station (after having eaten, of course). I managed to walk in the opposite direction and was completely turned around. Fortunately, I ran into a few others that knew the way back. So much for wanting to get books before we left Bath!

The bus ride to Stratford-upon-Avon was magnificent. I took at least 500 pictures between Bath and Stratford. They were all taken through the bus window, so I’ll have to see what they look like on a bigger screen than my phone.

wpid-img_20150526_114913080_hdr

When we arrived in Stratford, we were led on a tour of the city. Stratford is known as the city of Shakespeare, so much of what we covered were things about him. We saw his gravesite, the house he grew up in, and his school. We also learned about the Tudor architecture style and about how, like London, most of the wooden buildings were burned down in fires. Stratford is also the hometown of Thomas Crapper, the inventor of the modern toilet. Just thought I’d throw that out there.

wpid-img_20150526_144331916

We also toured the Holy Trinity Church. I feel like we should have toured all the churches in reverse order, so that they would be getting bigger and more magnificent, instead of smaller and more lack-luster. Compared to Westminster and Notre-Dame, this wasn’t much to see. There was, however, a window inscribed “The Gift of America to Shakespeare’s Church.” This was given to them by the American ambassador in 1896.

After we checked into our hotel, a number of us went to have dinner. Most of the guys wanted to have the “Shakesbeer” that one pub was advertising, so we went there to eat. I was expecting it to be super touristy, but it seemed like an authentic pub for locals, so I was pleasantly surprised.

After the meal, we decided we wanted to get ice cream, so we wandered around the city for about fifteen minutes. Its incredible how when you aren’t looking for something, it seems to be everywhere and when you are, they all disappear. In Bath, there was at least 4 ice-cream shops on each block. Here, nothing. Eventually, we end up walking past the pub we ate at. Lo and behold, if we had turned the other direction in search, we would have seen a gelato shop right next to the pub…

Then, we saw The Jew of Malta at The Swan Theater of the Royal Shakespeare Company. This was the most comfortable theater we’ve been in yet. I had plenty of leg room (when I was sitting back in my seat, my feet didn’t touch the floor—fantastic)! There was a bar to lean forward on to see over the balcony. Because of my height, I could see the stage perfectly from my seat. The play itself was entertaining too. I think I’m the only member of our group that thought this was better than The Merchant of Venice, though.

wpid-img_20150526_221101098