Home

Add

Edit

With Linenumbers

Code in Textfield

Download

'##############################################################################################################
'##############################################################################################################
' TSNEplay_V3 - TCP Socket Networking [Eventing] Play (Gaming Extension) Version: 1.0 for TSNE_V3
'##############################################################################################################
'##############################################################################################################
' 2009 By.: /_\ DeltaLab's Germany - Experimental Computing
' Autor: Martin Wiemann
' Version: 2013.03.11
'##############################################################################################################





#IFNDEF _TSNEplay_
    #DEFINE _TSNEplay_
'>...

'##############################################################################################################
#DEFINE TSNE_DEF_REUSER
#INCLUDE Once "TSNE_V3.bi"



'##############################################################################################################
Enum TSNEPlay_GURUCode
    TSNEPlay_NoError                            = 1
    TSNEPlay_Unknown                            = 0
    TSNEPlay_NotReadyForNewConnection           = -1000
    TSNEPlay_PlayerIDNotFound                   = -1001
    TSNEPlay_MessageToLong                      = -1002
End Enum



'##############################################################################################################
Enum TSNEPlay_State_Enum
    TSNEPlay_State_Unknown                      = 0
    TSNEPlay_State_Disconnected                 = 1
    TSNEPlay_State_Connecting                   = 2
    TSNEPlay_State_Connected                    = 3
    TSNEPlay_State_Login                        = 4
    TSNEPlay_State_Ready                        = 5
End Enum

'--------------------------------------------------------------------------------------------------------------
Enum TSNEPlay_MessageType_Enum
    TSNEPlay_MSGType_Regular                    = 0
    TSNEPlay_MSGType_Private                    = 1
    TSNEPlay_MSGType_Notice                     = 2
    TSNEPlay_MSGType_Hightlighted               = 3
End Enum



'##############################################################################################################
Enum TSNEPlay_INT_CMDType_Enum
    TSNEPlay_INT_MSGT_Unknown                   = 0
    TSNEPlay_INT_MSGT_NeedPassword              = 1
    TSNEPlay_INT_MSGT_Password                  = 2
    TSNEPlay_INT_MSGT_PasswordWrong             = 3
    TSNEPlay_INT_MSGT_GetInfo                   = 4
    TSNEPlay_INT_MSGT_PutInfo                   = 5
    TSNEPlay_INT_MSGT_Ready                     = 10
    TSNEPlay_INT_MSGT_StreamError               = 999999
    TSNEPlay_INT_MSGT_Ping                      = 1000
    TSNEPlay_INT_MSGT_Pong                      = 1001
    TSNEPlay_INT_MSGT_MSG                       = 1002
    TSNEPlay_INT_MSGT_Move                      = 1003
    TSNEPlay_INT_MSGT_Dat                       = 1004
    TSNEPlay_INT_MSGT_Con                       = 1005
    TSNEPlay_INT_MSGT_Dis                       = 1006
    TSNEPlay_INT_MSGT_Full                      = 1007
    TSNEPlay_INT_MSGT_MoveDbl                   = 1008
End Enum



'##############################################################################################################
Type TSNEPlay_INT_CommandQue_Type
    V_Next                                          As TSNEPlay_INT_CommandQue_Type Ptr
    V_Prev                                          As TSNEPlay_INT_CommandQue_Type Ptr
    
    V_RAW                                           As String
    V_CMDType                                       As TSNEPlay_INT_CMDType_Enum
    V_Data                                          As String
End Type



'##############################################################################################################
Type TSNEPlay_INT_Client_Type
    V_Next                                          As TSNEPlay_INT_Client_Type Ptr
    V_Prev                                          As TSNEPlay_INT_Client_Type Ptr
    
    V_TSNEID                                        As Uinteger
    V_IPA                                           As String
    V_Data                                          As String
    V_State                                         As TSNEPlay_State_Enum
    
    V_CMDQueF                                       As TSNEPlay_INT_CommandQue_Type Ptr
    V_CMDQueL                                       As TSNEPlay_INT_CommandQue_Type Ptr
    V_CMDQueC                                       As Ushort
    
    V_PlayerID                                      As Uinteger
    V_Nickname                                      As String
    
    T_LastPing                                      As Double
    T_PingT                                         As Double
End Type

'--------------------------------------------------------------------------------------------------------------
Dim Shared TSNEPlay_INT_ClientF                     As TSNEPlay_INT_Client_Type Ptr
Dim Shared TSNEPlay_INT_ClientL                     As TSNEPlay_INT_Client_Type Ptr
Dim Shared TSNEPlay_INT_ClientC                     As Uinteger
Dim Shared TSNEPlay_INT_PlayerIDC                   As Uinteger



'##############################################################################################################
Dim Shared TSNEPlay_INT_Mutex                       As Any Ptr
'--------------------------------------------------------------------------------------------------------------
Dim Shared TSNEPlay_INT_State                       As TSNEPlay_State_Enum
Dim Shared TSNEPlay_INT_ClientMode                  As Ubyte
Dim Shared TSNEPlay_INT_ServerPassword              As String
Dim Shared TSNEPlay_INT_Nickname                    As String
'--------------------------------------------------------------------------------------------------------------
Dim Shared TSNEPlay_INT_Server_TSNEID               As Uinteger
Dim Shared TSNEPlay_INT_Server_PlayerID             As Uinteger
Dim Shared TSNEPlay_INT_Server_MaxPlayer            As Ushort
'--------------------------------------------------------------------------------------------------------------
Dim Shared TSNEPlay_INT_Client_TSNEID               As Uinteger
Dim Shared TSNEPlay_INT_Client_Data                 As String
Dim Shared TSNEPlay_INT_Client_PlayerID             As Uinteger
'--------------------------------------------------------------------------------------------------------------
Dim Shared TSNEPlay_INT_Event_ConnectionState       As Sub (Byval V_FromPlayerID As Uinteger, Byval V_State As TSNEPlay_State_Enum)
Dim Shared TSNEPlay_INT_Event_Player_Connected      As Sub (Byval V_PlayerID As Uinteger, V_IPA As String, V_Nickname As String)
Dim Shared TSNEPlay_INT_Event_Player_Disconnected   As Sub (Byval V_PlayerID As Uinteger)
Dim Shared TSNEPlay_INT_Event_Message               As Sub (Byval V_FromPlayerID As Uinteger, Byval V_ToPlayerID As Uinteger, Byval V_Message As String, Byval V_MessageType As TSNEPlay_MessageType_Enum)
Dim Shared TSNEPlay_INT_Event_Move                  As Sub (Byval V_FromPlayerID As Uinteger, Byval V_ToPlayerID As Uinteger, Byval V_NewPositionX As Integer, Byval V_NewPositionY As Integer, Byval V_NewPositionZ As Integer, Byval V_SubData As Uinteger)
Dim Shared TSNEPlay_INT_Event_MoveDbl               As Sub (Byval V_FromPlayerID As Uinteger, Byval V_ToPlayerID As Uinteger, Byval V_NewPositionX As Double, Byval V_NewPositionY As Double, Byval V_NewPositionZ As Double, Byval V_SubData As Uinteger)
Dim Shared TSNEPlay_INT_Event_Data                  As Sub (Byval V_FromPlayerID As Uinteger, Byval V_ToPlayerID As Uinteger, Byref V_Data As String)



'##############################################################################################################
Sub TSNEPlay_INT_Construct() Constructor
TSNEPlay_INT_Mutex = Mutexcreate()
End Sub

'--------------------------------------------------------------------------------------------------------------
Sub TSNEPlay_INT_Destruct() Destructor
Mutexdestroy(TSNEPlay_INT_Mutex)
TSNEPlay_INT_Mutex = 0
End Sub



