This wiki is archived from 2021-09-05

Example Mod Chat Alert

From Planetary Annihilation: TITANS and Classic PA Wiki
Jump to navigation Jump to search

File:Titans-icon.png Example Mod: Chat Alert

This example will demonstrate how to make a client mod that changes how the user interface works.

File:Gold-rank-icon.png Chat Alert

Here we will modify the inner workings of the UI, which is based on HTML and JavaScript. We are going to make a mods that plays an audible alert when somebody types a new message in-game or in the lobby. This will also demonstrate how to add settings for the mod in the PA Settings screen.

File:Gold-rank-icon.png Mod structure

To create a new local client mod, navigate to the Planetary Annihilation Data Directory and if it does not already exist, create a new directory called "client_mods". Inside that directory create a directory for our new mod, for example: "com.pa.you.chat-alert". And inside of that directory, create a new text file called "modinfo.json". This will contain the information about our mod. It should look like this:

{
  "context": "client",
  "identifier": "com.pa.you.chat-alert",
  "display_name": "Chat alert",
  "description": "Audible alerts when somebody type in lobby or in-game chat.",
  "author": "You",
  "version": "1.0",
  "build": "105067",
  "date": "2017-12-10",
  "signature": "not yet implemented",
  "forum": "",
  "priority": 100,
  "icon": "",
  "category": ["gameplay", "lobby", "ui"],
  "scenes":
  {
    "new_game":
    [
      "coui://ui/mods/com.pa.you.chatalert/new_game.js"
    ],
    "live_game_chat":
    [
      "coui://ui/mods/com.pa.you.chatalert/live_game_chat.js"
    ],
    "settings":
    [
      "coui://ui/mods/com.pa.you.chatalert/settings.js"
    ]
  }
}

See here for more details on the meaning of these entries. However, important for this mod are the entries for `"scenes"`. Here will tell the mod manager which parts of the UI we will inject new JavaScript into.

Next, we are going to add the files we are going to add. Since we are defining new files, we should take care that we do not accidentally shadow existing PA files or of other mods. One way of doing that is adding our own subdirectory. So create a new folder "ui" and inside that folder create "mods", and inside of that folder create "com.pa.you.chat-alert". By reusing our mod identifier like this, we can be certain we are not affecting anything else. Notice that we already used this directory structure in the `"scenes"` above.

Now we should have the following structure:

File:Gold-rank-icon.png Adding JavaScript

Now we make three JavaScript files. Open a text editor and copy-paste the following text:

(function() {
  console.log("Hello world!");
})();

Save this text to three files called "new_game.js", "live_game_chat.js", and "settings.js" in the directory we created above. The function `console.log` on the second line will print a message to the log so that we can check if the mod is actually loaded. The structure on the first and third line are not strictly necessary, but it is good practise because it allows any variables or functions you might declare to remain "local". That means that they cannot interfere with other mods or PA in unexpected ways.

Now we should have the following structure:

Now we will test if this works and in doing so introduce the debugger tool that comes with PA which is in invaluable tool for developing mods that modify the UI. First enable the mod by starting Planetary Annihilation and going to Community Mods. Under the Installed tab, you should see the mod you just created. Click on it and click the Enable button.

File:Gold-rank-icon.png Coherent Debugger

Our mods modifies the Settings, Lobby, and the in-game Chat interface. So if we go to any of those, our mod should be called. But first we need a way to see the log in the first place. For that, we can use the Coherent Debugger. You will find it at the Planetary Annihilation Installation Directory/Coherent/Debugger/Debugger on Linux and probably similar locations on Windows can macOS. First start Planetary Annihilation and navigate to the Settings screen. Then start the debugger. It will start with a blank screen, but click on "Go" to connect to Planetary Annihilation. You should then see the following:

Coherent-debugger-main.jpg

Click on "Game Settings". Here it will display the HTML code of the settings screen in PA. Now click on the "Console" button in the toolbar at the top of the screen. That's where the `console.log` messages or any errors if it did not work. It should look like this:

Coherent-debugger-settings.jpg

Notice the "Hello world!" being displayed there. That means that the mod is active and working. You can also check the lobby and the live game.

File:Gold-rank-icon.png Investigating Planetary Annihilation User Interface files

Before we can add the scripts to modify the UI, we first need to figure out how the UI works in the first place. Planetary Annihilation uses HTML and JavaScript for its UI, but it relies heavily on a JavaScript library called Knockout.js. It is very instructive to read the documentation for that library.

The files for the UI can be found in Planetary Annihilation Installation Directory/media/ui/main/game. There are a lot of subdirectories here with one for each screen. Let's first focus on the Game Lobby, the files for which can be found in new_game. Inside that subdirectory, there are two files of interest, "new_game.html" and "new_game.js". If you open the HTML file and search for the word "chat", then you will eventually find this:

<!-- LOBBY CHAT -->
<div class="section game_chat">
  <div class="form-group" id="chat-bar">
    <div class="section_header" for="chat">
      <loc>Chat</loc>
    </div>
    <div style="height: calc(100% - 58px); position: relative;">
      <div class="chat_container">
        <!-- ko foreach: chatMessages -->

So that looks promising. If you read the Knockout documentation you may recognize what ko foreach does; it uses the observable "chatMessages" to insert HTML. So this means that if the observable "chatMessages" changes, then probably a new chat message has been added and we need to play a sound. If we look in the JS file, we see that "chatMessages" is actually a observableArray. So now we know how chat messages are handled in the Game Lobby.

We can do the same for "live_game" which is the in-game screen. If you look in that subdirectory, there are lots of files. But of course, live_game_chat.js looks the most promising. This time we'll investigate the JavaScript file directly just to show how that works. We want to react to chat messages as they come in. In the UI event are handled by "handlers", so look for those at the end of the file. There are only five and this one looks the most interesting for our purposes:

handlers.chat_message = function (payload) {
  var chat_message = new ChatMessageModel(payload);
  model.chatLog.push(chat_message);
  model.visibleChat.push(chat_message);
  $(".div_chat_feed").scrollTop($(".div_chat_feed")[0].scrollHeight);
  $(".div_chat_log_feed").scrollTop($(".div_chat_log_feed")[0].scrollHeight);
};

So we see that every time a new chat message comes in, the message is added to both "chatLog" and "visibleChat", so we need to look for changes of one of those. To figure out which one, look for both "chatLog" and "visibleChat" in the rest of the file. You'll see that "chatLog" is only defined and nothing else happens to it, whereas "visibleChat" is also involved in the function "removeOldChatMessages". So that means that chatLog only changes when new message arrive while visibleChat also changes when old messages are removed. We do not want to play a sound on message removal, so we have to use "chatLog".

File:Gold-rank-icon.png new_game.js

In the previous section, we found that we need to monitor the observableArray "chatMessages" for changes. We can do by using the subscribe function on it which is a function that is defined by Knockout for this exact purpose as shown in the Knockout documentation.

Open the file "new_game.js" in your mod. It now just contains the "Hello World!" we put there earlier, but we will now replace that with subscribing to "chatMessages". Make it so that the file now contains:

(function() {
  model.chatMessages.subscribe(function () {
    console.log("My mod says message received!");
  });
})();

The argument for the subscribe-function defined by Knockout is a function that is called whenever "chatMessages" is changed. Here that function is just contains a console.log again to see if it actually works. Save the file and in Planetary Annihilation go to the Game Lobby (or press F5 in either Planetary Annihilation or in the debugger to reload if you already are there). Now type a chat message in the lobby and if you are looking at the console output in the Debugger, you should see "My mod says message received!" every time you type a new message in the lobby.

The next step is to figure out how to play audio. We can again look at the existing Planetary Annihilation files. The grep command on Linux and macOS is a helpful tool for that allows you to search for text in files. For Windows there is Select-String in the PowerShell. Using that you can search for strings such as "sound" or "audio" to see examples of playing sounds. In particular searching for "audio" turns up examples of api.audio.playSound. So now we know how to play a sound. Searching for "audio.playSound" shows a bunch of sound effects we can use to play. For example, /media/ui/main/shared/js/inputmap.js contains api.audio.playSound('/SE/UI/UI_camera_anchor_saved'). If want to quickly test this, we can go to the Debugger and pas that in the console and execute by pressing Enter. Planetary Annihilation will then play that sound.

That sound sounds ok to get a chat alert, so we will use that. Now we change the new_game.js file in our mod to:

(function() {
  model.chatMessages.subscribe(function () {
    api.audio.playSound('/SE/UI/UI_camera_anchor_saved');
  });
})();

And that is all we need for the Game Lobby. You can test this now.

File:Gold-rank-icon.png live_game_chat.js

Now we need to do the same thing as for new_game.js. The only difference is that we determined we needed to use the observableArray "chatLog". So the content of live_game_chat.js is going to be almost the same as for new_game.js, we just need to use the proper observable to subscribe to. So make the content of live_game_chat.js in your mod this:

(function() {
  model.chatLog.subscribe(function () {
    api.audio.playSound('/SE/UI/UI_camera_anchor_saved');
  });
})();

And now that part is done too and we have a functioning mod that plays audio alerts on chat messages.

File:Gold-rank-icon.png settings.js

Settings in Planetary Annihilation are accessed through the JavaScript object api.settings.

File:Gold-rank-icon.png Publishing

See Submitting Your Released Mod for details on how to publish your mod.