8f3114e377
Signed-off-by: Michael Fabian Dirks <michael.dirks@project-kube.de>
665 lines
22 KiB
BlitzBasic
665 lines
22 KiB
BlitzBasic
;----------------------------------------------------------------
|
|
;-- Packet Descriptors
|
|
;----------------------------------------------------------------
|
|
|
|
;-- Any Packet
|
|
;Off Size Desc
|
|
; 0 1 Packet Id
|
|
|
|
;-- Login
|
|
;Off Size Desc
|
|
; 1 2 Unique Id (Server) / UDP Port (Client)
|
|
; 3 2 Version
|
|
; 5 16 Name (Always 16B, Only allows bytes above 32)
|
|
; 21 4F Initial Position X
|
|
; 25 4F Initial Position Y
|
|
; 29 4F Initial Position Z
|
|
; 33 4F Initial Rotation X
|
|
; 37 4F Initial Rotation Y
|
|
; 41 4F Initial Rotation Z
|
|
|
|
;-- Logout
|
|
;Off Size Desc
|
|
; 1 2 Unique Id
|
|
|
|
;-- Kick
|
|
;Off Size Desc
|
|
; 1 2 Reason Length
|
|
; 3 ^ Reason
|
|
|
|
;-- Data
|
|
; 1 2 Unique Id
|
|
; 3 1 Data Flags (See BNET_DATAFLAG_*)
|
|
;... 4F Position X
|
|
;... 4F Position Y
|
|
;... 4F Position Z
|
|
;... 2 Rotation X
|
|
;... 2 Rotation Y
|
|
;... 2 Rotation Z
|
|
;... 2 Velocity X
|
|
;... 2 Velocity Y
|
|
;... 2 Velocity Z
|
|
;... 2 Aim X
|
|
;... 2 Aim Y
|
|
|
|
;-- Action (Yet Unsupported)
|
|
|
|
;----------------------------------------------------------------
|
|
;-- Constants
|
|
;----------------------------------------------------------------
|
|
; BlitzNet Version
|
|
Const BNET_VERSION_MAJOR% = 0
|
|
Const BNET_VERSION_MINOR% = 1
|
|
; Size of Buffer for Network Packets, 64KB should be enough for now.
|
|
Const BNET_BUFFER_SIZE% = (64 * 1024)
|
|
; Flags for data changes. Only when the bit is set this data is available.
|
|
Const BNET_DATAFLAG_POSX = $00000001
|
|
Const BNET_DATAFLAG_POSY = $00000010
|
|
Const BNET_DATAFLAG_POSZ = $00000100
|
|
Const BNET_DATAFLAG_ROTX = $00001000
|
|
Const BNET_DATAFLAG_ROTY = $00010000
|
|
Const BNET_DATAFLAG_ROTZ = $00100000
|
|
Const BNET_DATAFLAG_VELOCITY = $01000000
|
|
Const BNET_DATAFLAG_AIM = $10000000
|
|
; Packet Ids, for identification of each one.
|
|
Const BNET_PACKET_LOGIN = 0
|
|
Const BNET_PACKET_LOGOUT = 1
|
|
Const BNET_PACKET_KICK = 2
|
|
Const BNET_PACKET_DATA = 3
|
|
Const BNET_PACKET_ACTION = 4
|
|
; How many updates should we send out each minute?
|
|
Const BNET_DATA_COUNT = 150
|
|
; How many keyframes should we send out each minute?
|
|
Const BNET_DATA_COUNT_KEYFRAME = 3
|
|
; How much has the value to change to be considered different?
|
|
Const BNET_DATA_THRESHOLD_POS# = 1.0
|
|
Const BNET_DATA_THRESHOLD_ROT# = 1.0
|
|
Const BNET_DATA_THRESHOLD_VEL# = 1.0
|
|
Const BNET_DATA_THRESHOLD_AIM# = 1.0
|
|
|
|
;----------------------------------------------------------------
|
|
;-- Globals
|
|
;----------------------------------------------------------------
|
|
; Connections to Sector Servers.
|
|
Global BNet_Sector_TCP% = 0
|
|
Global BNet_Sector_UDP% = 0
|
|
; Our UniqueId and Player instance so we know which Player is us.
|
|
Global BNet_UniqueId% = -1
|
|
Global BNet_Player.BNetPlayer = Null
|
|
; Buffer for Network Packets.
|
|
Global BNet_Buffer% = CreateBank(BNET_BUFFER_SIZE)
|
|
; Set to true when Kicked from the server, or similar.
|
|
Global BNet_Kick% = False
|
|
Global BNet_Kick_Reason$ = "Not Kicked"
|
|
; Update Times
|
|
Global BNet_Data_Time = 60000 / BNET_DATA_COUNT
|
|
Global BNet_Data_Time_KeyFrame = 60000 / BNET_DATA_COUNT_KEYFRAME
|
|
Global BNet_Data_LastUpdate = 0
|
|
Global BNet_Data_LastKeyFrame = 0
|
|
; Array for all known players. Makes access a bit faster.
|
|
Dim BNet_Players.BNetPlayer(65535)
|
|
|
|
;----------------------------------------------------------------
|
|
;-- Types
|
|
;----------------------------------------------------------------
|
|
Type BNetPlayer
|
|
Field Name$ = "Invalid Player"
|
|
|
|
; Position, Rotation, Velocity and Aim
|
|
Field PositionX#, PositionY#, PositionZ#
|
|
Field RotationX#, RotationY#, RotationZ#
|
|
Field VelocityX#, VelocityY#, VelocityZ#
|
|
Field AimX#, AimY#
|
|
|
|
; Internal Data
|
|
Field m_UniqueId%
|
|
End Type
|
|
|
|
;----------------------------------------------------------------
|
|
;-- Functions
|
|
;----------------------------------------------------------------
|
|
Function BNet_Initialize()
|
|
TCPTimeouts 100, 100
|
|
End Function
|
|
|
|
Function BNet_Connect(Ip$ = "127.0.0.1", IPort% = 27000, DPort = 27001)
|
|
BNet_Kick% = False
|
|
BNet_Kick_Reason$ = "Not Kicked"
|
|
|
|
BNet_Sector_TCP = OpenTCPStream(Ip, IPort)
|
|
If BNet_Sector_TCP Then
|
|
BNet_Sector_UDP = CreateUDPStream()
|
|
If BNet_Sector_UDP Then
|
|
Return True
|
|
Else
|
|
CloseTCPStream BNet_Sector_TCP
|
|
BNet_Sector_UDP = 0
|
|
BNet_Sector_TCP = 0
|
|
EndIf
|
|
Else
|
|
BNet_Sector_UDP = 0
|
|
BNet_Sector_TCP = 0
|
|
EndIf
|
|
Return False
|
|
End Function
|
|
|
|
Function BNet_Disconnect()
|
|
If BNet_UniqueId > -1 Then
|
|
; Remove all existing players
|
|
For Player.BNetPlayer = Each BNetPlayer
|
|
Local UniqueId = Player\m_UniqueId
|
|
|
|
CB_BNet_DeletePlayer(UniqueId, Player)
|
|
|
|
Delete BNet_Players(UniqueId):BNet_Players(UniqueId) = Null
|
|
Next
|
|
|
|
; Logout
|
|
BNet_Logout()
|
|
BNet_UniqueId = -1
|
|
EndIf
|
|
If BNet_Sector_UDP Then CloseUDPStream(BNet_Sector_UDP):BNet_Sector_UDP = 0
|
|
If BNet_Sector_TCP Then CloseTCPStream(BNet_Sector_TCP):BNet_Sector_TCP = 0
|
|
End Function
|
|
|
|
Function BNet_Connected()
|
|
If BNet_Sector_TCP = 0 Then Return False
|
|
If BNet_Sector_UDP = 0 Then Return False
|
|
If Eof(BNet_Sector_TCP) <> 0 Then Return False
|
|
|
|
Return True
|
|
End Function
|
|
|
|
Function BNet_Login(Name$, PosX# = 0, PosY# = 0, PosZ# = 0, RotX# = 0, RotY# = 0, RotZ# = 0)
|
|
If BNet_Connected() And BNet_UniqueId = -1 Then
|
|
; Packet Id: Login
|
|
PokeByte BNet_Buffer, 0, BNET_PACKET_LOGIN
|
|
; Write UDP Port
|
|
PokeShort BNet_Buffer, 1, UDPStreamPort(BNet_Sector_UDP)
|
|
; Write Client Version
|
|
PokeShort BNet_Buffer, 3, BNET_VERSION_MAJOR Shl 8 + BNET_VERSION_MINOR
|
|
; Write Name
|
|
Local NameLength% = Len(Name)
|
|
For NamePos = 1 To NameLength:PokeByte BNet_Buffer, (5 + NamePos - 1), Asc(Mid(Name, NamePos, 1)):Next
|
|
For NamePos = NameLength To 16:PokeByte BNet_Buffer, (5 + NamePos - 1), 0:Next
|
|
; Write Initial Position
|
|
PokeFloat BNet_Buffer, 21, PosX
|
|
PokeFloat BNet_Buffer, 25, PosY
|
|
PokeFloat BNet_Buffer, 29, PosZ
|
|
; Write Initial Rotation
|
|
PokeFloat BNet_Buffer, 33, RotX
|
|
PokeFloat BNet_Buffer, 37, RotX
|
|
PokeFloat BNet_Buffer, 41, RotX
|
|
|
|
; Write to Stream
|
|
WriteBytes BNet_Buffer, BNet_Sector_TCP, 0, 47
|
|
|
|
Return True
|
|
Else
|
|
Return False
|
|
EndIf
|
|
End Function
|
|
|
|
Function BNet_Logout()
|
|
If BNet_Connected() And BNet_UniqueId > -1 Then
|
|
; Packet Id: Logout
|
|
PokeByte BNet_Buffer, 0, BNET_PACKET_LOGOUT
|
|
; Write our own UniqueId
|
|
PokeShort BNet_Buffer, 1, BNet_UniqueId
|
|
|
|
; Write to Stream
|
|
WriteBytes BNet_Buffer, BNet_Sector_TCP, 0, 3
|
|
|
|
Return True
|
|
Else
|
|
Return False
|
|
EndIf
|
|
End Function
|
|
|
|
Function BNet_Update()
|
|
Local UniqueId, PacketSize, PacketId, DataFlags, Offset, TempPlayer.BNetPlayer
|
|
If BNet_Connected() Then
|
|
; TCP
|
|
While Not Eof(BNet_Sector_TCP) And ReadAvail(BNet_Sector_TCP) > 0
|
|
PacketSize = ReadAvail(BNet_Sector_TCP)
|
|
If PacketSize > BNET_BUFFER_SIZE Then PacketSize = BNET_BUFFER_SIZE
|
|
ReadBytes(BNet_Buffer, BNet_Sector_TCP, 0, PacketSize)
|
|
|
|
PacketId = PeekByte(BNet_Buffer, 0)
|
|
Select PacketId
|
|
Case BNET_PACKET_LOGIN
|
|
UniqueId = PeekShort(BNet_Buffer, 1)
|
|
|
|
BNet_Players(UniqueId) = New BNetPlayer
|
|
; Read Name
|
|
For NamePos = 1 To 16
|
|
Local NameChar = PeekByte(BNet_Buffer, (5 + NamePos - 1))
|
|
If NameChar < 32 Then Exit
|
|
BNet_Players(UniqueId)\Name$ = BNet_Players(UniqueId)\Name$ + Chr(NameChar)
|
|
Next
|
|
; Read initital Position
|
|
BNet_Players(UniqueId)\PositionX = PeekFloat(BNet_Buffer, 21)
|
|
BNet_Players(UniqueId)\PositionY = PeekFloat(BNet_Buffer, 25)
|
|
BNet_Players(UniqueId)\PositionZ = PeekFloat(BNet_Buffer, 29)
|
|
; Read initial Rotation
|
|
BNet_Players(UniqueId)\RotationX = PeekFloat(BNet_Buffer, 33)
|
|
BNet_Players(UniqueId)\RotationY = PeekFloat(BNet_Buffer, 37)
|
|
BNet_Players(UniqueId)\RotationZ = PeekFloat(BNet_Buffer, 41)
|
|
; Assign Unique Id
|
|
BNet_Players(UniqueId)\m_UniqueId = UniqueId
|
|
|
|
; Assign local UniqueId if we don't have one.
|
|
If BNet_UniqueId > -1 Then
|
|
BNet_UniqueId = UniqueId
|
|
Else
|
|
CB_BNet_CreatePlayer(UniqueId, BNet_Players(BNet_UniqueId))
|
|
EndIf
|
|
Case BNET_PACKET_LOGOUT
|
|
UniqueId = PeekShort(BNet_Buffer, 1)
|
|
|
|
; A logout packet for ourselves will make us logout.
|
|
If BNet_UniqueId = UniqueId Then
|
|
BNet_Disconnect():Return True
|
|
ElseIf BNet_Players(UniqueId) <> Null Then
|
|
; Otherwise, it is another player removed from visible space.
|
|
CB_BNet_DeletePlayer(Unique, BNet_Players(UniqueId))
|
|
|
|
Delete BNet_Players(UniqueId):BNet_Players(UniqueId) = Null
|
|
Else
|
|
DebugLog "BNet: Logout for non-existing player."
|
|
EndIf
|
|
Case BNET_PACKET_KICK
|
|
BNet_Kick = True
|
|
|
|
; Read reason for Kick
|
|
Local ReasonLength% = PeekShort(BNet_Buffer, 1)
|
|
For ReasonPos = 1 To ReasonLength
|
|
Local ReasonChar = PeekByte(BNet_Buffer, (3 + ReasonPos - 1))
|
|
If ReasonChar < 32 Then Exit
|
|
BNet_Kick_Reason = BNet_Kick_Reason + Chr(NameChar)
|
|
Next
|
|
|
|
BNet_Disconnect():Return True
|
|
End Select
|
|
Wend
|
|
|
|
; UDP
|
|
While Not Eof(BNet_Sector_UDP) And ReadAvail(BNet_Sector_UDP) > 0
|
|
PacketSize = ReadAvail(BNet_Sector_UDP)
|
|
If PacketSize > BNET_BUFFER_SIZE Then PacketSize = BNET_BUFFER_SIZE
|
|
ReadBytes(BNet_Buffer, BNet_Sector_UDP, 0, PacketSize)
|
|
|
|
PacketId = PeekByte(BNet_Buffer, 0)
|
|
Select PacketId
|
|
Case BNET_PACKET_DATA
|
|
If BNet_UniqueId > -1 Then
|
|
UniqueId = PeekShort(BNet_Buffer, 1)
|
|
If BNet_Players(UniqueId) <> Null Then
|
|
DataFlags = PeekShort(BNet_Buffer, 3)
|
|
Offset% = 5
|
|
|
|
If DataFlags And BNET_DATAFLAGS_POSX Then BNet_Players(UniqueId)\PositionX = PeekInt(BNet_Buffer, Offset):Offset = Offset + 4
|
|
If DataFlags And BNET_DATAFLAGS_POSY Then BNet_Players(UniqueId)\PositionY = PeekInt(BNet_Buffer, Offset):Offset = Offset + 4
|
|
If DataFlags And BNET_DATAFLAGS_POSZ Then BNet_Players(UniqueId)\PositionZ = PeekInt(BNet_Buffer, Offset):Offset = Offset + 4
|
|
If DataFlags And BNET_DATAFLAGS_ROTX Then BNet_Players(UniqueId)\RotationX = BNet_FloatFromShort(PeekShort(BNet_Buffer, Offset)) * 360.0:Offset = Offset + 2
|
|
If DataFlags And BNET_DATAFLAGS_ROTY Then BNet_Players(UniqueId)\RotationY = BNet_FloatFromShort(PeekShort(BNet_Buffer, Offset)) * 360.0:Offset = Offset + 2
|
|
If DataFlags And BNET_DATAFLAGS_ROTZ Then BNet_Players(UniqueId)\RotationZ = BNet_FloatFromShort(PeekShort(BNet_Buffer, Offset)) * 360.0:Offset = Offset + 2
|
|
If DataFlags And BNET_DATAFLAGS_VELOCITY Then
|
|
BNet_Players(UniqueId)\VelocityX = BNet_FloatFromShort(PeekShort(BNet_Buffer, Offset)) * 255.0
|
|
BNet_Players(UniqueId)\VelocityY = BNet_FloatFromShort(PeekShort(BNet_Buffer, Offset)) * 255.0
|
|
BNet_Players(UniqueId)\VelocityZ = BNet_FloatFromShort(PeekShort(BNet_Buffer, Offset)) * 255.0
|
|
|
|
Offset = Offset + 6
|
|
EndIf
|
|
If DataFlags And BNET_DATAFLAGS_AIM Then
|
|
BNet_Players(UniqueId)\AimX = BNet_FloatFromShort(PeekShort(BNet_Buffer, Offset)) * 360.0
|
|
BNet_Players(UniqueId)\AimY = BNet_FloatFromShort(PeekShort(BNet_Buffer, Offset)) * 360.0
|
|
|
|
Offset = Offset + 4
|
|
EndIf
|
|
|
|
; Tell Client to update visual stuff
|
|
CB_BNet_UpdatePlayer(UniqueId, BNet_Players(UniqueId))
|
|
EndIf
|
|
EndIf
|
|
; Case BNET_PACKET_ACTION
|
|
; If BNet_UniqueId > -1 Then
|
|
;
|
|
; EndIf
|
|
End Select
|
|
Wend
|
|
|
|
; If we are logged in, tell the server our current data.
|
|
If BNet_UniqueId > -1 Then
|
|
Local Time = MilliSecs()
|
|
|
|
; Send out whatever is needed.
|
|
If Time - BNet_Data_LastKeyFrame > BNet_Data_Time_KeyFrame Then
|
|
; Force Client to update Player object
|
|
CB_BNet_SendUpdate(BNet_UniqueId, BNet_Player)
|
|
|
|
; Packet Id
|
|
PokeByte BNet_Buffer, 0, BNET_PACKET_DATA
|
|
; Unique Id
|
|
PokeShort BNet_Buffer, 1, BNet_UniqueId
|
|
; Data Flags (KeyFrame always has this at 255, since it contains all data)
|
|
PokeByte BNet_Buffer, 3, $11111111
|
|
; Position
|
|
PokeFloat BNet_Buffer, 4, BNet_Player\PositionX
|
|
PokeFloat BNet_Buffer, 8, BNet_Player\PositionY
|
|
PokeFloat BNet_Buffer,12, BNet_Player\PositionZ
|
|
; Rotation
|
|
PokeShort BNet_Buffer,16, BNet_ShortFromFloat(BNet_Player\RotationX / 360.0)
|
|
PokeShort BNet_Buffer,18, BNet_ShortFromFloat(BNet_Player\RotationY / 360.0)
|
|
PokeShort BNet_Buffer,20, BNet_ShortFromFloat(BNet_Player\RotationZ / 360.0)
|
|
; Velocity
|
|
PokeShort BNet_Buffer,22, BNet_ShortFromFloat(BNet_Player\VelocityX / 256.0)
|
|
PokeShort BNet_Buffer,24, BNet_ShortFromFloat(BNet_Player\VelocityY / 256.0)
|
|
PokeShort BNet_Buffer,26, BNet_ShortFromFloat(BNet_Player\VelocityZ / 256.0)
|
|
; Aim
|
|
PokeShort BNet_Buffer,28, BNet_ShortFromFloat(BNet_Player\AimX / 360.0)
|
|
PokeShort BNet_Buffer,30, BNet_ShortFromFloat(BNet_Player\AimY / 360.0)
|
|
|
|
; Send Packet
|
|
WriteBytes BNet_Buffer, BNet_Sector_UDP, 0, 32
|
|
|
|
; Swap Player objects.
|
|
TempPlayer = BNet_Player
|
|
BNet_Player = BNet_Players(BNet_UniqueId)
|
|
BNet_Players(BNet_UnqiueId) = TempPlayer
|
|
|
|
; Set last keyframe and update time to now.
|
|
BNet_Data_LastKeyFrame = Time
|
|
BNet_Data_LastUpdate = Time
|
|
ElseIf Time - BNet_Data_LastUpdate > BNet_Data_Time Then
|
|
DataFlags = 0
|
|
Offset = 4
|
|
|
|
; Force Client to update Player object
|
|
CB_BNet_SendUpdate(BNet_UniqueId, BNet_Player)
|
|
|
|
; Packet Id
|
|
PokeByte BNet_Buffer, 0, BNET_PACKET_DATA
|
|
; Unique Id
|
|
PokeShort BNet_Buffer, 1, BNet_UniqueId
|
|
|
|
; Position
|
|
If Abs(BNet_Player\PositionX - BNet_Players(BNet_UniqueId)\PositionX) > BNET_DATA_THRESHOLD_POS Then
|
|
DataFlags = DataFlags Or BNET_DATAFLAG_POSX
|
|
PokeFloat BNet_Buffer, Offset, BNet_Player\PositionX:Offset = Offset + 4
|
|
EndIf
|
|
If Abs(BNet_Player\PositionY - BNet_Players(BNet_UniqueId)\PositionY) > BNET_DATA_THRESHOLD_POS Then
|
|
DataFlags = DataFlags Or BNET_DATAFLAG_POSY
|
|
PokeFloat BNet_Buffer, Offset, BNet_Player\PositionY:Offset = Offset + 4
|
|
EndIf
|
|
If Abs(BNet_Player\PositionZ - BNet_Players(BNet_UniqueId)\PositionZ) > BNET_DATA_THRESHOLD_POS Then
|
|
DataFlags = DataFlags Or BNET_DATAFLAG_POSZ
|
|
PokeFloat BNet_Buffer, Offset, BNet_Player\PositionZ:Offset = Offset + 4
|
|
EndIf
|
|
; Rotation
|
|
If Abs(BNet_Player\RotationX - BNet_Players(BNet_UniqueId)\RotationX) > BNET_DATA_THRESHOLD_POS Then
|
|
DataFlags = DataFlags Or BNET_DATAFLAG_ROTX
|
|
PokeFloat BNet_Buffer, Offset, BNet_ShortFromFloat(BNet_Player\RotationX / 360.0):Offset = Offset + 2
|
|
EndIf
|
|
If Abs(BNet_Player\RotationY - BNet_Players(BNet_UniqueId)\RotationY) > BNET_DATA_THRESHOLD_POS Then
|
|
DataFlags = DataFlags Or BNET_DATAFLAG_ROTY
|
|
PokeFloat BNet_Buffer, Offset, BNet_ShortFromFloat(BNet_Player\RotationY / 360.0):Offset = Offset + 2
|
|
EndIf
|
|
If Abs(BNet_Player\RotationZ - BNet_Players(BNet_UniqueId)\RotationZ) > BNET_DATA_THRESHOLD_POS Then
|
|
DataFlags = DataFlags Or BNET_DATAFLAG_ROTZ
|
|
PokeFloat BNet_Buffer, Offset, BNet_ShortFromFloat(BNet_Player\RotationZ / 360.0):Offset = Offset + 2
|
|
EndIf
|
|
; Velocity
|
|
If Abs(BNet_Player\VelocityX - BNet_Players(BNet_UniqueId)\VelocityX) + Abs(BNet_Player\VelocityY - BNet_Players(BNet_UniqueId)\VelocityY) + Abs(BNet_Player\VelocityZ - BNet_Players(BNet_UniqueId)\VelocityZ) > BNET_DATA_THRESHOLD_VEL Then
|
|
DataFlags = DataFlags Or BNET_DATAFLAG_VELOCITY
|
|
PokeFloat BNet_Buffer, Offset, BNet_ShortFromFloat(BNet_Player\VelocityX / 256.0):Offset = Offset + 2
|
|
PokeFloat BNet_Buffer, Offset, BNet_ShortFromFloat(BNet_Player\VelocityY / 256.0):Offset = Offset + 2
|
|
PokeFloat BNet_Buffer, Offset, BNet_ShortFromFloat(BNet_Player\VelocityZ / 256.0):Offset = Offset + 2
|
|
EndIf
|
|
; Aim
|
|
If Abs(BNet_Player\AimX - BNet_Players(BNet_UniqueId)\AimX) + Abs(BNet_Player\AimY - BNet_Players(BNet_UniqueId)\AimY) > BNET_DATA_THRESHOLD_AIM Then
|
|
DataFlags = DataFlags Or BNET_DATAFLAG_AIM
|
|
PokeFloat BNet_Buffer, Offset, BNet_ShortFromFloat(BNet_Player\AimX / 360.0):Offset = Offset + 2
|
|
PokeFloat BNet_Buffer, Offset, BNet_ShortFromFloat(BNet_Player\AimY / 360.0):Offset = Offset + 2
|
|
EndIf
|
|
|
|
; Data Flags
|
|
PokeByte BNet_Buffer, 3, DataFlags
|
|
|
|
; Send Packet
|
|
WriteBytes BNet_Buffer, BNet_Sector_UDP, 0, Offset
|
|
|
|
; Swap Player objects.
|
|
TempPlayer = BNet_Player
|
|
BNet_Player = BNet_Players(BNet_UniqueId)
|
|
BNet_Players(BNet_UnqiueId) = TempPlayer
|
|
|
|
; Set last update time to now.
|
|
BNet_Data_LastUpdate = Time
|
|
EndIf
|
|
EndIf
|
|
Else
|
|
Return False
|
|
EndIf
|
|
End Function
|
|
|
|
Function BNet_FloatFromShort#(Value%)
|
|
Return BNet_Math_ClipF((Value / 65536.0), 0.0, 1.0)
|
|
End Function
|
|
|
|
Function BNet_ShortFromFloat%(Value#)
|
|
Return BNet_Math_ClipF((Value * 65536.0), 0.0, 1.0)
|
|
End Function
|
|
|
|
Function BNet_Math_MinimumF#(Value#, Min#)
|
|
If Value < Min Then Return Min
|
|
Return Value
|
|
End Function
|
|
|
|
Function BNet_Math_MaximumF#(Value#, Max#)
|
|
If Value > Max Then Return Max
|
|
Return Value
|
|
End Function
|
|
|
|
Function BNet_Math_ClampF#(Value#, Min#, Max#)
|
|
If Value < Min Then Return Min
|
|
If Value > Max Then Return Max
|
|
Return Value
|
|
End Function
|
|
|
|
Function BNet_Math_ClipF#(Value#, Min#, Max#)
|
|
Local Out#, Diff#
|
|
Diff = Max - Min:Out = Value - Min
|
|
If (Out >= Diff) Or (Out < 0) Then Out = Out - (Floor(Out/Diff) * Diff)
|
|
Return Min + Out
|
|
End Function
|
|
|
|
;----------------------------------------------------------------
|
|
;-- Callbacks
|
|
;----------------------------------------------------------------
|
|
;Function CB_BNet_CreatePlayer(UniqueId, Player.BNetPlayer)
|
|
;End Function
|
|
|
|
;Function CB_BNet_UpdatePlayer(UniqueId, Player.BNetPlayer)
|
|
;End Function
|
|
|
|
;Function CB_BNet_DeletePlayer(UniqueId, Player.BNetPlayer)
|
|
;End Function
|
|
|
|
;Function CB_BNet_SendUpdate(UniqueId, Player.BNetPlayer)
|
|
;End Function
|
|
|
|
;----------------------------------------------------------------
|
|
;-- Example
|
|
;----------------------------------------------------------------
|
|
Graphics3D 800, 600, 32, 2
|
|
SetBuffer BackBuffer()
|
|
SeedRnd MilliSecs()
|
|
|
|
Local FrameTimer = CreateTimer(60)
|
|
Local TimeToLogin = MilliSecs()
|
|
|
|
Dim Players.TPlayer(65535)
|
|
Local Player.TPlayer = Null
|
|
|
|
Global TestX#, TestY#, TestZ#
|
|
Global TestRX#, TestRY#, TestRZ#
|
|
Global TestVX#, TestVY#, TestVZ#
|
|
Global TestAX#, TestAY#
|
|
Local ShipVeloLR#, ShipVeloUD#, ShipVeloFB#
|
|
Const ShipMaxVeloLR# = 5.0, ShipMaxVeloUD# = 5.0, ShipMaxVeloFB = 30.0
|
|
|
|
; Init
|
|
TestX = Rnd(-2048, 2048)
|
|
TestY = Rnd(-2048, 2048)
|
|
TestZ = Rnd(-2048, 2048)
|
|
TestRX = Rnd(0, 360)
|
|
TestRY = Rnd(0, 360)
|
|
TestRZ = Rnd(0, 360)
|
|
TestVX = 0
|
|
TestVY = 0
|
|
TestVZ = 0
|
|
TestAX = 0
|
|
TestAY = 0
|
|
|
|
|
|
Local Cam = CreateCamera()
|
|
Local Conv = CreatePivot()
|
|
|
|
Print "[INF] Connecting..."
|
|
BNet_Initialize()
|
|
BNet_Connect()
|
|
If BNet_Connected() Then
|
|
Print "[INF] Logging in..."
|
|
BNet_Login("Test " + Rand(0, 65535), TestX, TestY, TestZ, TestRX, TestRY, TestRZ)
|
|
|
|
Local LoopExit = False
|
|
Local Load = False
|
|
Repeat
|
|
If Load = False And BNet_UniqueId = -1 And (MilliSecs() - TimeToLogin > 30000) Then
|
|
Print "[ERR] Failed to login."
|
|
LoopExit = True
|
|
ElseIf Load = False And BNet_UniqueId > -1 Then
|
|
Print "[INF] Logged in."
|
|
|
|
Player = New TPlayer
|
|
Player\Mesh = CreateCone()
|
|
Player\Player = BNet_Player
|
|
Players(BNet_UniqueId) = Player
|
|
EntityParent Cam, Player\Mesh
|
|
|
|
Load = True
|
|
ElseIf Load = True And BNet_UniqueId > -1
|
|
; Player Input
|
|
; Velocity
|
|
ShipVeloFB = BNet_Math_ClampF(ShipVeloFB + (KeyDown(17) - KeyDown(31)) * 2.5, -ShipMaxVeloFB, ShipMaxVeloFB)
|
|
ShipVeloLR = BNet_Math_ClampF(ShipVeloLR + (KeyDown(32) - KeyDown(30)) * 1.5, -ShipMaxVeloLR, ShipMaxVeloLR)
|
|
ShipVeloUD = BNet_Math_ClampF(ShipVeloUD + (KeyDown(19) - KeyDown(33)) * 1.5, -ShipMaxVeloUD, ShipMaxVeloUD)
|
|
; Rotation
|
|
If KeyDown(57) Then
|
|
If KeyHit(57) Then MoveMouse 512, 384
|
|
TestRX = TestRX + ((MouseX() / 512) - 1.0)
|
|
TestRY = TestRY + ((MouseY() / 384) - 1.0)
|
|
EndIf
|
|
TestRZ = TestRZ + (KeyDown(18) - KeyDown(16)) * 1.0
|
|
|
|
; Update Game
|
|
; Slowly scale down Velocity.
|
|
ShipVeloFB = ShipVeloFB * 0.9
|
|
ShipVeloLR = ShipVeloLR * 0.8
|
|
ShipVeloUD = ShipVeloUD * 0.8
|
|
; Convert Local Velocity to Global Velocity
|
|
TFormPoint ShipVeloLR, ShipVeloUD, ShipVeloFB, Player\Mesh, Conv
|
|
TestVX = TFormedX()
|
|
TestVY = TFormedY()
|
|
TestVZ = TFormedZ()
|
|
; Move player by Velocity.
|
|
TestX = TestX + TestVX
|
|
TestY = TestY + TestVY
|
|
TestZ = TestZ + TestVZ
|
|
|
|
; Draw Game
|
|
; Update Local Mesh
|
|
PositionEntity Player\Mesh, TestX, TestY, TestZ
|
|
RotateEntity Player\Mesh, TestRX, TestRY, TestRZ
|
|
; Update conversion point
|
|
PositionEntity Conv, TestX, TestY, TestZ
|
|
|
|
RenderWorld
|
|
Flip 0
|
|
EndIf
|
|
|
|
If BNet_Update() Then
|
|
LoopExit = True
|
|
EndIf
|
|
WaitTimer FrameTimer
|
|
Until (LoopExit = True)
|
|
If BNet_Kick = True Then Print "[INF] Kicked: " + BNet_Kick_Reason Else Print "Logging out."
|
|
|
|
BNet_Disconnect()
|
|
Else
|
|
Print "[ERR] Failed to connect."
|
|
EndIf
|
|
End
|
|
|
|
Function CB_BNet_CreatePlayer(UniqueId, Player.BNetPlayer)
|
|
DebugLog "[INF] New Player: " + Player\Name + "[" + UniqueId + "]"
|
|
DebugLog " Pos: " + Player\PositionX + ", " + Player\PositionY + ", " + Player\PositionZ
|
|
DebugLog " Rot: " + Player\RotationX + ", " + Player\RotationY + ", " + Player\RotationZ
|
|
|
|
If Players(UniqueId) = Null Then Players(UniqueId) = New TPlayer
|
|
If Players(UniqueId)\Mesh <> 0 Then Players(UniqueId)\Mesh = CreateCone()
|
|
Players(UniqueId)\Player = Player
|
|
|
|
PositionEntity Players(UniqueId)\Mesh, Player\PositionX, Player\PositionY, Player\PositionZ
|
|
RotateEntity Players(UniqueId)\Mesh, Player\RotationX, Player\RotationY, Player\RotationZ
|
|
End Function
|
|
|
|
Function CB_BNet_UpdatePlayer(UniqueId, Player.BNetPlayer)
|
|
If Players(UniqueId) <> Null Then
|
|
DebugLog "[INF] Update Player: " + Player\Name + "[" + UniqueId + "]"
|
|
DebugLog " Pos: " + Player\PositionX + ", " + Player\PositionY + ", " + Player\PositionZ
|
|
DebugLog " Rot: " + Player\RotationX + ", " + Player\RotationY + ", " + Player\RotationZ
|
|
|
|
PositionEntity Players(UniqueId)\Mesh, Player\PositionX, Player\PositionY, Player\PositionZ
|
|
RotateEntity Players(UniqueId)\Mesh, Player\RotationX, Player\RotationY, Player\RotationZ
|
|
Else
|
|
DebugLog "[ERR] Player does not exist: " + Player\Name + "[" + UniqueId + "]"
|
|
EndIf
|
|
End Function
|
|
|
|
Function CB_BNet_DeletePlayer(UniqueId, Player.BNetPlayer)
|
|
If Players(UniqueId) <> Null Then
|
|
DebugLog "[INF] Delete Player: " + UniqueId + "," + Player\Name
|
|
|
|
FreeEntity Players(UniqueId)\Mesh
|
|
Delete Players(UniqueId)
|
|
Else
|
|
DebugLog "[ERR] Player does not exist: " + Player\Name + "[" + UniqueId + "]"
|
|
EndIf
|
|
End Function
|
|
|
|
Function CB_BNet_SendUpdate(UniqueId, Player.BNetPlayer)
|
|
DebugLog "[INF] Update Self"
|
|
|
|
Player\PositionX = TestX
|
|
Player\PositionY = TestY
|
|
Player\PositionZ = TestZ
|
|
|
|
Player\VelocityX = TestVX
|
|
Player\VelocityY = TestVY
|
|
Player\VelocityZ = TestVZ
|
|
|
|
Player\RotationX = TestRX
|
|
Player\RotationY = TestRY
|
|
Player\RotationZ = TestRZ
|
|
|
|
Player\AimX = TestAX
|
|
Player\AimY = TestAY
|
|
End Function
|
|
|
|
Type TPlayer
|
|
Field Mesh
|
|
|
|
Field Player.BNetPlayer
|
|
End Type |