'##############################################################################################################
Function TSNEPlay_INT_ClientGetPID(V_PlayerID As Uinteger) As TSNEPlay_INT_Client_Type Ptr
Dim TPtr As TSNEPlay_INT_Client_Type Ptr = TSNEPlay_INT_ClientF
Do Until TPtr = 0
    If TPtr->V_PlayerID = V_PlayerID Then Return TPtr
    TPtr = TPtr->V_Next
Loop
Return 0
End Function

'--------------------------------------------------------------------------------------------------------------
Function TSNEPlay_INT_ClientGetTSNEID(V_TSNEID As Uinteger) As TSNEPlay_INT_Client_Type Ptr
Dim TPtr As TSNEPlay_INT_Client_Type Ptr = TSNEPlay_INT_ClientF
Do Until TPtr = 0
    If TPtr->V_TSNEID = V_TSNEID Then Return TPtr
    TPtr = TPtr->V_Next
Loop
Return 0
End Function

'--------------------------------------------------------------------------------------------------------------
Function TSNEPlay_INT_ClientAdd() As TSNEPlay_INT_Client_Type Ptr
Dim TPtr As TSNEPlay_INT_Client_Type Ptr
TSNEPlay_INT_PlayerIDC += 1
Do Until TSNEPlay_INT_ClientGetPID(TSNEPlay_INT_PlayerIDC) = 0
    TSNEPlay_INT_PlayerIDC += 1
    If TSNEPlay_INT_PlayerIDC = 0 Then TSNEPlay_INT_PlayerIDC = 1
Loop
If TSNEPlay_INT_ClientL <> 0 Then
    TSNEPlay_INT_ClientL->V_Next = Callocate(Sizeof(TSNEPlay_INT_Client_Type))
    TSNEPlay_INT_ClientL->V_Next->V_Prev = TSNEPlay_INT_ClientL
    TSNEPlay_INT_ClientL = TSNEPlay_INT_ClientL->V_Next
Else
    TSNEPlay_INT_ClientL = Callocate(Sizeof(TSNEPlay_INT_Client_Type))
    TSNEPlay_INT_ClientF = TSNEPlay_INT_ClientL
End If
With *TSNEPlay_INT_ClientL
    .V_PlayerID = TSNEPlay_INT_PlayerIDC
End With
TSNEPlay_INT_ClientC += 1
Return TSNEPlay_INT_ClientL
End Function

'--------------------------------------------------------------------------------------------------------------
Sub TSNEPlay_INT_ClientDel(V_Client As TSNEPlay_INT_Client_Type Ptr)
If V_Client->V_Next <> 0 Then V_Client->V_Next->V_Prev = V_Client->V_Prev
If V_Client->V_Prev <> 0 Then V_Client->V_Prev->V_Next = V_Client->V_Next
If TSNEPlay_INT_ClientF = V_Client Then TSNEPlay_INT_ClientF = V_Client->V_Next
If TSNEPlay_INT_ClientL = V_Client Then TSNEPlay_INT_ClientL = V_Client->V_Prev
With *V_Client
    Do Until .V_CMDQueF = 0
        .V_CMDQueL = .V_CMDQueF->V_Next
        Deallocate(.V_CMDQueF)
        .V_CMDQueF = .V_CMDQueL
    Loop
End With
Deallocate(V_Client)
If TSNEPlay_INT_ClientC > 0 Then TSNEPlay_INT_ClientC -= 1
End Sub



'##############################################################################################################
Function TSNEPlay_Desc_GetGuruCode(V_GuruCode As TSNEPlay_GURUCode) As String
Select Case V_GuruCode
    Case TSNEPlay_NoError                           : Return "No error!"
    Case TSNEPlay_Unknown                           : Return "Unknown error!"
    Case TSNEPlay_NotReadyForNewConnection          : Return "Not Ready! Conection Already Exist! Close all connections!"
    Case TSNEPlay_MessageToLong                     : Return "Message text is too long!"
    Case Else                                       : Return TSNE_GetGURUCode(V_GuruCode)
End Select
End Function

'--------------------------------------------------------------------------------------------------------------
Function TSNEPlay_Desc_GetStateCode(V_State As TSNEPlay_State_Enum) As String
Select Case V_State
    Case TSNEPlay_State_Unknown                     : Return "Unknown"
    Case TSNEPlay_State_Disconnected                : Return "Disconnected!"
    Case TSNEPlay_State_Connecting                  : Return "Connecting..."
    Case TSNEPlay_State_Connected                   : Return "Connected!"
    Case TSNEPlay_State_Login                       : Return "Login..."
    Case TSNEPlay_State_Ready                       : Return "Ready!"
    Case Else                                       : Return "[Unknown State-Code]"
End Select
End Function



'##############################################################################################################
Function TSNEPlay_INT_CreateStreamCommand(V_Command As TSNEPlay_INT_CMDType_Enum, V_Data As String = "") As String
'Print "OUT_CMD: >"; Str(V_Command); "<___>"; Str(Len(V_Data)) & "<"
Dim MX As Uinteger = 4 + Len(V_Data)
Dim T As String
T += Chr((MX Shr 24) And 255) & Chr((MX Shr 16) And 255) & Chr((MX Shr 8) And 255) & Chr(MX And 255)
T += Chr((V_Command Shr 24) And 255) & Chr((V_Command Shr 16) And 255) & Chr((V_Command Shr 8) And 255) & Chr(V_Command And 255)
Return T & V_Data
End Function

'--------------------------------------------------------------------------------------------------------------
Sub TSNEPlay_INT_ParseStreamCommand(Byref V_Data As String, Byref R_CMDQueF As TSNEPlay_INT_CommandQue_Type Ptr, Byref R_CMDQueL As TSNEPlay_INT_CommandQue_Type Ptr)
Dim MX As Uinteger
Dim XRAW As String
Dim XCMD As TSNEPlay_INT_CMDType_Enum
Dim XData As String
Do
    If Len(V_Data) < 8 Then Exit Sub
    MX = (V_Data[0] Shl 24) Or (V_Data[1] Shl 16) Or (V_Data[2] Shl 8) Or V_Data[3]
    If (Len(V_Data) - 4) < MX Then Exit Sub
    XCMD = (V_Data[4] Shl 24) Or (V_Data[5] Shl 16) Or (V_Data[6] Shl 8) Or V_Data[7]
    XRAW = Left(V_Data, MX + 4)
    XData = Mid(V_Data, 9, MX - 4)
    V_Data = Mid(V_Data, MX + 5)
    If R_CMDQueL <> 0 Then
        R_CMDQueL->V_Next = Callocate(Sizeof(TSNEPlay_INT_CommandQue_Type))
        R_CMDQueL = R_CMDQueL->V_Next
    Else
        R_CMDQueL = Callocate(Sizeof(TSNEPlay_INT_CommandQue_Type))
        R_CMDQueF = R_CMDQueL
    End If
    With *R_CMDQueL
        .V_RAW = XRAW
        .V_CMDType = XCMD
        .V_Data = XData
    End With
Loop
End Sub

'--------------------------------------------------------------------------------------------------------------
Function TSNEPlay_INT_SendData(V_ToPlayerID As Uinteger, V_Data As String, Byref R_LocalSend As Ubyte) As TSNEPlay_GURUCode
'Print "OUT:"; V_ToPlayerID; " "; Len(V_Data); "  ";: For XXX as UInteger = 1 to Len(V_Data): Print V_Data[XXX - 1]; " ";: Next: Print
R_LocalSend = 0
If TSNEPlay_INT_ClientMode = 1 Then
    TSNE_Data_Send(TSNEPlay_INT_Client_TSNEID, V_Data)
    Return TSNEPlay_NoError
