Gaming

How to Add Moderation and Translation to Your Unity Game

How to Add Moderation and Translation to Your Unity Game

As you implement your real-time chat for your Unity game, you’ll need to ensure you add an inclusive and welcoming environment for your all players. Language translation allows players from all over the world to interact with each other in real time, rather than isolating players that do not understand the language. Implementing moderation for your chat ensures that your players can chat freely without being subjected to abusive and profane messages. Both of these features allow players to interact with each other in a positive environment, helping foster a sense of community and strengthening player engagement.

While language translation and moderation are vital in game development for your chat, incorporating these features in your Unity project is easier said than done. To start from scratch, it takes a lot of resources to build, maintain, and scale when your players increase. You also need to intercept these messages in real time to translate and filter, as online games need messages to be efficiently delivered to communicate properly. Luckily, PubNub has made it easier than ever to inject real-time functionalities into Unity games with our real-time, low-latency API platform. We take care of the infrastructure layer of your apps so that you can focus on your application. Whether you're developing for Windows, Mac, iOS, Android, Virtual Reality systems such as Oculus and Meta Quest, or going cross-platform, our Unity SDK has you covered.

Continue reading to learn how to add language translation and moderation to your real-time chat in your Unity game, starting from understanding how to configure the PubNub GameObject, learning about PubNub Functions, and the different integrations with third-party services that allow you to filter and translate messages in real time.

We strongly recommend you follow our real-time chat how-to guide which teaches you about how to implement different chat types and advanced features with PubNub. This guide is more focused on the language translation and moderation aspects of chat messages.

If you would like to see an example of how to implement language translation and moderation in a Unity game to use as a reference when following along with this guide, be sure to check out our Unity Showcase Game.

Getting Started with PubNub

Before you begin to understand how to set up language translation and moderation for your chat messages in real time, you’ll need to understand PubNub and how to configure your application to take advantage of the platform’s features.

Overview

PubNub is based on the Pub/Sub (Publish/Subscribe) model. A user will publish a message, which is essentially a payload that contains all relevant information, to the PubNub network. Users who want to receive or listen to the message and other generated events will subscribe to the PubNub network and parse the message. Event listeners are used to catch messages and events generated in the PubNub Network and trigger based on an action taken place.

To ensure the message gets to the right recipients, channels are used as the mechanism through which the data is transmitted from one device to another. Channels are required each time a device wants to publish and subscribe to the PubNub network. While a user can only publish one message at a time, a user can subscribe to many different channels at a time.

Install and Configure the PubNub Unity SDK

To begin, you'll need to install any PubNub dependencies and configure the PubNub Unity SDK to connect your application to the PubNub network. This guide already assumes you have the Unity Game Engine, Unity Assets, and code editors such as Visual Studio installed. Please refer to the Unity SDK documentation for full details, but as an overview, you will need to:

  1. Add the Unity package through the Package Manager.
  2. Create a free PubNub account and obtain your PubNub Keys. You’ll need to enable the features on your keyset that your application needs. For this guide, you’ll need to enable Stream Controller and App Context with the default settings. The other important feature, Functions, will be enabled automatically once you initialize the Function, which will be discussed later in this guide.
  3. Create a new Unity Project or open your existing game and provide Unity with the publish and subscribe keys you obtained in the previous step to configure the PubNub GameObject in the Unity Editor. You should also provide a UserId, as every PubNub object requires a unique identifier to establish a connection to PubNub. Once you have done so, initialize the PubNub object:
1 2 3 4 using PubnubApi; using PubnubApi.Unity; … PubNub pubnub = new Pubnub(pnConfiguration);
  1. Add an event listener for your game to react to messages, where your back end will essentially receive notifications about when you receive new messages. There are different event listeners to be able to implement custom logic to respond to each type of message or event, but for this guide, you’ll simply need the Message Event Listener:
1 2 3 4 5 6 7 8 9 var listener = new SubscribeCallbackListener(); pubnub.AddListener(listener); listener.onMessage += OnPnMessage; … private void OnPnMessage(Pubnub pn, PNMessageResult<object> result) { Debug.Log($"Message received: {result.Message}"); //Handle the message based on channel name, User ID, etc. }

Intercept Messages in Real Time: Functions

Before we begin to implement language translation and moderation for chat messages, we need to talk about how we can intercept the messages before they are delivered to other players.

Functions allows developers to create and execute business logic on the edge to route, filter, transform, augment, and aggregate real-time messages as they route through the PubNub network. You can host this business logic without needing to spin up your server, where you can integrate with one of our trusted third-party integrations (which are already set up to work with Functions and include instructions on getting started) or write your code and use your custom REST endpoints. Regardless of which route you go, you can safely store your API keys in our Vault module, which encrypts and obfuscates your keys after you initially add the key. You can also choose to intercept messages before or after delivery of messages. You can learn more about Functions in detail by diving into our documentation.

With both language translation and moderation, you want to intercept all messages before they are delivered to other players in your game. You’ll be able to capture the event as soon as a player hits send and can perform this logic to transform and send it back to your game once you’ve finished filtering/translating the message.

To be able to use Functions, you’ll need to perform some more setup in the Admin Portal:

  1. Navigate to the Admin Portal.
  2. Click on the Functions tab on the left-hand side of the portal.
  3. Select the App and keyset you created in the previous section.
  4. Click on Create New Module.
  5. Give the module a name.
  6. Enter a description of what the Module is doing.
  7. Select the keyset you created earlier to add the Module. Click Create (You will be creating two functions in this guide, one for moderation that filters for profanity and the other for language translation).
  8. Give both Functions a name.
  9. Select the Before Publish or Fire event type for both functions, as you will need to intercept the messages before they reach other players.
  10. Enter the channel name you wish the Function to intercept or update after a message is published (this can be adjusted later as well). You’ll be using a channel name consisting of the Wildcard Subscribe character * feature:
  • Translation Function Channel Name: chat.translate.*
  • Moderating Function Channel Name: chat.game.*

You can learn more about how Wildcard Subscribe works for chat messages in the following guide. 11. Click the Create button for each Function.

You will be brought to the Function overview page, where you can change settings, test, and even monitor the Function when it is interacting with your game for each Function. In the middle of the screen, there should be automatically generated JavaScript code. This is a sample "Hello World" function to showcase an example of how a function would work and where you can either host your code or execute the business logic of a third-party integration.

We’ll discuss how to implement the logic for both moderation and translation Functions in the next two sections. Once you have finished implementing the business logic in those sections: press the Save button for each Function and then click on Restart Module to run the modules, as well as any time you make changes to the code. Both of your Functions are now ready to add code to translate and moderate messages in real time!

Translate Languages in Real Time

Implementing language translation is a daunting task if implemented yourself, as it takes a lot of resources to ensure that messages are properly translated: computing power, database mapping of languages, and validity of the translated messages all need to be considered and carefully crafted.

We recommend using one of our ready-to-use language third-party integrations, specifically Amazon Translate. Amazon Translate removes the complexity of building translation capabilities into your applications with a simple API call. While there are over 5,550 supported language combinations in Amazon Translate, consider narrowing down your supported translation list, especially if used in conjunction with a moderation service such as Tisane (more on that in the next section).

We recommend starting with the walkthrough of getting started with the Amazon Translate integration, as you’ll need to obtain two API keys: an AWS Access Key and an AWS Secret Key. Once you’ve added the block to your keyset by clicking on the “Try it Now” button, there will be a lot of configuration code.

Focus on the block of code that is setting up the event payload, as you’ll need to set up the payload with a few different fields. We recommend replacing this code with what is used in the Unity Showcase Game’s payload configuration and then returning the result:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 const payload = request.message; if (payload) { return vault.get('AWS_access_key').then((AWS_access_key) => { return vault.get('AWS_secret_key').then((AWS_secret_key) => { let translate = payload; let opts = { path: '/', service: 'translate', region: 'us-east-2', headers: { 'Content-Type': 'application/x-amz-json-1.1', 'X-Amz-Target': 'AWSShineFrontendService_20170701.TranslateText' }, host: 'translate.us-east-2.amazonaws.com', body: JSON.stringify({ "Text": translate.text, "SourceLanguageCode": translate.source, "TargetLanguageCode": translate.target }) } signAWS(opts, { accessKeyId: AWS_access_key, secretAccessKey: AWS_secret_key }); const http_options = { 'method': 'POST', 'body': opts.body, 'headers': opts.headers }; return xhr.fetch('https://' + opts.host, http_options).then((response) => { const body = JSON.parse(response.body); //Able to translate text if (body.TranslatedText) { request.message.text = body.TranslatedText; //message has been translated, mark both the source and the target as the same. request.message.source = translate.target; } else { translate.error = body['Message']; } return request.ok(); }).catch((error) => { console.log('Error:', error); }); }); }); }

Every event payload requires the translate field to contain the following three fields:

  • text: The message to be translated.
  • source: The language that the message originates from.
  • target: The language the message needs to be translated to.

The event payload can now be sent via the Amazon Translate API to translate the message. In the above code, if the message has been translated, the message of the text is replaced with the translated text and marks the source language to indicate that the message has been properly translated (so your game doesn’t send the message back again to be translated). If the message cannot be translated, then the message is simply sent back.

Once you’ve added your business logic and restarted the Function (and checked in the console to ensure there are no errors), you’ll need to subscribe to receive the translated message from the Function via an Event Listener whenever a message is published.

You should consider edge cases such as not needing to translate a message when the source and target languages are the same (to save time, resources, and send the message to the recipient faster), as well as to handle when a message has been properly translated. You can publish the message in the Function code to a different channel that you are specifically subscribed to in your game to receive translated messages or as in the above example used in the Unity Showcase Game, by checking that the source and target languages are the same, which means that the message has been translated.

However, two issues need to be addressed by using the above functionality before you can implement this code: How do we obtain the source and target languages from players to include in the payload? How do we set up the message payload to send the source and target languages once we obtain them?

In your Unity project, you will need to implement Unity’s Localization package to set up not only easy-to-access language codes (such as “en” for English, “fr” for French, etc), but as well as for string and asset localization.

You can add a setting to your settings page to default to a language and allow them to change it to update their game’s language. You can then store the user’s language setting using the App Context API, which allows you to store and retrieve metadata about your players. Once a player updates their language, you can catch the change via the Objects Event Listener or retrieve the intended player’s metadata to obtain their language.

Before sending a message, you can format the payload to be a class that contains simple data types that can be extracted in the Function logic:

1 2 3 4 5 6 7 8 public class MessageModeration { public string text; public string source; public string target; public string publisher; public string chatType; }

If you would like to see an example of language translation in action, view our Unity Showcase Game; for how to set the metadata of a user when they select a new user, check out the SettingsWindow.cs file. For how to parse a message containing this language, view the Chat.cs file to understand how a message is parsed when it is received.

Filter Profanity & Abusive Text: Moderation

Filtering profane and harmful chat messages has always been a struggle for developers to implement properly for online games. New ways of entering profane and harmful text continue to increase and you need to ensure you protect your players from these negative interactions.

While you certainly can implement your own moderation logic to execute and intercept chat messages in real time, we recommend using one of our language third-party integrations, specifically the Tisane Labs Natural Language Processing integration.

The Tisane Labs Natural Language Processing Block analyzes real-time data streams and reveals not only why the text is positive or negative and provides extensive grammar tagging and parse tree output. The unique aspect of Tisane is that it can detect this content in over 27 languages. This means that you can send the block a message that is in any of the supported languages and still have it filter for abusive content, which is extremely useful when used in conjunction with language translation.

We recommend starting with the walkthrough of getting started with the Tisane Labs integration. You’ll need to sign up for a Tisane Labs account and obtain the API key to add to the Vault of the Function you created earlier. It will also generate the business logic block of code for you, so you’re ready to get started implementing moderation for your own game’s use case. Be sure to follow Tisane’s documentation for specific and other useful details.

As an actual use-case example, our Unity Showcase Game utilizes Tisane Labs to moderate abusive content in multiple languages so we can filter and mask any abusive words it flags. Here is the Function code we use in our game:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 const xhr = require('xhr'); const vault = require('vault'); export default (request) => { let message = request.message.text; let language = request.message.source; const getAPIKey = new Promise((resolve) => { //use the MY SECRETS on the left after you've got your API Key from Tisane of vault vault.get('tisaneApiKey').then((key) => { resolve(key); }); }); return getAPIKey.then((tisaneApiKey) => { return xhr.fetch('https://api.tisane.ai/parse', { 'method': 'POST', 'headers': { 'Ocp-Apim-Subscription-Key': tisaneApiKey }, 'body': JSON.stringify({ 'language': language, //content is what is checking - the message itself. The string is in the message.text 'content': message, 'settings': { 'snippets': true } }) }); }).then((reply) => { //reply here is from Tisane as a JSON let responseJson = JSON.parse(reply.body); //any form of abuse will be returned in reply.body.abuse as an array for each type of abuse if (responseJson.abuse) { //Filter message for profanity and replace with asterisks for each profane character. let profanities = responseJson.abuse.filter(item => item.type === "profanity").sort((a, b) => b.offset - a.offset); profanities.forEach((profanity) => { let start = profanity.offset; let end = start + profanity.length; let replacement = "*".repeat(profanity.length); message = message.substring(0, start) + replacement + message.substring(end); }); request.message.text = message; return request.ok(); // send the original message, or the stars } //No profanity found, return original text. else { return request.ok(); } }).catch((err) => { console.error(err); return request.abort(); }); };

As soon as a message is received that contains a pattern that matches the wildcard subscribe channel, the message is passed through Tisane’s NLP. If there is any content that Tisane considers abusive, the original message is filtered to replace the abusive content with * characters while leaving the rest of the message intact. If there is no abuse, the original message is simply sent back to the application.

Once you’ve added your business logic and restarted the Function (and checked in the console to ensure there are no errors), you’ll need to subscribe to receive the filtered message from the Function via an Event Listener whenever a message is published. The Function will intercept the message, filter for any potential abuse, and send it back to the game. You would then parse the message in the Message Event Listener we set up earlier, ensuring that it is from the appropriate source by checking channel names.

If you are implementing both language translation and moderation, you’ll want to check if the language needs to be translated first before running it through moderation, as while every message needs to be moderated, not every message needs to be translated (unless you have a setting for players that disables moderation). In the event listener, you’ll need to set up how to handle situations to know when a message needs to be translated, filtered, and ready to be displayed to the intended recipients.

If you would like to see an example of how to implement language translation and moderation in a Unity game, be sure to check out our Unity Showcase Game.

What’s Next

In this how-to guide, you’ve learned how to add language translation and moderation to your Unity game. With Functions, you can host code to intercept messages to translate and filter for abusive content in real time, ensuring your players can safely interact with players from around the world, creating a safer, more welcoming, and more engaging player experience.

Keep in mind this is the tip of the iceberg with Functions. Since everything is computed at the edge for low latency, you can do everything from IoT sensor data aggregation, chatbots, and AI integrations such as Open AI ChatGPT, to dynamic geofencing and geo-triggering, as well as implementing a leaderboard system in your Unity game.

Learn more with the following resources:

Feel free to reach out to the Developer Relations Team at devrel@pubnub.com for any questions or concerns.