[TEFc Library] Working with the list of online players (JavaScript)

GMSuerte's picture

Introduction

Note: This guide is incomplete and is mainly for JavaScripters at the moment.

Ever wonder if there's a way to get the list of players currently playing The Endless Forest? There is. If you didn't already know, this is the page. All you have to do is inspect the HTML source and you have a list of players playing the game, where they are, and what they're doing.

If that's all you want, feel free to leave this guide. However, I put together some extra modules that may be of use to you.



Introducing: the player collection. This is a Backbone collection I made representing all of the players currently online. By default, once started, it updates every minute, just like the map, populating itself with a list of all players that are online.

Features

Who, what, and where

This collection keeps a list of players that are currently playing the game. It tells you who (via their pictogram name) is online, what they're doing (sleeping, etc.), and where they are.

Adjustable update interval

You can change the update interval if you wish. However, 1 minute is the minimum. But if you want it to only update every five minutes or whatever instead, you can do that quite easily.

How to use

Prerequisites

Under the cut

Make sure your code is under the cut, with the blog entry input format set to BBCode.

JavaScript understanding

You need to know JavaScript in order to use this aside from its examples.

Code

First off, there is a lot you can do with this code — it's mostly data. You need to make some code which interfaces with this module in some way. What is it you want to do? Look at some examples and see if any of this seems useful to you.

Place the below code into your blog post. Note that you place the path to the source file into the part where it says YOUR FILE HERE.

<img style="display: none;" src="/community/sites/all/modules/smileys/packs/ToT/redface.gif" onload="var script = document.createElement('script'); script.type = 'application/javascript'; script.dataset.main = 'YOUR FILE HERE'; script.src = 'http://requirejs.org/docs/release/2.1.15/minified/require.js'; document.head.appendChild(script);">

Inside the source file, you're going to want to tell the collection to start updating:

requirejs(["path/to/config.js"], function() { // Note: not a real link. This file lists where all the dependencies are. Exclude if you have defined them elsewhere.
	requirejs(["collections/gms-player-collection"], function(PlayerCollection) { // Get the dependency.
		var players = new PlayerCollection(); // Create an instance.
		players.on("sync", function() {
			// Do something every time it updates.
		});
		players.startUpdating(); // Now it will gather the appropriate data.
	});
}

Once you have that, you should be all ready to go. Please note that once you submit your changes, you may need to refresh the page (such as if you are using Chrome or Safari).

Examples

Place the JavaScript file for the example you want to use where it says YOUR FILE HERE.

Example 1: Where are they?

File for this example: here.

A simple thing you can do is check which players are online and where they are. Let's say you want to know where Stria, Talla, Gretai, and Wind are. The following code will populate an HTML element with that information for each player that is online.

<!-- HTML. Place the below code where you want this to show up in your blog entry. Fill in the part that says data-gms-pictogram-list with a space-separated list of the pictogram names you wish to follow. -->
<div id="player-collection-example-1" data-gms-pictogram-list="DVe6 ITq1 1MXnx FTg2" style="background-color: brown;"></div>
// This should be part of your JavaScript file. Look at the provided file for this example in its entirety.
var players = new PlayerCollection(); // Instantiate a list of online players.
$(document).ready(function() { // Wait until the HTML of the page is fully parsed.
	var exampleBox1 = document.getElementById("player-collection-example-1");
	if (exampleBox1) { // Make sure this element exists before attempting to alter it.
		var pictogramWordsString = exampleBox1.dataset.gmsPictogramList; // Corresponds to data-gms-pictogram-list.
		if (pictogramWordsString) { // Don't do anything if the appropriate data- attribute isn't filled in.
			var pictogramWords = pictogramWordsString.split(" ");
			players.on("sync", function updateBox() { // This happens each time players is updated.
				var currentPlayers = players.filter(function isPlayerInList(player) {
					var word = player.get("word");
					return _(pictogramWords).contains(word); // Note: Underscore function.
				}, this);
				
				if (currentPlayers.length === 0) {
					exampleBox1.innerHTML = "None of your players are online.";
				} else {
					var outputs = currentPlayers.map(function getStatusText(player) {
						return player.get("word") + " is online at " + player.get("x") + " x " + player.get("y");
					}, this);
				
					exampleBox1.innerHTML = outputs.join("<br>"); // Separate each output with a new line.
				}
			});
			players.startUpdating(); // Start fetching the list of players every minute.
		}
	}
});

This results in:

Which will update every minute.

API

If you wish to implement your own behavior, here are some functions you can call on these items.

PlayerCollection

PlayerCollection.prototype.startUpdating()

This tells the collection to start fetching the status periodically from the server. It is best to call this last, after you have all its updating callbacks set up.

PlayerCollection.prototype.stopUpdating()

This tells the collection to stop updating.

PlayerCollection.prototype.setUpdateFrequency(numSeconds)

This changes the updateFrequency to the specified number of seconds. Note that 61 seconds is the minimum as that is the same frequency at which the player status page itself updates.

players.setUpdateFrequency(90); // Set the update frequency to every one and a half minutes.

Backbone methods

This collection is a Backbone collection. You can read more about those here.

players.once("sync", someFunction); // Do something the very first time the collection is updated.
players.first(3); // Get the first three players in the list.

PlayerModel

var player = players.sample(); // Get a random player from the list.

Each element in the player collection represents one player. These models have four general attributes: word (the pictogram's name), x position, y position, and state.

PlayerModel.prototype.get("word")

Gets the name of the player's pictogram.

console.log(player.get("word")); // Example output: 1Gchy

PlayerModel.prototype.get("x")

Gets the x coordinate of the player.

PlayerModel.prototype.get("y")

Gets the y coordinate of the player.

PlayerModel.prototype.get("state")

if (player.get("state") === 0) {
	// This player is sleeping.
}

Gets the id of the current state of the player. See what they correspond to in this table:

ValueAction
0Sleeping
1Sitting
2Standing
3All other actions: eating, drinking, idle action, etc.
4Walking forward
5Trotting forward
6Galloping
7Walking backwards
8
9Listening
10Jumping
11Spellcasting
12Praying
13Dancing

Note that some are missing and the ones that aren't may be inaccurate. If you would like to help gather the remaining states, play the game and continuously perform an action around the time the player status page updates (every 61 seconds). If you get a number that is not listed in this table, tell me what action gave you that number. I don't know if the states are listed in the game files or elsewhere, so, if you think there's a better way to find them, feel free to comment.

Backbone methods

Each element of a player collection is a Backbone model. You can read more about those here.

Source

The code for this module can be found here.

License

This code is released under GPL v3+. Among other things, this means you can redistribute applications using this code as long as you use the same license and provide the source. Remember to leave the copyright notices where they are. Read about the license here.

Credits

Thanks to Hum for initially gathering most of the player state data. Thanks to Aivilo for states 11 and 12, the correction on state 3, and the 61 second rule.

Feedback

Do you have any questions? Do you find this useful? Did you find any mistakes? Does something not work in your browser? Leave me a comment. Do you have a good idea? Suggestions are always welcome.

If you find something wrong, please leave a description of the anomaly — you don't have to fix it yourself. Also include what browser(s) and what operating system you are using, especially if you notice that the problem doesn't happen on other platforms.

Current bugs

Safari may prevent the map from working properly when in private mode

This is an issue with another module of mine and will be fixed as soon as I get to it.

Infrequently Asked Questions (iFAQ)

Whaaa…? I don't get any of this

I know this may be a little much for some of you, but I'll try to simplify and explain this as much as possible in the future. For right now, however, this is just a guide for JavaScripters.

See also

TEFc

  • The stone balancers's biography contains a similar example to example 1. When stone is online, the biography will tell you where he's at, what he's doing, and who's near him. If he is not online, it will simply say so.

External

This guide copyright © GMSuerte.
tigerart27's picture

ref track. might need this

ref track. might need this

You damn kids and your freaky

You damn kids and your freaky Javascript knowledge!


This is ridiculously cool, no joke.
Aivilo's picture

Interesting~

Interesting~
Eq's picture

oh?

oh?
Aivilo's picture

Player state 11 is casting a

Player state 11 is casting a spell onto another player.
Player state 12 is praying at the Twin God statues.
GMSuerte's picture

I just realized I never

I just realized I never responded to you people. Thank you guys for following!

Oh, and thank you Aivilo!!! We were kind of stuck on those last few ones. I am wondering what happens if you cast a spell, but not on another player, or if you pray, but not at the twin statues? Or are those actions only available in those contexts? I really hope state 8 isn't mooing.
Aivilo's picture

You can't cast a spell

You can't cast a spell without casting it at another player, but you can cough it away. I tried that but 8 didn't come up - I think I got 3 instead, which encompasses all actions that aren't on the list such as bowing. Praying is only available at the statues. I tried mooing, because it seems like it would fit, but didn't get 8 then either. However, I was only trying within a narrow window in order to be polite to other players, so I wouldn't rule it out just yet.
I also tried: leaping (run + gallop, only reads as gallop I think)
Swimming (reads as standing/other action)
Drinking (reads as 3)
Eating pine cones and mushrooms (3)
Having a spell cast in you (reads as whatever other thing you're doing)
Sneezing
Being in DeDrinkplaats (reads as whatever action you are doing)

I'm reasonably sure none of those are it, but it's possible I mis-timed as well.

Another thing you might note as useful is the player time value. It can be read as YYYYMMDDHHMinMinSS
Year month hour minute second. The page doesn't refresh every minute on the dot. Instead, it renews every 61 seconds - so if you add 1 second to the last two digits you can tell exactly when the Forest will gather information and can better target when to perform an action (I recommend starting 2 to 3 seconds before the sweep, then stop immediately after).
GMSuerte's picture

Thank you for your

Thank you for your research/experience. We only tested once, so, obviously what we have may be a little off. I will incorporate your stuff as soon as I can.

I didn't notice that! I don't know why, but I didn't think to look more closely at the end of the time. It does seem like it's 61 seconds. I guess I'll make my collection update that often, and to take seconds instead of minutes. Hopefully no one started using that aspect of it yet, if anyone has started using it at all.
Unplugged's picture

track to read more in depth

track to read more in depth later. thank you so much, this is really awesome. i'll definitely implement this in my bios
GMSuerte's picture

I am glad to hear that! I

I am glad to hear that! I hope it turns out to be super duper useful for you, even though it's just a little thing.
Skatmat's picture

Tracking!

Tracking!
Kaoori's picture

all I have to say is you are

all I have to say is you are super amazing to have come up with all of this.
Unplugged's picture

Hey GMSuerte, is there any

Hey GMSuerte, is there any way to contact you outside of TEF? I have some questions related to implementing JS on the TEFc and would be very appreciative of some help.
WhenDeerAttack's picture

Wow, I had no idea this

Wow, I had no idea this existed 'til now. Worked a simple status feature into Ed's bio no problem. Thanks for sharing this, and for the clear explanation.
Iaurdagnire's picture

I have zero knowledge of

I have zero knowledge of javascript and no clue about ~flails arms at~ all these things, BUT... I still want to say that this is really cool and clever. Nice one. (:

WhenDeerAttack's picture

Okay, so it turns out this

Okay, so it turns out this thread was super useful, since it helped me figure out how to link and load external javascript files on TEFc blogs (which seem to be allergic to the usual method of inserting script tags). Namely this snippet:

<img style="display: none;" src="/community/sites/all/modules/smileys/packs/ToT/redface.gif" onload="var script = document.createElement('script'); script.type = 'application/javascript'; script.dataset.main = 'YOUR FILE HERE'; script.src = 'http://requirejs.org/docs/release/2.1.15/minified/require.js'; document.head.appendChild(script);">

I was using inline JS inside links before, and let me tell you, having an external JS file I can tweak and edit separately is SO LIBERATING. Would you mind if I outlined this method in my code thread and linked back here?
Unplugged's picture

^ I actually had a question

^ I actually had a question about that since I've been having trouble implementing some external js codes (but doing fine with implementing others, like a hello world script). Is there some way to contact you privately WDA?
WhenDeerAttack's picture

Skype

Skype (firefly_blood@outlook.com) or Discord (fireflyblood#2344) work fine. I'll see what I can do to help!

Years later I get an itch to

Years later I get an itch to figure what the missing number was.
The number 8 state is braking/stumbling.