End If
Dim TPtr As TSNEPlay_INT_Client_Type Ptr
Mutexlock(TSNEPlay_INT_Mutex)
If V_ToPlayerID > 0 Then
    Dim TSID As Uinteger
    TPtr = TSNEPlay_INT_ClientGetPID(V_ToPlayerID)
    If TPtr = 0 Then Mutexunlock(TSNEPlay_INT_Mutex): Return TSNEPlay_PlayerIDNotFound
    TSID = TPtr->V_TSNEID
    Mutexunlock(TSNEPlay_INT_Mutex)
    If TSID > 0 Then
        TSNE_Data_Send(TSID, V_Data)
    Else: R_LocalSend = 1
    End If
Else
    Dim DD() As Uinteger
    Dim DC As Uinteger
    Dim DX As Uinteger
    TPtr = TSNEPlay_INT_ClientF
    Do Until TPtr = 0
        If TPtr->V_State = TSNEPlay_State_Ready Then
            If TPtr->V_TSNEID > 0 Then
                DC += 1
                If DC > DX Then
                    DX += 4
                    Redim Preserve DD(DX) As Uinteger
                End If
                DD(DC) = TPtr->V_TSNEID
            Else: R_LocalSend = 1
            End If
        End If
        TPtr = TPtr->V_Next
    Loop
    Mutexunlock(TSNEPlay_INT_Mutex)
    For X As Uinteger = 1 To DC
        TSNE_Data_Send(DD(X), V_Data)
    Next
End If
Return TSNEPlay_NoError
End Function



'##############################################################################################################
Sub TSNEPlay_INT_SendPlayerTable(V_TSNEID As Uinteger)
Dim D As String
Dim TMS0 As String
Dim TMS1 As String
Dim TMV0 As Uinteger
Mutexlock(TSNEPlay_INT_Mutex)
Dim TPtr As TSNEPlay_INT_Client_Type Ptr = TSNEPlay_INT_ClientF
Do Until TPtr = 0
    If TPtr->V_TSNEID <> V_TSNEID Then
        With *TPtr
            TMS1 = Chr((.V_PlayerID Shr 24) And 255) & Chr((.V_PlayerID Shr 16) And 255) & Chr((.V_PlayerID Shr 8) And 255) & Chr(.V_PlayerID And 255)
            TMV0 = 0: TMS1 += Chr((TMV0 Shr 24) And 255) & Chr((TMV0 Shr 16) And 255) & Chr((TMV0 Shr 8) And 255) & Chr(TMV0 And 255)
            TMS1 += ""
            TMV0 = Len(.V_Nickname): TMS1 += Chr((TMV0 Shr 24) And 255) & Chr((TMV0 Shr 16) And 255) & Chr((TMV0 Shr 8) And 255) & Chr(TMV0 And 255)
            TMS1 += .V_Nickname
            TMS1 = TSNEPlay_INT_CreateStreamCommand(TSNEPlay_INT_MSGT_Con, TMS1)
            D += TMS1
        End With
    End If
    TPtr = TPtr->V_Next
Loop
Mutexunlock(TSNEPlay_INT_Mutex)
TSNE_Data_Send(V_TSNEID, D)
End Sub



'##############################################################################################################
Sub TSNEPlay_INT_Disconnected(Byval V_TSNEID As Uinteger)
'Print "DIS:"; V_TSNEID
If TSNEPlay_INT_ClientMode = 1 Then
    TSNEPlay_INT_State = TSNEPlay_State_Disconnected
    If TSNEPlay_INT_Event_ConnectionState <> 0 Then TSNEPlay_INT_Event_ConnectionState(TSNEPlay_INT_Client_PlayerID, TSNEPlay_INT_State)
    Exit Sub
End If
Mutexlock(TSNEPlay_INT_Mutex)
Dim TPtr As TSNEPlay_INT_Client_Type Ptr = TSNEPlay_INT_ClientGetTSNEID(V_TSNEID)
If TPtr = 0 Then Mutexunlock(TSNEPlay_INT_Mutex): TSNE_Disconnect(V_TSNEID): Exit Sub
Dim TPID As Uinteger = TPtr->V_PlayerID
Dim TAOK As TSNEPlay_State_Enum = TPtr->V_State
TSNEPlay_INT_ClientDel(TPtr)
Mutexunlock(TSNEPlay_INT_Mutex)
If TSNEPlay_INT_Event_Player_Disconnected <> 0 Then TSNEPlay_INT_Event_Player_Disconnected(TPID)
If TAOK <> TSNEPlay_State_Ready Then Exit Sub
Dim T As String = Chr((TPID Shr 24) And 255) & Chr((TPID Shr 16) And 255) & Chr((TPID Shr 8) And 255) & Chr(TPID And 255)
T = TSNEPlay_INT_CreateStreamCommand(TSNEPlay_INT_MSGT_Dis, T)
Dim TLocalSend As Ubyte
Dim RV As TSNEPlay_GURUCode = TSNEPlay_INT_SendData(0, T, TLocalSend)
End Sub

'--------------------------------------------------------------------------------------------------------------
Sub TSNEPlay_INT_Connected(Byval V_TSNEID As Uinteger)
'Print "CON:"; V_TSNEID
If TSNEPlay_INT_ClientMode = 1 Then
    TSNEPlay_INT_State = TSNEPlay_State_Connected
    If TSNEPlay_INT_Event_ConnectionState <> 0 Then TSNEPlay_INT_Event_ConnectionState(TSNEPlay_INT_Client_PlayerID, TSNEPlay_INT_State)
    Exit Sub
End If
Mutexlock(TSNEPlay_INT_Mutex)
Dim TPtr As TSNEPlay_INT_Client_Type Ptr = TSNEPlay_INT_ClientGetTSNEID(V_TSNEID)
If TPtr = 0 Then Mutexunlock(TSNEPlay_INT_Mutex): TSNE_Disconnect(V_TSNEID): Exit Sub
Dim TPID As Uinteger
With *TPtr
    If TSNEPlay_INT_ServerPassword = "" Then
        .V_State        = TSNEPlay_State_Connected
    Else: .V_State      = TSNEPlay_State_Login
    End If
    TPID = .V_PlayerID
End With
Mutexunlock(TSNEPlay_INT_Mutex)
If TSNEPlay_INT_ServerPassword <> "" Then
    TSNE_Data_Send(V_TSNEID, TSNEPlay_INT_CreateStreamCommand(TSNEPlay_INT_MSGT_NeedPassword))
Else: TSNE_Data_Send(V_TSNEID, TSNEPlay_INT_CreateStreamCommand(TSNEPlay_INT_MSGT_GetInfo, Str(TPID)))
End If
End Sub

'--------------------------------------------------------------------------------------------------------------
Sub TSNEPlay_INT_NewData(Byval V_TSNEID As Uinteger, Byref V_Data As String)
'Print "DAT:"; V_TSNEID; " "; Len(V_Data); "  ";: For XXX as UInteger = 1 to Len(V_Data): Print V_Data[XXX - 1]; " ";: Next: Print
Dim TCMDQueF As TSNEPlay_INT_CommandQue_Type Ptr
Dim TCMDQueL As TSNEPlay_INT_CommandQue_Type Ptr
Dim TCInfo As TSNEPlay_INT_Client_Type
Dim TPtr As TSNEPlay_INT_Client_Type Ptr
If TSNEPlay_INT_ClientMode = 1 Then
    If Len(TSNEPlay_INT_Client_Data) > 10000 Then
        TSNE_Data_Send(V_TSNEID, TSNEPlay_INT_CreateStreamCommand(TSNEPlay_INT_MSGT_StreamError))
        TSNE_Disconnect(V_TSNEID)
        Exit Sub
    End If
    TSNEPlay_INT_Client_Data += V_Data
    TSNEPlay_INT_ParseStreamCommand(TSNEPlay_INT_Client_Data, TCMDQueF, TCMDQueL)
