[Release] Bubble Chat

Started by Sebastian, Mar 08, 2017, 12:35 PM

Previous topic - Next topic

Sebastian

CREDITS:


From "I'm presenting you the future" series:

Bubble Chat !
The easiest way to chat with your friends


You type a message, it appears near your ped
It's invisible for you, but visible for the others around you
It's attached to you
Gets auto-removed after few seconds
It's auto-scaling, depending on your resolution



[spoiler=how it reacts when text.len() > 25]

[/spoiler]



[spoiler=Instalation guide]
SCRIPT-SIDE

for the top:
enum StreamType
{
BubbleChat = 0x01
};

onPlayerChat( player, chat )
local Stream = Stream();
Stream.WriteByte( StreamType.BubbleChat );
Stream.WriteInt( player.ID );

if( text.len() > 25 )
                {
                text = "(" + text.slice( 0, 20 ) + "...)";
                }

Stream.WriteString( text );
Stream.SendStream( null );

CLIENT-SIDE

for the top:
MAX_PLAYERS <- 50; // change it with your Max Players' Limit !

enum StreamType
{
BubbleChat = 0x01
}

local ChatBubble_UI = array( MAX_PLAYERS );
local ChatBubble_Sender = array( MAX_PLAYERS );
local ChatBubble_Frames = array( MAX_PLAYERS, 0 );
// Would've made these constant as well but:
//  ChatBubble_Colour is not a primitive
//  ChatBubble_Scale may be adjusted in windowed mode
local ChatBubble_Colour = Colour( 255, 255, 255 );
// I'm guessing these can be considered constant
const ChatBubble_Alpha = 255;
const ChatBubble_Font = "Verdana";
local ChatBubble_Flag = GUI_FFLAG_OUTLINE;

Script::ScriptProcess( )
::ChatBubbleProc();

Server::ServerData( stream )
local type = stream.ReadByte();

switch(type)
{
case StreamType.BubbleChat:
            local pID = stream.ReadInt();
            ::ChatBubbleSetData( pID, World.FindPlayer( pID ), stream.ReadString() );
        break;
}

Bubble Chat functions
//-------------------------------------------
function ChatBubbleSetData( index, player, text )
{
    // We create the label locally first
    local lbl = GUILabel( VectorScreen( 0, 0 ), ChatBubble_Colour, "" );
    // Configure the label
    lbl.FontSize = (GUI.GetScreenSize().Y / 40);
    //lbl.FontName = ChatBubble_Font; // commented because it gives 1ms freeze
    lbl.Alpha = ChatBubble_Alpha;
    //lbl.FontFlags = ChatBubble_Flag; // commented because it gives 1-2ms freeze
    lbl.Text = text;
    // Only after we know the label was created and configured we save it
    ChatBubble_UI[ index ] = lbl;
    // At this point we can store the associated player
    //ChatBubble_Sender[ index ] = player;
    // Only after everything is successful we reset the frame counter
    ChatBubble_Frames[ index ] = 0;
}
//-------------------------------------------
function Distance( x1, y1, z1, x2, y2, z2 )
{
    return sqrt( (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) + (z1 - z2) * (z1 - z2) );
}
//-------------------------------------------
function ChatBubbleProc()
{
    local lplayer = World.FindLocalPlayer(), sender;
    local lpos = lplayer.Position, spos;
    local lbl, wpts, z1 = Vector( 0, 0, 1 );
    // We know there are as many frame counters as senders and we can use their index as limit
    for (local i = 0, maxi = ChatBubble_Frames.len(); i < maxi; ++i)
    {
if( ChatBubble_UI[ i ] && ChatBubble_Frames[ i ] <= 450 )
{
// Stop this whole shenanigan here if:
//  the text was updated more than 450 frames ago
// or:
//  the text does not even exists anymore
if( ChatBubble_Frames[i] >= 450 || ChatBubble_UI[i] == null )
{
// We can just ignore this index...
}
// Don't process if the text was updated more than 450 frames ago
else if( ++ChatBubble_Frames[i] == 450 || !World.FindPlayer( i ) )
{
ChatBubble_UI[ i ] = null;
ChatBubble_Sender[ i ] = null;
}
// Don't process if there's no sender
else if( sender = ChatBubble_Sender[ i ] && World.FindPlayer( i ) )
{
spos = sender.Position, lbl = ChatBubble_UI[ i ], lbl.Alpha = 0;
// See if the sender is within local player range
if( Distance( lpos.X, lpos.Y, lpos.Z, spos.X, spos.Y, spos.Z ) < 20 )
{
wpts = GUI.WorldPosToScreen( spos + z1 );

lbl.Position = VectorScreen( wpts.X, wpts.Y );

local ChatBubble_PosToScreen = GUI.WorldPosToScreen( spos );
if( ChatBubble_PosToScreen.Z < 1)
{
lbl.Alpha = ChatBubble_Alpha;
}
else
{
lbl.Alpha = 0;
}
}
   
if( sender == lplayer )
{
lbl.Alpha = 0;
}
}
}
    }
}

