Hello everyone!
A few months ago, I partially developed (helped by an AI) a system for age chat communication capabilities, and I even published this post describing it completely.
This is the full post:
[V1.0] Chat Capabilities Checking System
So i have been thinking about it a bit, and I believe it needs some improvements, such as making it more modular, optimizing it or even improving the visual indicator. But the problem is, I don’t know where to begin.
Here is the code from the client-side script:
--!strict
--> Services
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
--> Remotes
local ChatCheck = ReplicatedStorage:FindFirstChild("ChatCheckFunction")
--> Definitions
local LocalPlayer = Players.LocalPlayer :: Player
local LocalUserId = LocalPlayer.UserId :: number
--> Array
local LocalCombinations: {Combination} = {}
--> Types
type Combination = {
Ab: boolean, -- Result
Ea: number, -- Self player uid (Local)
Eb: number -- Other player uid
}
-- This function returns the passed values casted to the combination type
local function CreateCombination(Attribute: boolean, EntityA: number, EntityB: number) : Combination
return {
Ab = Attribute,
Ea = EntityA,
Eb = EntityB
}
end
-- This function calls the server for verify the chat status of the other player (Eb) towards you (Ea) from the combination; returns a boolean
local function ChatCheckFunction(Ea: number, Eb: number) : boolean
local Result = ChatCheck:InvokeServer(Ea, Eb)
return Result
end
-- This function shows a text over the other player head from the combination, depending of flag Ab
local function DisplayIcon()
for _, combination in ipairs(LocalCombinations) do
local TargetPlayer = Players:GetPlayerByUserId(combination.Eb)
if TargetPlayer then
-- This avoids errors during the character load
local Character = TargetPlayer.Character or TargetPlayer.CharacterAdded:Wait()
local HRP = Character:FindFirstChild("HumanoidRootPart") or Character:WaitForChild("HumanoidRootPart")
-- This avoids duplications
local ExistingBillboard = HRP:FindFirstChild("ChatCheckDisplay")
if ExistingBillboard then
ExistingBillboard:Destroy()
end
local Display = Instance.new("BillboardGui")
Display.Name = "ChatCheckDisplay"
Display.Size = UDim2.new(1, 1, 1, 1)
Display.AlwaysOnTop = false
Display.MaxDistance = 30
Display.StudsOffsetWorldSpace = Vector3.new(0, 5, 0)
Display.Parent = HRP
local Label = Instance.new("TextLabel")
Label.Size = UDim2.new(1, 1, 1, 1)
Label.Name = "Text"
Label.BackgroundTransparency = 1
Label.TextColor3 = Color3.new(1, 1, 1)
if combination.Ab == true then
Label.Text = "✅ This player can chat with you"
elseif combination.Ab == false then
Label.Text = "🚫 This player cant chat with you"
else
warn("Unexpected value!", tostring(combination.Ab))
end
Label.Parent = Display
end
end
end
--[[ [DEBUG ONLY] Displays all the combinations at the moment
local function PrintCombinations()
if #LocalCombinations == 0 then
print("No combinations at the moment")
elseif #LocalCombinations ~= 0 then
for index, Combination in ipairs(LocalCombinations) do
print("Combination", index, ": (", Combination.Ab, ",", Combination.Ea, ",", Combination.Eb, ")")
end
end
end
]]--
-- Sums a new combination with the player passed
local function SumCombination(player: Player)
if player.UserId ~= LocalUserId then -- This avoids combinations with oneself, like (1, 1)
local result = ChatCheckFunction(LocalUserId, player.UserId)
local combination = CreateCombination(result, LocalUserId, player.UserId)
table.insert(LocalCombinations, combination)
--print("New combination:", LocalUserId, player.UserId)
--PrintCombinations()
DisplayIcon()
end
end
-- Substracts the combination that matches with the player passed
local function SubCombination(player: Player)
-- Reverse read, check: https://devforum.roblox.com/t/how-to-flip-an-array/1549982
for i = #LocalCombinations, 1, -1 do
if LocalCombinations[i].Eb == player.UserId then
table.remove(LocalCombinations, i)
end
end
--print("Player left:", player.UserId)
--PrintCombinations()
DisplayIcon()
end
-- Processing actual players (Runs once!)
for _, player in ipairs(Players:GetPlayers()) do
SumCombination(player)
end
--> Events
Players.PlayerAdded:Connect(SumCombination)
Players.PlayerRemoving:Connect(SubCombination)
Also there is the server-side script:
--!strict
--> Services
local TextChatService = game:GetService("TextChatService")
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
--> Remotes
local ChatCheck = ReplicatedStorage:FindFirstChild("ChatCheckFunction")
ChatCheck.OnServerInvoke = function(player: Player, Ea: number, Eb: number) : boolean
local success, result = pcall(function(Ea, Eb)
return TextChatService:CanUsersChatAsync(Ea, Eb)
end)
if success then
return result -- False or True
else
warn("Error on CanUsersChatAsync: " .. tostring(result))
return false
end
end
I would really like to discuss the code so i can release a new version for the community!