Else
    Mutexlock(TSNEPlay_INT_Mutex)
    TPtr = TSNEPlay_INT_ClientGetTSNEID(V_TSNEID)
    If TPtr = 0 Then Mutexunlock(TSNEPlay_INT_Mutex): TSNE_Disconnect(V_TSNEID): Exit Sub
    Dim TData As String = TPtr->V_Data & V_Data
    Mutexunlock(TSNEPlay_INT_Mutex)
    If Len(TData) > 10000 Then
        TSNE_Data_Send(V_TSNEID, TSNEPlay_INT_CreateStreamCommand(TSNEPlay_INT_MSGT_StreamError))
        TSNE_Disconnect(V_TSNEID)
        Exit Sub
    End If
    TSNEPlay_INT_ParseStreamCommand(TData, TCMDQueF, TCMDQueL)
    Mutexlock(TSNEPlay_INT_Mutex)
    TPtr = TSNEPlay_INT_ClientGetTSNEID(V_TSNEID)
    If TPtr = 0 Then Mutexunlock(TSNEPlay_INT_Mutex): TSNE_Disconnect(V_TSNEID): Exit Sub
    TPtr->V_Data = TData
    TCInfo = *TPtr
    Mutexunlock(TSNEPlay_INT_Mutex)
End If
Dim TLocalSend As Ubyte
Dim RV As TSNEPlay_GURUCode
Dim XErrExit As Ubyte
Dim TMV0 As Uinteger
Dim TMV1 As Uinteger
Dim TMV2 As Double
Dim TMV3 As Double
Dim TMV4 As Double
Dim TMV5 As Uinteger
Dim TMV6 As Uinteger
Dim TMV7 As Uinteger
Dim TMVI1 As Integer
Dim TMVI2 As Integer
Dim TMVI3 As Integer
Dim TMS0 As String
Dim TMS1 As String
Do Until TCMDQueF = 0
    TCMDQueL = TCMDQueF->V_Next
    If XErrExit = 0 Then
        With *TCMDQueF
            TMV0 = 0
            TMV1 = 0
            TMV2 = 0
            TMV3 = 0
            TMV4 = 0
            TMV5 = 0
            TMS0 = ""
            TMS1 = ""
