How to use Llama Chat in an existing project
Prerequisites
Ensure TextMeshPro is in your project already. If it is not, you can add it from the package manager.
If you do not already have a database, you can use the provided sqlite database in Assets/Llama Software/Llama Chat/Demo/Database/login.db
until you move your users to a more production-ready database.
If you already have a database you will need to make some sql command changes to hook up Llama Chat to your database. If you do not use sqlite please ensure you have the appropriate C# libraries to connect to your database.
Recommend you add subscribed_channels
table as defined in Assets/Llama Software/Llama Chat/Demo/Database/create_login_sample.sql
. If you want to support friends list & block list, recommend also having a similar setup for friends
table and blocked_players
table if you do not already have them.
Player GameObject Creation Requirements
Llama Chat REQUIRES custom player creation. You can see examples of how this is done in LoginController#CreatePlayerFromRow
LobbyLoginController#CreatePlayerFromRow
and InMemoryLoginController#HandleUserLogin
.
There are 2 pieces of critical information you must have before attempting to create your Player GameObject.
- A unique identifier for each player (GUID or some other id)
- An active NetworkConnection for that player.
These two pieces of information must be set on the Player_Chat script in the same frame that the Player GameObject is created. If you do not have these two pieces of information and try to create your player the system will not be able to correctly set up the chat system for that player and unexpected, undesirable behavior will happen (including errors).
The critical code is:
Player_Chat player = Instantiate(LobbyPlayerPrefab);
player.Id = Id.ToString(); // In the same frame the Player_Chat script is added, you must also set the Id and Name property_
player.name = Username;
player.Name = Username; // In the same frame the Player_Chat script is added, you must also set the Id and Name property
NetworkServer.AddPlayerForConnection(connection, player.gameObject);
// optionally, also notify logged in players of this login:
List<Player> FriendsOfPlayer = SQLitePlayerDatabase.Instance.FindPlayersWhoHaveFriend(Id.ToString());
FriendsOfPlayer.FindAll((friends) => friends.ConnectionId != -1).ForEach((friend) =>
{
FriendUpdateMessage FriendUpdateMessage = new FriendUpdateMessage()
{
UpdatedFriends = new List<SocialPlayer>()
};
SocialPlayer Friend = new SocialPlayer()
{
PlayerId = player.Id,
Name = Username
};
Friend.IsOnline = true;
FriendUpdateMessage.UpdatedFriends.Add(Friend);
#if MIRROR
if (NetworkServer.connections.ContainsKey(connection.connectionId))
{
NetworkServer.connections[connection.connectionId].Send(FriendUpdateMessage);
}
else if (LlamaChatSettingsProvider.Instance.LlamaChatSettings.LogLevel >= LogType.Error)
{
Debug.LogError(string.Format("[Server] Unable to send friend list update to connection id {0} because their connection is not active on the server.", connection.connectionId));
}
#else
NetworkServer.SendToClient(friend.ConnectionId, ChatSystemConstants.CLIENT_FRIENDS_UPDATED, FriendUpdateMessage);
#endif
});
Updating SQL to match your database
I cannot cover all cases in this section, but I will provide the files that interact with a database and the concepts should be similar regardless of platform. This is the primary effort in integrating with an existing project with an existing database.
In this section I am assuming you have a game server that has direct access to a database with the player login information. If you have a situation where the game server must access player data via an API or if you just would like to not query the database for this information at runtime from Unity, see the below subsection More Complex Projects
Review the sql in Assets/Llama Software/Llama Chat/Demo/Database/create_login_sample.sql
so you understand the structure that was implemented for the demo and what kind of query changes need to happen to match your schemas.
- Open
LlamaSoftware.Chat.SQLitePlayerDatabase
class -SQLitePlayerDatabase.cs
- This is the class that primarily interacts with the database
- if you are not using sqlite you will need to connect to your database in a similar fashion to what is done here.
- If you are using sqlite, find
PathToDatabase
and update it to whatever URI you have your database on.
- In
FindPlayersWhoHaveFriend
update the command to match your schema. Currently it uses a unique player identifier and finds all players who have thatid
in thefriend_id
column, and joins that with the main account (login
) table to be able to generate a Player object. - In
FindFriendsFor
update the command to match your schema. Currently it uses a unique player identifier as a key and finds allid
s in thefriend_id
column and joins that with the main account (login
) table to be able to generate a Player object - In
FindPlayersWhoAreBlockedBy
&FindBlockedPlayersFor
the same logic happens, just on theblocked_players
table to find which players a given player should not talk to and not be able to be talked to by. - In
FindSubscribedChannelsFor
I would recommend just creating thissubscribed_channels
table and keeping this code the same. - In
DoSavePlayerData
it updates a given player's friends, blocked players, and channels.
- This is the class that primarily interacts with the database
- View
LlamaSoftware.Chat.Demo.LoginController
-LoginController.cs
- In
CreatePlayerFromRow
we do Player Construction – you will likely want to do a similar process on successful login.- If using Mirror, you can abstract the login piece out with an Authenticator.
- In
More Complex Projects
The guidance above assumes you have direct access to the database from your Unity game, which is not always true. In these scenarios you will likely want to use the InMemoryPlayerDatabase.cs
or at least start there. This class keeps all currently online players in the KnownPlayerSubscriptions
(A Dictionary of uniqueId -> Player) and does not persist data itself. It provides relatively high performance Dictionary operations to fulfil the AbstractPlayerDatabase
API to allow you to get friends, blocked players, chat channels, etc... from the list of currently online players.
To use ANY OTHER AbstractPlayerDatabase
(including InMemoryPlayerDatabase
) in place of the SQLitePlayerDatabase
you can simply replace references to SQLitePlayerDatabase
in the following files:
ChatSystem.cs
AreaTriggeredChannelJoiner.cs
Player_Chat.cs
If you want to test it in a demo scene, you will still have to do this and also update any references in the Demo scripts.
In almost all cases this is sufficient because you only want to operate on existing online players. AbstractPlayerDatabase#AddPlayer
and AbstractPlayerDatabase#RemovePlayer
already manage this KnownPlayerSubscriptions
Dictionary so there is no additional work required there.
For any scenarios where you will be using the InMemoryPlayerDatabase
you will be persisting the data separately from this class. This means you will need to write some code in InMemoryPlayerDatabase#SavePlayerChatSettings
to persist the updated player data. This can be done in a "Fire and Forget" methodology and even be performed on a background thread using a ThreadPool. Failure to update this method to store the latest player will result in your players not retaining changes across sessions. This means they will lose their newly added friends, blocked players, and chat channnels.
If we take a concrete example of your have a separate sever that houses the database that you communicate via an API assuming you are using the InMemoryPlayerDatabase
:
- a NetworkConnection must be established between the Game Server and the Player's Client
- Before creating the Player GameObject an API call must be sent to get all of the information about the Player (Id, Name, Chat Channels, Friends List, Block List).
- Create an instance of the Player and fill out all of those details
- Call
InMemoryPlayerDatabase.AddPlayer(fullyQualifiedPlayer);
- Instantiate the Player GameObject and set the
Id
andName
property on thePlayer_Chat
script.
Update your Player Prefab
Add LlamaSoftware.Chat.Player_Chat
– Player_Chat.cs
to your Player prefab and configure default chat channels.
All players will be given these chat channels by default. All players are expected to have at least 1 Chat Channel, but you can also configure those as AreaTriggeredChannelJoiner
classes.