//-------------------------------------------

[/spoiler]

MatheuS

if( !sucess ) tryAgain();
Thanks to the VCMP community. It was the happiest period of my life.

vito


kennedyarz


KAKAN

#4
Nice work. I really like that bubble chat :D

I got a question to ask:-
In your client side code, the locals:-
local ChatBubble_UI = array( GetMaxPlayers );
local ChatBubble_Sender = array( GetMaxPlayers );
local ChatBubble_Frames = array( GetMaxPlayers, 0 );
Isn't GetMaxPlayers a function? The last time I used it, it was a function, not a variable. I don't know about client side, but in server-side its a function. Please check it :)
oh no

Xmair

That just reminded me of @EK.IceFlake's server.

Credits to Boystang!

VU Full Member | VCDC 6 Coordinator & Scripter | EG A/D Contributor | Developer of VCCNR | Developer of KTB | Ex-Scripter of EAD

Sebastian

Quote from: KAKAN on Mar 08, 2017, 01:50 PMIsn't GetMaxPlayers a function? The last time I used it, it was a function, not a variable. I don't know about client side, but in server-side its a function. Please check it :)

Actually, it is a variable in this case, since there is no client-side function like GetMaxPlayers();
It's just the way I named it. I will change it to MAX_PLAYERS in order to not get confused again.

PS: Done.

Quote from: Xmair on Mar 08, 2017, 04:14 PMThat just reminded me of @EK.IceFlake's server.

Interesting. Never knew that.
This just accentuates the need of such a feature in every server. :)

Xmair

His server is still in beta and was password locked but he let me in :p

Credits to Boystang!

VU Full Member | VCDC 6 Coordinator & Scripter | EG A/D Contributor | Developer of VCCNR | Developer of KTB | Ex-Scripter of EAD

KAKAN

Quote from: Xmair on Mar 08, 2017, 05:26 PMHis server is still in beta and was password locked but he let me in :p
me too :)

Quote from: sseebbyy on Mar 08, 2017, 05:16 PM
Quote from: KAKAN on Mar 08, 2017, 01:50 PMIsn't GetMaxPlayers a function? The last time I used it, it was a function, not a variable. I don't know about client side, but in server-side its a function. Please check it :)

Actually, it is a variable in this case, since there is no client-side function like GetMaxPlayers();
It's just the way I named it. I will change it to MAX_PLAYERS in order to not get confused again.

PS: Done.
What's the need of variables? Just set them to 100, they won't eat 1GB of RAM. I usually prefer that :P
oh no

.

Quote from: KAKAN on Mar 08, 2017, 06:41 PMWhat's the need of variables? Just set them to 100, they won't eat 1GB of RAM. I usually prefer that :P

Then you'd be processing 50 or more players that don't exist. And you'll be doing that on each frame. It's not an error but it's a waste of processing power.
.

Sebastian

Quote from: KAKAN on Mar 08, 2017, 06:41 PMWhat's the need of variables? Just set them to 100, they won't eat 1GB of RAM. I usually prefer that :P

I prefer to set a variable for it, to change it easily when in need.
There is no need for more, if we know the exact amount.

Sebastian

#11
Hotfix
ChatBubbleProc() was updated to avoid server crash.

PS: I also put an e.g. of MAX_PLAYERS variable, so everybody can be aware of it.
Also, don't forget to set it's value to be the same as the maximum amount of players that can be on your server.

kennedyarz

A question of curiosity, when a player is afk and  I speak next to him and the player immediately returns. The question is, does he see the message I wrote? Another, if the player is in motion, the text follows to player?...

Sebastian

Quote from: kennedyarz on Mar 11, 2017, 01:32 PMA question of curiosity, when a player is afk and  I speak next to him and the player immediately returns. The question is, does he see the message I wrote? Another, if the player is in motion, the text follows to player?...

The message is shown near his head once it is sent to the chat.
And yes, it follows the player. (I said it is "attached")

kennedyarz

Quote from: sseebbyy on Mar 11, 2017, 01:40 PM
Quote from: kennedyarz on Mar 11, 2017, 01:32 PMA question of curiosity, when a player is afk and  I speak next to him and the player immediately returns. The question is, does he see the message I wrote? Another, if the player is in motion, the text follows to player?...

The message is shown near his head once it is sent to the chat.
And yes, it follows the player. (I said it is "attached")

The truth is that I have already tried 2 times this script and I do not see it, I am putting everything perfectly as you know, the problem is that I open 2 windows of the vcmp and connect it to my test server, I then send a message and like the other one Window is afk. Then I immediately return to the other window and I do not see the message in his head. The problem will be because a window is afk?