'           Print "CMD: >"; Str(.V_CMDType); "<___>"; .V_Data; "<"
'           Print #1, "IN_CMD: >"; Str(.V_CMDType); "<___>"; Str(Len(.V_Data)); "<"
            If TSNEPlay_INT_ClientMode = 1 Then
                Select Case .V_CMDType
                    Case TSNEPlay_INT_MSGT_Unknown
                    
                    Case TSNEPlay_INT_MSGT_Full
                        
                    Case TSNEPlay_INT_MSGT_NeedPassword
                        If TSNEPlay_INT_State = TSNEPlay_State_Connected Then
                            TSNEPlay_INT_State = TSNEPlay_State_Login
                            If TSNEPlay_INT_Event_ConnectionState <> 0 Then TSNEPlay_INT_Event_ConnectionState(TSNEPlay_INT_Client_PlayerID, TSNEPlay_INT_State)
                            TSNE_Data_Send(V_TSNEID, TSNEPlay_INT_CreateStreamCommand(TSNEPlay_INT_MSGT_Password, TSNEPlay_INT_ServerPassword))
                        End If
                        
                    Case TSNEPlay_INT_MSGT_PasswordWrong
                        XErrExit = 1
                        
                    Case TSNEPlay_INT_MSGT_GetInfo
                        TSNEPlay_INT_Client_PlayerID = Valuint(.V_Data)
                        TMV0 = Len(TSNEPlay_INT_Nickname): TMS0 += Chr((TMV0 Shr 24) And 255) & Chr((TMV0 Shr 16) And 255) & Chr((TMV0 Shr 8) And 255) & Chr(TMV0 And 255)
                        TMS0 += TSNEPlay_INT_Nickname
                        TSNE_Data_Send(V_TSNEID, TSNEPlay_INT_CreateStreamCommand(TSNEPlay_INT_MSGT_PutInfo, TMS0))
                        
                    Case TSNEPlay_INT_MSGT_PutInfo
                        
                    Case TSNEPlay_INT_MSGT_Ready
                        TSNEPlay_INT_State = TSNEPlay_State_Ready
                        If TSNEPlay_INT_Event_ConnectionState <> 0 Then TSNEPlay_INT_Event_ConnectionState(TSNEPlay_INT_Client_PlayerID, TSNEPlay_INT_State)
                        
                    Case TSNEPlay_INT_MSGT_StreamError
                        XErrExit = 1
                        
                    Case TSNEPlay_INT_MSGT_Ping
                        
                    Case TSNEPlay_INT_MSGT_MSG
                        If TSNEPlay_INT_Event_Message <> 0 Then
                            If Len(.V_Data) >= 16 Then
                                TMV0 = (.V_Data[0] Shl 24) Or (.V_Data[1] Shl 16) Or (.V_Data[2] Shl 8) Or .V_Data[3]
                                TMV1 = (.V_Data[4] Shl 24) Or (.V_Data[5] Shl 16) Or (.V_Data[6] Shl 8) Or .V_Data[7]
                                TMV6 = (.V_Data[8] Shl 24) Or (.V_Data[9] Shl 16) Or (.V_Data[10] Shl 8) Or .V_Data[11]
                                TMV7 = (.V_Data[12] Shl 24) Or (.V_Data[13] Shl 16) Or (.V_Data[14] Shl 8) Or .V_Data[15]
                                If (Len(.V_Data) - 16) >= TMV7 Then
                                    TMS0 = Mid(.V_Data, 17, TMV7)
                                    TSNEPlay_INT_Event_Message(TMV0, TMV1, TMS0, Cast(TSNEPlay_MessageType_Enum, TMV6))
                                End If
                            End If
                        End If
                        
                    Case TSNEPlay_INT_MSGT_Move
                        If TSNEPlay_INT_Event_Move <> 0 Then
                            If Len(.V_Data) >= 36 Then
                                TMV0 = (.V_Data[0] Shl 24) Or (.V_Data[1] Shl 16) Or (.V_Data[2] Shl 8) Or .V_Data[3]
                                TMV1 = (.V_Data[4] Shl 24) Or (.V_Data[5] Shl 16) Or (.V_Data[6] Shl 8) Or .V_Data[7]
                                TMVI1 = *Cast(Integer Ptr, @.V_Data[8])
                                TMVI2 = *Cast(Integer Ptr, @.V_Data[16])
                                TMVI3 = *Cast(Integer Ptr, @.V_Data[24])
                                TMV5 = (.V_Data[32] Shl 24) Or (.V_Data[33] Shl 16) Or (.V_Data[34] Shl 8) Or .V_Data[35]
                                TSNEPlay_INT_Event_Move(TMV0, TMV1, TMVI1, TMVI2, TMVI3, TMV5)
                            End If
                        End If
                        
                    Case TSNEPlay_INT_MSGT_MoveDbl
                        If TSNEPlay_INT_Event_Move <> 0 Then
                            If Len(.V_Data) >= 36 Then
                                TMV0 = (.V_Data[0] Shl 24) Or (.V_Data[1] Shl 16) Or (.V_Data[2] Shl 8) Or .V_Data[3]
                                TMV1 = (.V_Data[4] Shl 24) Or (.V_Data[5] Shl 16) Or (.V_Data[6] Shl 8) Or .V_Data[7]
                                TMV2 = *Cast(Double Ptr, @.V_Data[8])
                                TMV3 = *Cast(Double Ptr, @.V_Data[16])
                                TMV4 = *Cast(Double Ptr, @.V_Data[24])
                                TMV5 = (.V_Data[32] Shl 24) Or (.V_Data[33] Shl 16) Or (.V_Data[34] Shl 8) Or .V_Data[35]
                                TSNEPlay_INT_Event_Move(TMV0, TMV1, TMV2, TMV3, TMV4, TMV5)
                            End If
                        End If
                    
                    Case TSNEPlay_INT_MSGT_Dat
                        If TSNEPlay_INT_Event_Data <> 0 Then
                            If Len(.V_Data) >= 12 Then
                                TMV0 = (.V_Data[0] Shl 24) Or (.V_Data[1] Shl 16) Or (.V_Data[2] Shl 8) Or .V_Data[3]
                                TMV1 = (.V_Data[4] Shl 24) Or (.V_Data[5] Shl 16) Or (.V_Data[6] Shl 8) Or .V_Data[7]
                                TMV6 = (.V_Data[8] Shl 24) Or (.V_Data[9] Shl 16) Or (.V_Data[10] Shl 8) Or .V_Data[11]
                                If (Len(.V_Data) - 12) >= TMV6 Then
                                    TMS0 = Mid(.V_Data, 13, TMV6)
                                    TSNEPlay_INT_Event_Data(TMV0, TMV1, TMS0)
                                End If
                            End If
                        End If
                        
                    Case TSNEPlay_INT_MSGT_Con
                        If TSNEPlay_INT_Event_Player_Connected <> 0 Then
                            If Len(.V_Data) >= 8 Then
                                TMV0 = (.V_Data[0] Shl 24) Or (.V_Data[1] Shl 16) Or (.V_Data[2] Shl 8) Or .V_Data[3]
                                TMV1 = (.V_Data[4] Shl 24) Or (.V_Data[5] Shl 16) Or (.V_Data[6] Shl 8) Or .V_Data[7]
                                If (Len(.V_Data) - 8) >= TMV1 Then
                                    TMS0 = Mid(.V_Data, 9, TMV1)
                                    .V_Data = Mid(.V_Data, 9 + TMV1)
                                    TMV1 = (.V_Data[0] Shl 24) Or (.V_Data[1] Shl 16) Or (.V_Data[2] Shl 8) Or .V_Data[3]
                                    If (Len(.V_Data) - 4) >= TMV1 Then
                                        TMS1 = Mid(.V_Data, 5, TMV1)
                                        TSNEPlay_INT_Event_Player_Connected(TMV0, TMS0, TMS1)
                                    End If
                                End If
                            End If
                        End If
                        
                    Case TSNEPlay_INT_MSGT_Dis
                        If TSNEPlay_INT_Event_Player_Disconnected <> 0 Then
                            If Len(.V_Data) >= 4 Then
                                TMV0 = (.V_Data[0] Shl 24) Or (.V_Data[1] Shl 16) Or (.V_Data[2] Shl 8) Or .V_Data[3]
                                TSNEPlay_INT_Event_Player_Disconnected(TMV0)
                            End If
                        End If
                        
                End Select
            Else
                Select Case .V_CMDType
                    Case TSNEPlay_INT_MSGT_Unknown
                    Case TSNEPlay_INT_MSGT_Password
                        If .V_Data <> TSNEPlay_INT_ServerPassword Then
                            XErrExit = 1
                            TSNE_Data_Send(V_TSNEID, TSNEPlay_INT_CreateStreamCommand(TSNEPlay_INT_MSGT_Ready))
                        Else: TSNE_Data_Send(V_TSNEID, TSNEPlay_INT_CreateStreamCommand(TSNEPlay_INT_MSGT_GetInfo, Str(TCInfo.V_PlayerID)))
                        End If
                        
                    Case TSNEPlay_INT_MSGT_GetInfo
                        
                    Case TSNEPlay_INT_MSGT_PutInfo
                        If (TCInfo.V_State = TSNEPlay_State_Connected) Or (TCInfo.V_State = TSNEPlay_State_Login) Then
                            If Len(.V_Data) >= 4 Then
                                TMV0 = (.V_Data[0] Shl 24) Or (.V_Data[1] Shl 16) Or (.V_Data[2] Shl 8) Or .V_Data[3]
                                TMS0 = Mid(.V_Data, 5, TMV0)
                                Mutexlock(TSNEPlay_INT_Mutex)
                                TPtr = TSNEPlay_INT_ClientGetTSNEID(V_TSNEID)
                                If TPtr > 0 Then
                                    TPtr->V_Nickname = TMS0
                                    TPtr->V_State = TSNEPlay_State_Ready
                                End If
                                Mutexunlock(TSNEPlay_INT_Mutex)
                                TSNE_Data_Send(V_TSNEID, TSNEPlay_INT_CreateStreamCommand(TSNEPlay_INT_MSGT_Ready))
                                TSNEPlay_INT_Event_Player_Connected(TCInfo.V_PlayerID, TCInfo.V_IPA, TMS0)
                                TMS1 += Chr((TCInfo.V_PlayerID Shr 24) And 255) & Chr((TCInfo.V_PlayerID Shr 16) And 255) & Chr((TCInfo.V_PlayerID Shr 8) And 255) & Chr(TCInfo.V_PlayerID And 255)
                                TMV0 = 0: TMS1 += Chr((TMV0 Shr 24) And 255) & Chr((TMV0 Shr 16) And 255) & Chr((TMV0 Shr 8) And 255) & Chr(TMV0 And 255)
                                TMS1 += ""
                                TMV0 = Len(TMS0): TMS1 += Chr((TMV0 Shr 24) And 255) & Chr((TMV0 Shr 16) And 255) & Chr((TMV0 Shr 8) And 255) & Chr(TMV0 And 255)
                                TMS1 += TMS0
                                TMS1 = TSNEPlay_INT_CreateStreamCommand(TSNEPlay_INT_MSGT_Con, TMS1)
                                RV = TSNEPlay_INT_SendData(0, TMS1, TLocalSend)
                                TSNEPlay_INT_SendPlayerTable(V_TSNEID)
                            End If
                        End If
                        
                    Case TSNEPlay_INT_MSGT_Ready
                        
                    Case TSNEPlay_INT_MSGT_StreamError
                        XErrExit = 1
                        
                    Case TSNEPlay_INT_MSGT_Pong
                        
                    Case TSNEPlay_INT_MSGT_MSG
                        If Len(.V_Data) >= 16 Then
                            TMV1 = (.V_Data[4] Shl 24) Or (.V_Data[5] Shl 16) Or (.V_Data[6] Shl 8) Or .V_Data[7]
                            RV = TSNEPlay_INT_SendData(TMV1, .V_RAW, TLocalSend)
                            If TLocalSend = 1 Then
                                If TSNEPlay_INT_Event_Message <> 0 Then
                                    TMV0 = (.V_Data[0] Shl 24) Or (.V_Data[1] Shl 16) Or (.V_Data[2] Shl 8) Or .V_Data[3]
                                    TMV6 = (.V_Data[8] Shl 24) Or (.V_Data[9] Shl 16) Or (.V_Data[10] Shl 8) Or .V_Data[11]
                                    TMV7 = (.V_Data[12] Shl 24) Or (.V_Data[13] Shl 16) Or (.V_Data[14] Shl 8) Or .V_Data[15]
                                    If (Len(.V_Data) - 16) >= TMV7 Then
                                        TMS0 = Mid(.V_Data, 17, TMV7)
                                        TSNEPlay_INT_Event_Message(TMV0, TMV1, TMS0, Cast(TSNEPlay_MessageType_Enum, TMV6))
                                    End If
                                End If
                            End If
                        End If
                        
                    Case TSNEPlay_INT_MSGT_Move
                        If Len(.V_Data) >= 36 Then
                            TMV1 = (.V_Data[4] Shl 24) Or (.V_Data[5] Shl 16) Or (.V_Data[6] Shl 8) Or .V_Data[7]
                            RV = TSNEPlay_INT_SendData(TMV1, .V_RAW, TLocalSend)
                            If TLocalSend = 1 Then
                                If TSNEPlay_INT_Event_Move <> 0 Then
                                    TMV0 = (.V_Data[0] Shl 24) Or (.V_Data[1] Shl 16) Or (.V_Data[2] Shl 8) Or .V_Data[3]
                                    TMV1 = (.V_Data[4] Shl 24) Or (.V_Data[5] Shl 16) Or (.V_Data[6] Shl 8) Or .V_Data[7]
                                    TMVI1 = *Cast(Integer Ptr, @.V_Data[8])
                                    TMVI2 = *Cast(Integer Ptr, @.V_Data[16])
                                    TMVI3 = *Cast(Integer Ptr, @.V_Data[24])
                                    TMV5 = (.V_Data[32] Shl 24) Or (.V_Data[33] Shl 16) Or (.V_Data[34] Shl 8) Or .V_Data[35]
                                    TSNEPlay_INT_Event_Move(TMV0, TMV1, TMVI1, TMVI2, TMVI3, TMV5)
                                End If
                            End If
                        End If
                        
                    Case TSNEPlay_INT_MSGT_MoveDbl
                        If Len(.V_Data) >= 36 Then
                            TMV1 = (.V_Data[4] Shl 24) Or (.V_Data[5] Shl 16) Or (.V_Data[6] Shl 8) Or .V_Data[7]
                            RV = TSNEPlay_INT_SendData(TMV1, .V_RAW, TLocalSend)
                            If TLocalSend = 1 Then
                                If TSNEPlay_INT_Event_Move <> 0 Then
                                    TMV0 = (.V_Data[0] Shl 24) Or (.V_Data[1] Shl 16) Or (.V_Data[2] Shl 8) Or .V_Data[3]
                                    TMV1 = (.V_Data[4] Shl 24) Or (.V_Data[5] Shl 16) Or (.V_Data[6] Shl 8) Or .V_Data[7]
                                    TMV2 = *Cast(Double Ptr, @.V_Data[8])
                                    TMV3 = *Cast(Double Ptr, @.V_Data[16])
                                    TMV4 = *Cast(Double Ptr, @.V_Data[24])
                                    TMV5 = (.V_Data[32] Shl 24) Or (.V_Data[33] Shl 16) Or (.V_Data[34] Shl 8) Or .V_Data[35]
                                    TSNEPlay_INT_Event_Move(TMV0, TMV1, TMV2, TMV3, TMV4, TMV5)
                                End If
                            End If
                        End If
                        
                    Case TSNEPlay_INT_MSGT_Dat
                        If Len(.V_Data) >= 12 Then
                            TMV1 = (.V_Data[4] Shl 24) Or (.V_Data[5] Shl 16) Or (.V_Data[6] Shl 8) Or .V_Data[7]
                            RV = TSNEPlay_INT_SendData(TMV1, .V_RAW, TLocalSend)
                            If TLocalSend = 1 Then
                                If TSNEPlay_INT_Event_Data <> 0 Then
                                    TMV0 = (.V_Data[0] Shl 24) Or (.V_Data[1] Shl 16) Or (.V_Data[2] Shl 8) Or .V_Data[3]
                                    TMV6 = (.V_Data[8] Shl 24) Or (.V_Data[9] Shl 16) Or (.V_Data[10] Shl 8) Or .V_Data[11]
                                    If (Len(.V_Data) - 12) >= TMV6 Then
                                        TMS0 = Mid(.V_Data, 13, TMV6)
                                        TSNEPlay_INT_Event_Data(TMV0, TMV1, TMS0)
                                    End If
                                End If
                            End If
                        End If
                        
                End Select
            End If
        End With
    End If
    Deallocate(TCMDQueF)
    TCMDQueF = TCMDQueL
Loop
If XErrExit = 1 Then TSNE_Disconnect(V_TSNEID)
End Sub

'--------------------------------------------------------------------------------------------------------------
Sub TSNEPlay_INT_NewConnection(Byval V_TSNEID As Uinteger, Byval V_RequestID As Socket, Byval V_IPA As String)
'Print "NEW:"; V_TSNEID; " "; V_IPA
Dim RV As Integer
Dim TNewTSNEID As Uinteger
Mutexlock(TSNEPlay_INT_Mutex)
If TSNEPlay_INT_ClientC >= TSNEPlay_INT_Server_MaxPlayer Then
    Mutexunlock(TSNEPlay_INT_Mutex)
    RV = TSNE_Create_Accept(V_RequestID, TNewTSNEID, , @TSNEPlay_INT_Disconnected, @TSNEPlay_INT_Connected, 0)
    RV = TSNE_Data_Send(TNewTSNEID, TSNEPlay_INT_CreateStreamCommand(TSNEPlay_INT_MSGT_Full))
    RV = TSNE_Disconnect(TNewTSNEID)
    Exit Sub
End If
RV = TSNE_Create_Accept(V_RequestID, TNewTSNEID, , @TSNEPlay_INT_Disconnected, @TSNEPlay_INT_Connected, @TSNEPlay_INT_NewData)
Dim TPtr As TSNEPlay_INT_Client_Type Ptr = TSNEPlay_INT_ClientAdd()
With *TPtr
    .V_TSNEID       = TNewTSNEID
    .V_IPA          = V_IPA
    .V_State        = TSNEPlay_State_Connecting
End With
Mutexunlock(TSNEPlay_INT_Mutex)
End Sub



'##############################################################################################################
Function TSNEPlay_CreateServer(V_MaxPlayer As Ushort, V_Port As Ushort, V_Nickname As String, V_Password As String = "", Byval V_EventPtr_ConnectionState As Any Ptr = 0, Byval V_EventPtr_Player_Connected As Any Ptr, Byval V_EventPtr_Player_Disconnected As Any Ptr, Byval V_EventPtr_Message As Any Ptr, Byval V_EventPtr_Move As Any Ptr, Byval V_EventPtr_MoveDbl As Any Ptr, Byval V_EventPtr_Data As Any Ptr, V_NoSelfPlayer As Ubyte = 1) As TSNEPlay_GURUCode
If TSNEPlay_INT_State <> TSNEPlay_State_Unknown Then Return TSNEPlay_NotReadyForNewConnection
TSNEPlay_INT_Client_PlayerID = 0
TSNEPlay_INT_Server_MaxPlayer = V_MaxPlayer
TSNEPlay_INT_ServerPassword = V_Password
TSNEPlay_INT_Nickname = V_Nickname
TSNEPlay_INT_ClientMode = 0
TSNEPlay_INT_Event_ConnectionState      = V_EventPtr_ConnectionState
TSNEPlay_INT_Event_Player_Connected     = V_EventPtr_Player_Connected
TSNEPlay_INT_Event_Player_Disconnected  = V_EventPtr_Player_Disconnected
TSNEPlay_INT_Event_Message              = V_EventPtr_Message
TSNEPlay_INT_Event_Move                 = V_EventPtr_Move
TSNEPlay_INT_Event_Data                 = V_EventPtr_Data
TSNEPlay_INT_State = TSNEPlay_State_Connecting
If TSNEPlay_INT_Event_ConnectionState <> 0 Then TSNEPlay_INT_Event_ConnectionState(TSNEPlay_INT_Client_PlayerID, TSNEPlay_INT_State)
Dim RV As Integer = TSNE_Create_Server(TSNEPlay_INT_Server_TSNEID, V_Port, 100, @TSNEPlay_INT_NewConnection)
If RV <> TSNE_Const_NoError Then TSNEPlay_INT_State = TSNEPlay_State_Unknown: Return RV
If V_NoSelfPlayer = 0 Then
    Dim TPtr As TSNEPlay_INT_Client_Type Ptr = TSNEPlay_INT_ClientAdd()
    With *TPtr
        TSNEPlay_INT_Server_PlayerID = .V_PlayerID
        .V_Nickname     = V_Nickname
        .V_TSNEID       = 0
        .V_IPA          = "127.0.0.1"
        .V_State        = TSNEPlay_State_Ready
    End With
End If
TSNEPlay_INT_State = TSNEPlay_State_Ready
If TSNEPlay_INT_Event_ConnectionState <> 0 Then TSNEPlay_INT_Event_ConnectionState(TSNEPlay_INT_Client_PlayerID, TSNEPlay_INT_State)
Return TSNEPlay_NoError
End Function

'--------------------------------------------------------------------------------------------------------------
Function TSNEPlay_ConnectToServer(V_Host As String, V_Port As Ushort, V_Nickname As String, V_Password As String = "", Byval V_EventPtr_ConnectionState As Any Ptr = 0, Byval V_EventPtr_Player_Connected As Any Ptr, Byval V_EventPtr_Player_Disconnected As Any Ptr, Byval V_EventPtr_Message As Any Ptr, Byval V_EventPtr_Move As Any Ptr, Byval V_EventPtr_MoveDbl As Any Ptr, Byval V_EventPtr_Data As Any Ptr) As TSNEPlay_GURUCode
If TSNEPlay_INT_State <> TSNEPlay_State_Unknown Then Return TSNEPlay_NotReadyForNewConnection
TSNEPlay_INT_Client_PlayerID = 0
TSNEPlay_INT_ServerPassword = V_Password
TSNEPlay_INT_Nickname = V_Nickname
TSNEPlay_INT_ClientMode = 1
TSNEPlay_INT_Event_ConnectionState      = V_EventPtr_ConnectionState
TSNEPlay_INT_Event_Player_Connected     = V_EventPtr_Player_Connected
TSNEPlay_INT_Event_Player_Disconnected  = V_EventPtr_Player_Disconnected
TSNEPlay_INT_Event_Message              = V_EventPtr_Message
TSNEPlay_INT_Event_Move                 = V_EventPtr_Move
TSNEPlay_INT_Event_Data                 = V_EventPtr_Data
TSNEPlay_INT_State = TSNEPlay_State_Connecting
If TSNEPlay_INT_Event_ConnectionState <> 0 Then TSNEPlay_INT_Event_ConnectionState(TSNEPlay_INT_Client_PlayerID, TSNEPlay_INT_State)
Dim RV As Integer = TSNE_Create_Client(TSNEPlay_INT_Client_TSNEID, V_Host, V_Port, @TSNEPlay_INT_Disconnected, @TSNEPlay_INT_Connected, @TSNEPlay_INT_NewData, 60)
If RV <> TSNE_Const_NoError Then TSNEPlay_INT_State = TSNEPlay_State_Unknown: Return RV
Return TSNEPlay_NoError
End Function

'--------------------------------------------------------------------------------------------------------------
Function TSNEPlay_CloseAll() As TSNEPlay_GURUCode
If TSNEPlay_INT_Server_TSNEID <> 0 Then
    TSNE_Disconnect(TSNEPlay_INT_Server_TSNEID)
    TSNE_WaitClose(TSNEPlay_INT_Server_TSNEID)
    TSNEPlay_INT_Server_TSNEID = 0
    Mutexlock(TSNEPlay_INT_Mutex)
    Dim TPtr1 As TSNEPlay_INT_Client_Type Ptr = TSNEPlay_INT_ClientF
    Dim TPtr2 As TSNEPlay_INT_Client_Type Ptr
    Dim TSID As Uinteger
    Do Until TPtr1 = 0
        TPtr2 = TPtr1->V_Next
        TSID = TPtr1->V_TSNEID
        If TSID > 0 Then TSNE_Disconnect(TSID)
        TPtr1 = TPtr2
    Loop
    Mutexunlock(TSNEPlay_INT_Mutex)
    Mutexlock(TSNEPlay_INT_Mutex)
    TPtr1 = TSNEPlay_INT_ClientF
    Do Until TPtr1 = 0
        TPtr2 = TPtr1->V_Next
        TSID = TPtr1->V_TSNEID
        If TSID > 0 Then
            Mutexunlock(TSNEPlay_INT_Mutex)
            TSNE_WaitClose(TSID)
            Mutexlock(TSNEPlay_INT_Mutex)
        End If
        TPtr1 = TPtr2
    Loop
    TSNEPlay_INT_ClientF = 0
    TSNEPlay_INT_ClientL = 0
    Mutexunlock(TSNEPlay_INT_Mutex)
End If
If TSNEPlay_INT_Client_TSNEID <> 0 Then
    TSNE_Disconnect(TSNEPlay_INT_Client_TSNEID)
    TSNE_WaitClose(TSNEPlay_INT_Client_TSNEID)
    TSNEPlay_INT_Client_TSNEID = 0
End If
TSNEPlay_INT_State = TSNEPlay_State_Unknown
TSNEPlay_INT_Server_MaxPlayer = 0
TSNEPlay_INT_ServerPassword = ""
TSNEPlay_INT_Nickname = ""
TSNEPlay_INT_ClientMode = 0
TSNEPlay_INT_Event_ConnectionState      = 0
TSNEPlay_INT_Event_Player_Connected     = 0
TSNEPlay_INT_Event_Player_Disconnected  = 0
TSNEPlay_INT_Event_Message              = 0
TSNEPlay_INT_Event_Move                 = 0
TSNEPlay_INT_Event_Data                 = 0
Return TSNEPlay_NoError
End Function



'##############################################################################################################
Function TSNEPlay_Connection_GetState() As TSNEPlay_State_Enum
Return TSNEPlay_INT_State
End Function



'##############################################################################################################
Function TSNEPlay_SendMSG(V_ToPlayerID As Uinteger, V_Message As String, V_MessageType As TSNEPlay_MessageType_Enum = TSNEPlay_MSGType_Regular) As TSNEPlay_GURUCode
'<FromPlayerID><ToPlayerID><MSGType><MSG>
If Len(V_Message) > 4096 Then Return TSNEPlay_MessageToLong
If TSNEPlay_INT_State <> TSNEPlay_State_Ready Then Return TSNEPlay_NotReadyForNewConnection
Dim T As String
Dim FPID As Uinteger
If TSNEPlay_INT_ClientMode = 1 Then
    FPID = TSNEPlay_INT_Client_PlayerID
Else: FPID = TSNEPlay_INT_Server_PlayerID
End If
T += Chr((FPID Shr 24) And 255) & Chr((FPID Shr 16) And 255) & Chr((FPID Shr 8) And 255) & Chr(FPID And 255)
T += Chr((V_ToPlayerID Shr 24) And 255) & Chr((V_ToPlayerID Shr 16) And 255) & Chr((V_ToPlayerID Shr 8) And 255) & Chr(V_ToPlayerID And 255)
T += Chr((V_MessageType Shr 24) And 255) & Chr((V_MessageType Shr 16) And 255) & Chr((V_MessageType Shr 8) And 255) & Chr(V_MessageType And 255)
Dim MX As Uinteger = Len(V_Message)
T += Chr((MX Shr 24) And 255) & Chr((MX Shr 16) And 255) & Chr((MX Shr 8) And 255) & Chr(MX And 255)
T += V_Message
T = TSNEPlay_INT_CreateStreamCommand(TSNEPlay_INT_MSGT_MSG, T)
Dim TLocalSend As Ubyte
Dim RV As TSNEPlay_GURUCode = TSNEPlay_INT_SendData(V_ToPlayerID, T, TLocalSend)
If TLocalSend = 1 Then If TSNEPlay_INT_Event_Message <> 0 Then TSNEPlay_INT_Event_Message(FPID, V_ToPlayerID, V_Message, V_MessageType)
Return RV
End Function

'--------------------------------------------------------------------------------------------------------------
Function TSNEPlay_SendMove(V_ToPlayerID As Uinteger, V_NewPositonX As Double = 0, V_NewPositonY As Double = 0, V_NewPositonZ As Double = 0, Byval V_SubData As Uinteger = 0) As TSNEPlay_GURUCode
'<FromPlayerID><ToPlayerID><PosX><PosY><PosZ><SubData>
If TSNEPlay_INT_State <> TSNEPlay_State_Ready Then Return TSNEPlay_NotReadyForNewConnection
Dim T As String
Dim FPID As Uinteger
If TSNEPlay_INT_ClientMode = 1 Then
    FPID = TSNEPlay_INT_Client_PlayerID
Else: FPID = TSNEPlay_INT_Server_PlayerID
End If
T += Chr((FPID Shr 24) And 255) & Chr((FPID Shr 16) And 255) & Chr((FPID Shr 8) And 255) & Chr(FPID And 255)
T += Chr((V_ToPlayerID Shr 24) And 255) & Chr((V_ToPlayerID Shr 16) And 255) & Chr((V_ToPlayerID Shr 8) And 255) & Chr(V_ToPlayerID And 255)
T += Space(8): *Cast(Integer Ptr, @T[Len(T) - 8]) = V_NewPositonX
T += Space(8): *Cast(Integer Ptr, @T[Len(T) - 8]) = V_NewPositonY
T += Space(8): *Cast(Integer Ptr, @T[Len(T) - 8]) = V_NewPositonZ
T += Chr((V_SubData Shr 24) And 255) & Chr((V_SubData Shr 16) And 255) & Chr((V_SubData Shr 8) And 255) & Chr(V_SubData And 255)
T = TSNEPlay_INT_CreateStreamCommand(TSNEPlay_INT_MSGT_Move, T)
Dim TLocalSend As Ubyte
Dim RV As TSNEPlay_GURUCode = TSNEPlay_INT_SendData(V_ToPlayerID, T, TLocalSend)
If TLocalSend = 1 Then If TSNEPlay_INT_Event_Move <> 0 Then TSNEPlay_INT_Event_Move(FPID, V_ToPlayerID, V_NewPositonX, V_NewPositonY, V_NewPositonZ, V_SubData)
Return RV
End Function

'--------------------------------------------------------------------------------------------------------------
Function TSNEPlay_SendMoveDbl(V_ToPlayerID As Uinteger, V_NewPositonX As Double = 0, V_NewPositonY As Double = 0, V_NewPositonZ As Double = 0, Byval V_SubData As Uinteger = 0) As TSNEPlay_GURUCode
'<FromPlayerID><ToPlayerID><PosX><PosY><PosZ><SubData>
If TSNEPlay_INT_State <> TSNEPlay_State_Ready Then Return TSNEPlay_NotReadyForNewConnection
Dim T As String
Dim FPID As Uinteger
If TSNEPlay_INT_ClientMode = 1 Then
    FPID = TSNEPlay_INT_Client_PlayerID
Else: FPID = TSNEPlay_INT_Server_PlayerID
End If
T += Chr((FPID Shr 24) And 255) & Chr((FPID Shr 16) And 255) & Chr((FPID Shr 8) And 255) & Chr(FPID And 255)
T += Chr((V_ToPlayerID Shr 24) And 255) & Chr((V_ToPlayerID Shr 16) And 255) & Chr((V_ToPlayerID Shr 8) And 255) & Chr(V_ToPlayerID And 255)
T += Space(8): *Cast(Double Ptr, @T[Len(T) - 8]) = V_NewPositonX
T += Space(8): *Cast(Double Ptr, @T[Len(T) - 8]) = V_NewPositonY
T += Space(8): *Cast(Double Ptr, @T[Len(T) - 8]) = V_NewPositonZ
T += Chr((V_SubData Shr 24) And 255) & Chr((V_SubData Shr 16) And 255) & Chr((V_SubData Shr 8) And 255) & Chr(V_SubData And 255)
T = TSNEPlay_INT_CreateStreamCommand(TSNEPlay_INT_MSGT_MoveDbl, T)
Dim TLocalSend As Ubyte
Dim RV As TSNEPlay_GURUCode = TSNEPlay_INT_SendData(V_ToPlayerID, T, TLocalSend)
If TLocalSend = 1 Then If TSNEPlay_INT_Event_MoveDbl <> 0 Then TSNEPlay_INT_Event_MoveDbl(FPID, V_ToPlayerID, V_NewPositonX, V_NewPositonY, V_NewPositonZ, V_SubData)
Return RV
End Function

'--------------------------------------------------------------------------------------------------------------
Function TSNEPlay_SendData(V_ToPlayerID As Uinteger, Byref V_Data As String) As TSNEPlay_GURUCode
'<FromPlayerID><ToPlayerID><Data>
If Len(V_Data) > (TSNE_INT_BufferSize - 24) Then Return TSNEPlay_MessageToLong
If TSNEPlay_INT_State <> TSNEPlay_State_Ready Then Return TSNEPlay_NotReadyForNewConnection
Dim T As String
Dim FPID As Uinteger
If TSNEPlay_INT_ClientMode = 1 Then
    FPID = TSNEPlay_INT_Client_PlayerID
Else: FPID = TSNEPlay_INT_Server_PlayerID
End If
T += Chr((FPID Shr 24) And 255) & Chr((FPID Shr 16) And 255) & Chr((FPID Shr 8) And 255) & Chr(FPID And 255)
T += Chr((V_ToPlayerID Shr 24) And 255) & Chr((V_ToPlayerID Shr 16) And 255) & Chr((V_ToPlayerID Shr 8) And 255) & Chr(V_ToPlayerID And 255)
Dim MX As Uinteger = Len(V_Data)
T += Chr((MX Shr 24) And 255) & Chr((MX Shr 16) And 255) & Chr((MX Shr 8) And 255) & Chr(MX And 255)
T += V_Data
T = TSNEPlay_INT_CreateStreamCommand(TSNEPlay_INT_MSGT_Dat, T)
Dim TLocalSend As Ubyte
Dim RV As TSNEPlay_GURUCode = TSNEPlay_INT_SendData(V_ToPlayerID, T, TLocalSend)
If TLocalSend = 1 Then If TSNEPlay_INT_Event_Data <> 0 Then TSNEPlay_INT_Event_Data(FPID, V_ToPlayerID, V_Data)
Return RV
End Function



'##############################################################################################################
'...<
#ENDIF