Jump to content

Josh

Staff
  • Posts

    23,313
  • Joined

  • Last visited

Posts posted by Josh

  1. One of the examples actually has a switch the player can switch on and off to enable or disable a large fan.

     

    You can use the calc velocity and omega functions to calculate forces to make a body stay at a precise orientation. Another way to do this would be to create a body that represents the player's hands, and create a fixed joint between it and the object you want the player to

    pick up.

  2. Here's a more advanced version. This is actually pretty fun once you get into it, because you can design your own protocols as you see fit. This handles chat, whisper, kicking, banning, recurring names, and name changes:

    SuperStrict
    
    Private
    
    Const ENET_PACKET_FLAG_UNSEQUENCED:Int=2
    
    Function enet_host_port:Int( peer:Byte Ptr )
    Local ip:Int=(Int Ptr peer)[1]
    Local port:Int=(Short Ptr peer)[4]
    ?LittleEndian
    ip=(ip Shr 24) | (ip Shr 8 & $ff00) | (ip Shl 8 & $ff0000) | (ip Shl 24)
    ?
    Return port
    EndFunction
    
    Function enet_host_ip:Int( peer:Byte Ptr )
    Local ip:Int=(Int Ptr peer)[1]
    Local port:Int=(Short Ptr peer)[4]
    ?LittleEndian
    ip=(ip Shr 24) | (ip Shr 8 & $ff00) | (ip Shl 8 & $ff0000) | (ip Shl 24)
    ?
    Return ip
    EndFunction
    
    Function enet_peer_port:Int( peer:Byte Ptr )
    Local ip:Int=(Int Ptr peer)[3]
    Local port:Int=(Short Ptr peer)[8]
    ?LittleEndian
    ip=(ip Shr 24) | (ip Shr 8 & $ff00) | (ip Shl 8 & $ff0000) | (ip Shl 24)
    ?
    Return port
    EndFunction
    
    Function enet_peer_ip:Int( peer:Byte Ptr )
    Local ip:Int=(Int Ptr peer)[3]
    Local port:Int=(Short Ptr peer)[8]
    ?LittleEndian
    ip=(ip Shr 24) | (ip Shr 8 & $ff00) | (ip Shl 8 & $ff0000) | (ip Shl 24)
    ?
    Return ip
    EndFunction
    
    Type TNetworkNode
    
    Field port:Int
    Field ip:Int
    Field enethost:Byte Ptr
    Field enetpeer:Byte Ptr
    
    Method Delete()
    	If enethost
    		enet_host_destroy(enethost)
    		enethost=Null
    	EndIf	
    EndMethod
    
    Method Update(callback(client:TClient,id:Int,packet:TPacket)=Null)
    	Local ip:Int,port:Int,client:TClient,ev:ENetEvent=New ENetEvent,id:Byte,packet:TPacket
    
    	If Not Self.enethost RuntimeError "Can't update a remote server."
    	Repeat
    		If enet_host_service(Self.enethost,ev,0)
    
    			Select ev.event
    
    			Case ENET_EVENT_TYPE_CONNECT
    				id=NETWORK_CONNECT
    
    			Case ENET_EVENT_TYPE_DISCONNECT
    				id=NETWORK_DISCONNECT
    
    			Case ENET_EVENT_TYPE_RECEIVE
    				Local size:Int=enet_packet_size(ev.packet)
    				Local data:Byte[size]
    				MemCopy(Varptr id,enet_packet_data(ev.packet),1)
    				If size>1
    					packet=New TPacket
    					packet._bank.resize(size-1)
    					MemCopy(packet._bank.buf(),enet_packet_data(ev.packet)+1,size-1)
    				EndIf
    
    			Default
    				Continue
    
    			EndSelect
    
    			EvaluateEvent(id,packet,ev.peer)
    
    		Else
    			Exit
    		EndIf
    	Forever
    EndMethod
    
    Method EvaluateEvent(id:Int,packet:TPacket,enetpeer:Byte Ptr) Abstract
    
    EndType
    
    Public
    
    
    Const NETWORK_CONNECT:Int=1
    Const NETWORK_DISCONNECT:Int=2
    Const NETWORK_PINGREQUEST:Int=3
    Const NETWORK_PINGRESPONSE:Int=4
    Const NETWORK_JOINREQUEST:Int=5
    Const NETWORK_JOINRESPONSE:Int=6
    Const NETWORK_CHAT:Int=7
    Const NETWORK_LEAVEGAME:Int=8
    Const NETWORK_CHANGENAMEREQUEST:Int=9
    Const NETWORK_CHANGENAMERESPONSE:Int=10
    Const NETWORK_PLAYERJOINED:Int=11
    
    Const SEND_RELIABLE:Int=ENET_PACKET_FLAG_RELIABLE
    Const SEND_UNSEQUENCED:Int=ENET_PACKET_FLAG_UNSEQUENCED
    
    Type TServer Extends TNetworkNode
    
    Const maxplayers:Int=64
    
    Field clients:TList=New TList
    Field callback(server:TServer,client:TClient,id:Int,packet:TPacket)
    Field bannedips:Int[]
    Field clientmap:TMap=New TMap
    
    Method Delete()
    	If enethost
    		enet_host_destroy(enethost)
    		enethost=Null
    	EndIf
    EndMethod
    
    Function Create:TServer(ip:Int=0,port:Int=7777)
    	Local server:TServer=New TServer,addr:Byte Ptr
    
    	If ip
    		server.ip=ip
    	Else
    		server.ip=ENET_HOST_ANY
    	EndIf
    	server.port=port
    	If server.port<>0 Or server.ip<>ENET_HOST_ANY
    		addr=enet_address_create(server.ip,server.port)
    	EndIf
    	server.enethost=enet_host_create(addr,maxplayers,0,0)
    	If addr
    		enet_address_destroy(addr)
    	EndIf
    	If Not server.enethost
    		Return Null		
    	EndIf
    	Return server
    EndFunction
    
    Method FindClientByName:TClient(name:String)
    	Return TClient(clientmap.valueforkey(name))
    EndMethod
    
    Method FindClientByPeer:TClient(peer:Byte Ptr)
    	Local client:TClient
    	For client=EachIn clients
    		If client.enetpeer=peer Return client
    	Next
    EndMethod
    
    Method FindClient:TClient(ip:Int,port:Int)
    	Local client:TClient
    	For client=EachIn clients
    		If client.ip=ip And client.port=port Return client
    	Next
    EndMethod
    
    Method EvaluateEvent(id:Int,packet:TPacket,enetpeer:Byte Ptr)
    	Local client:TClient
    	Local issilent:Int=False
    
    	client=FindClient(enet_peer_ip(enetpeer),enet_peer_port(enetpeer))
    	Select id
    
    	Case NETWORK_JOINREQUEST
    		If client Disconnect(client,1)
    		client=TClient.Find(enet_peer_ip(enetpeer),enet_peer_port(enetpeer))
    		client.enetpeer=enetpeer
    
    		If IPBanned(client.ip)
    			Disconnect(client,0)
    			issilent=1
    		Else
    			client.name=packet.ReadLine()
    			If Not FindClientByName(client.name)
    				clientmap.insert(client.name,client)
    				clients.AddLast(client)
    				Local responsepacket:TPacket=New TPacket
    				responsepacket.WriteByte(1)
    				responsepacket.WriteByte(clients.count())
    				Local peer:TClient
    				For peer=EachIn clients
    					responsepacket.WriteLine(peer.name)
    				Next
    				Send(client,NETWORK_JOINRESPONSE,responsepacket,SEND_RELIABLE)
    				id=NETWORK_PLAYERJOINED
    			Else
    				packet=New TPacket
    				packet.WriteByte(0)'no, you can't joint
    				packet.WriteByte(1)'reason: name already taken
    				Send(client,NETWORK_JOINRESPONSE,packet,SEND_RELIABLE)
    				'Disconnect(client,0)
    				issilent=1
    			EndIf
    		EndIf
    
    	Case NETWORK_CHANGENAMEREQUEST
    		Local name:String=packet.ReadLine()
    		packet=New TPacket
    		If client
    			If FindClientByName(name)<>Null And client.name<>name
    				packet.WriteByte(0)
    				send(client,NETWORK_CHANGENAMERESPONSE,packet,SEND_RELIABLE)
    				issilent=True
    			Else
    				packet.WriteByte(1)
    				packet.WriteLine(name)
    				send(client,NETWORK_CHANGENAMERESPONSE,packet,SEND_RELIABLE)
    				clientmap.remove(client.name)
    				client.name=name
    				clientmap.insert(name,client)
    			EndIf
    		Else
    			If FindClientByName(name)=Null
    				packet.WriteByte(1)
    				packet.WriteLine(name)
    				send(client,NETWORK_CHANGENAMERESPONSE,packet,SEND_RELIABLE)
    				issilent=True
    			EndIf
    		EndIf
    
    	Case NETWORK_CONNECT
    		issilent=True
    
    	Case NETWORK_DISCONNECT
    		client=FindClientByPeer(enetpeer)			
    		If client
    			Disconnect(client,0)
    		Else
    			issilent=True
    		EndIf
    
    	Case NETWORK_PINGREQUEST
    		Send(client,NETWORK_PINGRESPONSE,packet)
    		issilent=True
    
    	Case NETWORK_CHAT
    		Local relay:TPacket=New TPacket
    		Local count:Int=packet.ReadByte()
    		relay.WriteLine(packet.ReadLine())
    		If count=0				
    			Broadcast(NETWORK_CHAT,relay)
    		Else
    			For Local n:Int=1 To count
    				client=FindClientByName(packet.ReadLine())
    				If client
    					Send(client,NETWORK_CHAT,relay)
    				EndIf
    			Next
    		EndIf
    
    		issilent=True
    
    	EndSelect
    
    	If Not issilent
    		If callback
    			If packet packet.seek(0)
    			callback(Self,client,id,packet)
    		EndIf
    	EndIf	
    EndMethod
    
    Method Send:Int(client:TClient,id:Int,packet:TPacket=Null,flags:Int=0,channel:Int=0)
    	Local enetpacket:Byte Ptr
    	Local result:Int
    
    	If Not client.enetpeer RuntimeError "Can't send to local client."
    
    	Local data:Byte[]
    	If packet
    		If packet._bank.size()=0 packet=Null
    	EndIf
    	If packet
    		data=New Byte[packet._bank.size()+1]
    		MemCopy(Varptr data[1],packet._bank.buf(),packet._bank.size())
    	Else
    		data=New Byte[1]
    	EndIf
    	data[0]=id
    	enetpacket=enet_packet_create(data,data.length,flags)
    	result=(enet_peer_send(client.enetpeer,channel,enetpacket)=0)		
    	Return result
    EndMethod
    
    Method Broadcast:Int(id:Int,packet:TPacket=Null,flags:Int=0,channel:Int=0)
    	Local result:Int=1
    	For Local client:TClient=EachIn clients
    		If Not Send(client,id,packet,flags,channel) result=0
    	Next
    	Return result
    	Rem
    	Local enetpacket:Byte Ptr
    	Local result:Int
    
    	Local data:Byte[]
    	If packet
    		If packet._bank.size()=0 packet=Null
    	EndIf
    	If packet
    		data=New Byte[packet._bank.size()+1]
    		MemCopy(Varptr data[1],packet._bank.buf(),packet._bank.size())
    	Else
    		data=New Byte[1]
    	EndIf
    	data[0]=id
    	enetpacket=enet_packet_create(data,data.length,flags)
    	enet_host_broadcast(Self.enethost,channel,enetpacket)
    	EndRem
    EndMethod
    
    Method Disconnect(client:TClient,force:Int=False)
    	If client.enetpeer
    		If force
    			enet_peer_reset(client.enetpeer)
    		Else
    			enet_peer_disconnect(client.enetpeer)
    		EndIf
    		clients.remove(client)
    		If Not client.enethost
    			client.link.remove()
    		EndIf
    		If clientmap.valueforkey(client.name)=client
    			clientmap.remove(client.name)
    		EndIf
    	EndIf
    EndMethod
    
    Method BanIP(ip:Int)
    	bannedips=bannedips[..bannedips.length+1]
    	bannedips[bannedips.length-1]=ip
    EndMethod
    
    Method IPBanned:Int(ip:Int)
    	For Local n:Int=0 To bannedips.length-1
    		If ip=bannedips[n] Return True
    	Next
    	Return False
    EndMethod
    
    Method Kick(client:TClient)
    	BanIP(client.ip)
    	Disconnect(client)
    EndMethod
    
    EndType
    
    Type TClient Extends TNetworkNode
    
    Const maxplayers:Int=64
    
    Global list:TList=New TList
    
    Field name:String
    Field link:TLink
    Field server:TServer
    Field connected:Int
    Field joined:Int=0
    Field callback(client:TClient,id:Int,packet:TPacket)
    
    Function Find:TClient(ip:Int,port:Int)
    	Local client:TClient
    	For client=EachIn list
    		If client.ip=ip And client.port=port Return client
    	Next
    	client=New TClient
    	client.ip=ip
    	client.port=port
    	client.link=list.addlast(client)
    	Return client
    EndFunction
    
    Function Create:TClient(ip:Int=0,port:Int=7776)
    	Local client:TClient=Find(ip,port)
    	Local addr:Byte Ptr
    
    	If ip
    		client.ip=ip
    	Else
    		client.ip=ENET_HOST_ANY
    	EndIf
    	client.port=port
    	If client.port<>0 Or client.ip<>ENET_HOST_ANY addr=enet_address_create(client.ip,client.port)
    	client.enethost=enet_host_create(addr,maxplayers,0,0)
    	If addr enet_address_destroy(addr)
    	If Not client.enethost
    		Return Null
    	EndIf
    	Return client
    EndFunction
    
    Method Disconnect(force:Int=False)
    	If server
    		If force
    			enet_peer_reset(server.enetpeer)
    		Else
    			enet_peer_disconnect(server.enetpeer)
    		EndIf
    		server=Null
    	EndIf
    EndMethod
    
    Method SetName(name:String)
    	If name.length>16 name=name[..16]
    	If server
    		Local packet:TPacket=New TPacket
    		packet.WriteLine(name)
    		Send(NETWORK_CHANGENAMEREQUEST,packet,SEND_RELIABLE)
    	Else
    		Self.name=name
    	EndIf
    EndMethod
    
    Method Connect:Int(ip:Int,port:Int)
    	Local addr:Byte Ptr
    
    	If Not Self.enethost RuntimeError "Remote client cannot connect to server."
    	If server Disconnect()		
    	server=New TServer
    	server.ip=ip
    	server.port=port
    	addr=enet_address_create(server.ip,server.port)
    	server.enetpeer=enet_host_connect(Self.enethost,addr,1)
    	enet_address_destroy(addr)
    	If server.enetpeer=Null
    		server=Null
    		Return 0
    	EndIf
    	Return 1
    EndMethod
    
    Method Send:Int(id:Int,packet:TPacket=Null,flags:Int=0,channel:Int=0)
    	Local enetpacket:Byte Ptr
    	Local result:Int
    
    	If Not connected Return 0
    
    	If Not server RuntimeError "Client is not connected."
    	Local data:Byte[]
    	If packet
    		If packet._bank.size()=0 packet=Null
    	EndIf
    	If packet
    		data=New Byte[packet._bank.size()+1]
    		MemCopy(Varptr data[1],packet._bank.buf(),packet._bank.size())
    	Else
    		data=New Byte[1]
    	EndIf
    	data[0]=id
    	enetpacket=enet_packet_create(data,data.length,flags)
    	result=(enet_peer_send(server.enetpeer,channel,enetpacket)=0)		
    	Return result
    EndMethod
    
    Method EvaluateEvent(id:Int,packet:TPacket,enetpeer:Byte Ptr)
    	Local issilent:Int=False
    
    	Select id
    
    	Case NETWORK_CONNECT
    		Self.connected=True
    		packet=New TPacket
    		packet.WriteLine(name)
    		Send(NETWORK_JOINREQUEST,packet)
    
    	Case NETWORK_JOINRESPONSE
    		joined=packet.ReadByte()
    
    	Case NETWORK_CHANGENAMERESPONSE
    		If packet.ReadByte()=1
    			name=packet.ReadLine()
    		EndIf
    
    	Case NETWORK_PINGRESPONSE
    
    
    	Case NETWORK_CHAT
    
    
    	EndSelect
    
    	If Not issilent
    		If callback
    			If packet packet.seek(0)
    			callback(Self,id,packet)
    		EndIf
    	EndIf
    EndMethod
    
    Method Join()
    	If Not joined
    		Local packet:TPacket=New TPacket
    		packet.WriteLine(name)
    		Send(NETWORK_JOINREQUEST,packet)
    	EndIf
    EndMethod
    
    Method Ping:Int()
    	Local packet:TPacket=New TPacket
    	packet.WriteInt(MilliSecs())
    	Return Send(NETWORK_PINGREQUEST,packet)
    EndMethod
    
    Method Say:Int(text:String,recipients:String[]=Null)
    	Local packet:TPacket=New TPacket
    	If recipients
    		packet.WriteByte(recipients.length)
    		packet.WriteLine(text)
    		For Local n:Int=0 To recipients.length-1
    			packet.WriteLine(recipients[n])
    		Next
    	Else
    		packet.WriteByte(0)
    		packet.WriteLine(text)
    	EndIf
    	Return Send(NETWORK_CHAT,packet)		
    EndMethod
    
    EndType
    
    
    Type TPacket Extends TBankStream
    
    Method New()
    	_bank=New TBank
    EndMethod
    
    EndType
    
    
    Function CreatePacket:TPacket()
    Local packet:TPacket=New TPacket
    Return packet
    EndFunction
    
    
    '----------------------------------------------------------------------------------------------------
    
    Local server:TServer
    Local client1:TClient
    Local client2:TClient
    Local ip:Int=HostIp("127.0.0.1")
    
    server=TServer.Create(ip,7777)
    client1=TClient.Create(ip,7776)
    client2=TClient.Create(ip,7779)
    
    client1.name="Steve"
    client2.name="Bob"
    
    client1.connect(server.ip,server.port)
    client2.connect(server.ip,server.port)
    
    client1.callback=ClientCallBack
    client2.callback=ClientCallBack
    server.callback=ServerCallBack
    
    Repeat
    server.Update()
    client1.Update()
    client2.Update()
    Delay 1
    If Rand(100)=1
    	client1.SetName("Barney")
    	client1.Disconnect()
    
    	'client2.Ping()
    	client2.Say("Hello!")
    EndIf
    Forever
    
    Function ServerCallBack(server:TServer,client:TClient,id:Int,packet:TPacket)
    Select id
    Case NETWORK_PLAYERJOINED
    	Print "New player "+packet.ReadLine()+" joined."
    Case NETWORK_DISCONNECT
    	If client
    		Print client.name+" disconnected."
    	Else
    		Print "Unknown disconnection"
    		Print server.clients.count()+" players"
    	EndIf
    Case NETWORK_CONNECT
    	Print "New client connected."
    EndSelect
    EndFunction
    
    Function ClientCallBack(client:TClient,id:Int,packet:TPacket)
    Select id
    Case NETWORK_CHANGENAMERESPONSE
    	If packet.ReadByte()=1
    		Print "Changed name to "+packet.ReadLine()
    	Else
    		Print "Name change rejected."
    	EndIf
    Case NETWORK_JOINRESPONSE
    	If packet.ReadByte()=1
    		Print "Joined game"
    		Local count:Int=packet.ReadByte()
    		Print count+" players"
    		For Local n:Int=1 To count
    			Print n+". "+packet.ReadLine()
    		Next
    	Else
    		Print "Rejected from game"
    		Select packet.ReadByte()
    		Case 1
    			Print "Name already in use"
    		Default
    			Print "Unknown reason"
    		EndSelect
    	EndIf
    Case NETWORK_DISCONNECT
    	Print "Disconnected from server."
    Case NETWORK_CONNECT
    	Print "Connected to server."
    Case NETWORK_CHAT
    	Print "Says: "+packet.ReadLine()
    Case NETWORK_PINGRESPONSE
    	Print "Ping = "+(MilliSecs()-packet.ReadInt())
    EndSelect
    EndFunction

    • Upvote 1
  3. Take a look at this. Instead of a host/peer design, this is a more intuitive server/client design. If you are hosting a game, you create a server. If you want to play in the game yourself, create a client. Here, I created two clients. You could create a client for each bot and run them through the network, or just one client for yourself. You'd probably want to always run the game through the network, even if it is single-player, so that you have a uniform design for single and multi player modes.

     

    The messages are turned into a form with an ID and a packet, which is a stream of any length. There are built-in message IDs. Some are handled entirely silently. For example, when the server receives a chat message, it just broadcasts the data to all clients, without the user having to do anything. Synced entities would behave this way as well.

     

    The user's interaction with the system comes in the form of a callback. The callback can be used to do stuff when messages are received. In the example below, the client callback is used to print the ping and to print any chat messages that are sent.

     

    SuperStrict
    
    Private
    
    Function enet_host_port:Int( peer:Byte Ptr )
    Local ip:Int=(Int Ptr peer)[1]
    Local port:Int=(Short Ptr peer)[4]
    ?LittleEndian
    ip=(ip Shr 24) | (ip Shr 8 & $ff00) | (ip Shl 8 & $ff0000) | (ip Shl 24)
    ?
    Return port
    EndFunction
    
    Function enet_host_ip:Int( peer:Byte Ptr )
    Local ip:Int=(Int Ptr peer)[1]
    Local port:Int=(Short Ptr peer)[4]
    ?LittleEndian
    ip=(ip Shr 24) | (ip Shr 8 & $ff00) | (ip Shl 8 & $ff0000) | (ip Shl 24)
    ?
    Return ip
    EndFunction
    
    Function enet_peer_port:Int( peer:Byte Ptr )
    Local ip:Int=(Int Ptr peer)[3]
    Local port:Int=(Short Ptr peer)[8]
    ?LittleEndian
    ip=(ip Shr 24) | (ip Shr 8 & $ff00) | (ip Shl 8 & $ff0000) | (ip Shl 24)
    ?
    Return port
    EndFunction
    
    Function enet_peer_ip:Int( peer:Byte Ptr )
    Local ip:Int=(Int Ptr peer)[3]
    Local port:Int=(Short Ptr peer)[8]
    ?LittleEndian
    ip=(ip Shr 24) | (ip Shr 8 & $ff00) | (ip Shl 8 & $ff0000) | (ip Shl 24)
    ?
    Return ip
    EndFunction
    
    Type TNetworkNode
    
    Field port:Int
    Field ip:Int
    Field enethost:Byte Ptr
    Field enetpeer:Byte Ptr
    
    Method Delete()
    	If enethost
    		enet_host_destroy(enethost)
    		enethost=Null
    	EndIf	
    EndMethod
    
    Method Update(callback(client:TClient,id:Int,packet:TPacket)=Null)
    	Local ip:Int,port:Int,client:TClient,ev:ENetEvent=New ENetEvent,id:Byte,packet:TPacket
    
    	If Not Self.enethost RuntimeError "Can't update a remote server."
    	Repeat
    		If enet_host_service(Self.enethost,ev,0)
    
    			Select ev.event
    
    			Case ENET_EVENT_TYPE_CONNECT
    				id=NETWORK_CONNECT
    
    			Case ENET_EVENT_TYPE_CONNECT
    				id=NETWORK_DISCONNECT
    
    			Case ENET_EVENT_TYPE_RECEIVE
    				Local size:Int=enet_packet_size(ev.packet)
    				Local data:Byte[size]
    				MemCopy(Varptr id,enet_packet_data(ev.packet),1)
    				If size>1
    					packet=New TPacket
    					packet._bank.resize(size-1)
    					MemCopy(packet._bank.buf(),enet_packet_data(ev.packet)+1,size-1)
    				EndIf
    
    			Default
    				Continue
    
    			EndSelect
    
    			EvaluateEvent(id,packet,ev.peer)
    
    		Else
    			Exit
    		EndIf
    	Forever
    EndMethod
    
    Method EvaluateEvent(id:Int,packet:TPacket,enetpeer:Byte Ptr) Abstract
    
    EndType
    
    Public
    
    
    Const NETWORK_CONNECT:Int=1
    Const NETWORK_DISCONNECT:Int=2
    Const NETWORK_PINGREQUEST:Int=3
    Const NETWORK_PINGRESPONSE:Int=4
    Const NETWORK_JOINREQUEST:Int=5
    Const NETWORK_JOINREPLY:Int=6
    Const NETWORK_CHAT:Int=7
    
    
    Type TServer Extends TNetworkNode
    
    Const maxplayers:Int=64
    
    Field clients:TList=New TList
    Field callback(server:TServer,id:Int,packet:TPacket)
    
    Method Delete()
    	If enetpeer
    		enetpeer=Null
    	EndIf
    	If enethost
    		enet_host_destroy(enethost)
    		enethost=Null
    	EndIf	
    EndMethod
    
    Function Create:TServer(ip:Int=0,port:Int=7777)
    	Local server:TServer=New TServer,addr:Byte Ptr
    
    	If ip
    		server.ip=ip
    	Else
    		server.ip=ENET_HOST_ANY
    	EndIf
    	server.port=port
    	If server.port<>0 Or server.ip<>ENET_HOST_ANY
    		addr=enet_address_create(server.ip,server.port)
    	EndIf
    	server.enethost=enet_host_create(addr,maxplayers,0,0)
    	If addr
    		enet_address_destroy(addr)
    	EndIf
    	If Not server.enethost
    		Return Null		
    	EndIf
    	Return server
    EndFunction
    
    Method FindClient:TClient(ip:Int,port:Int)
    	Local client:TClient
    	For client=EachIn clients
    		If client.ip=ip And client.port=port Return client
    	Next
    EndMethod
    
    Method EvaluateEvent(id:Int,packet:TPacket,enetpeer:Byte Ptr)
    	Local client:TClient
    	Local issilent:Int=False
    
    	client=FindClient(enet_peer_ip(enetpeer),enet_peer_port(enetpeer))
    	Select id
    
    	Case NETWORK_CONNECT
    		If client Disconnect(client,True)
    		client=New TClient
    		client.enetpeer=enetpeer
    		client.ip=enet_peer_ip(enetpeer)
    		client.port=enet_peer_port(enetpeer)
    		client.link=clients.AddLast(client)
    
    	Case NETWORK_PINGREQUEST
    		Send(client,NETWORK_PINGRESPONSE,packet)
    		issilent=True
    
    	Case NETWORK_CHAT
    		Broadcast(id,packet)
    		issilent=True
    
    	EndSelect
    
    	If Not issilent
    		If callback
    			callback(Self,id,packet)
    		EndIf
    	EndIf	
    EndMethod
    
    Method Send:Int(client:TClient,id:Int,packet:TPacket=Null,flags:Int=0,channel:Int=0)
    	Local enetpacket:Byte Ptr
    	Local result:Int
    
    	If Not client.enetpeer RuntimeError "Can't send to local client."
    
    	Local data:Byte[]
    	If packet
    		If packet._bank.size()=0 packet=Null
    	EndIf
    	If packet
    		data=New Byte[packet._bank.size()+1]
    		MemCopy(Varptr data[1],packet._bank.buf(),packet._bank.size())
    	Else
    		data=New Byte[1]
    	EndIf
    	data[0]=id
    	enetpacket=enet_packet_create(data,data.length,flags)
    	result=(enet_peer_send(client.enetpeer,channel,enetpacket)=0)		
    	Return result
    EndMethod
    
    Method Broadcast(id:Int,packet:TPacket=Null,flags:Int=0,channel:Int=0)
    	Local enetpacket:Byte Ptr
    	Local result:Int
    
    	Local data:Byte[]
    	If packet
    		If packet._bank.size()=0 packet=Null
    	EndIf
    	If packet
    		data=New Byte[packet._bank.size()+1]
    		MemCopy(Varptr data[1],packet._bank.buf(),packet._bank.size())
    	Else
    		data=New Byte[1]
    	EndIf
    	data[0]=id
    	enetpacket=enet_packet_create(data,data.length,flags)
    	enet_host_broadcast(Self.enethost,channel,enetpacket)
    EndMethod
    
    Method Disconnect(client:TClient,force:Int=False)
    	If client.enetpeer
    		If force
    			enet_peer_reset(client.enetpeer)
    		Else
    			enet_peer_disconnect(client.enetpeer)
    		EndIf
    		client.link.remove()
    	EndIf
    EndMethod
    
    EndType
    
    
    Type TClient Extends TNetworkNode
    
    Const maxplayers:Int=64
    
    Field link:TLink
    Field server:TServer
    Field connected:Int
    Field callback(client:TClient,id:Int,packet:TPacket)
    
    Function Create:TClient(ip:Int=0,port:Int=7776)
    	Local client:TClient=New TClient
    	Local addr:Byte Ptr
    
    	If ip
    		client.ip=ip
    	Else
    		client.ip=ENET_HOST_ANY
    	EndIf
    	client.port=port
    	If client.port<>0 Or client.ip<>ENET_HOST_ANY addr=enet_address_create(client.ip,client.port)
    	client.enethost=enet_host_create(addr,maxplayers,0,0)
    	If addr enet_address_destroy(addr)
    	If Not client.enethost
    		Return Null
    	EndIf
    	Return client
    EndFunction
    
    Method Disconnect(force:Int=False)
    	If server
    		If force
    			enet_peer_reset(server.enetpeer)
    		Else
    			enet_peer_disconnect(server.enetpeer)
    		EndIf
    		server=Null
    	EndIf
    EndMethod
    
    Method Connect:TServer(ip:Int,port:Int)
    	Local addr:Byte Ptr,server:TServer
    
    	If Not Self.enethost RuntimeError "Remote client cannot connect to server."
    	If server Disconnect()		
    	server=New TServer
    	server.ip=ip
    	server.port=port
    	addr=enet_address_create(server.ip,server.port)
    	server.enetpeer=enet_host_connect(Self.enethost,addr,1)
    	enet_address_destroy(addr)
    	If server.enetpeer=Null Return Null
    	Self.server=server
    	Return server
    EndMethod
    
    Method Send:Int(id:Int,packet:TPacket=Null,flags:Int=0,channel:Int=0)
    	Local enetpacket:Byte Ptr
    	Local result:Int
    
    	If Not connected Return 0
    
    	If Not server RuntimeError "Client is not connected."
    	Local data:Byte[]
    	If packet
    		If packet._bank.size()=0 packet=Null
    	EndIf
    	If packet
    		data=New Byte[packet._bank.size()+1]
    		MemCopy(Varptr data[1],packet._bank.buf(),packet._bank.size())
    	Else
    		data=New Byte[1]
    	EndIf
    	data[0]=id
    	enetpacket=enet_packet_create(data,data.length,flags)
    	result=(enet_peer_send(server.enetpeer,channel,enetpacket)=0)		
    	Return result
    EndMethod
    
    Method EvaluateEvent(id:Int,packet:TPacket,enetpeer:Byte Ptr)
    	Local issilent:Int=False
    
    	Select id
    
    	Case NETWORK_CONNECT
    		Self.connected=True
    
    	Case NETWORK_PINGRESPONSE
    
    	Case NETWORK_CHAT
    
    	EndSelect
    
    	If Not issilent
    		If callback
    			callback(Self,id,packet)
    		EndIf
    	EndIf
    EndMethod
    
    Method Ping:Int()
    	Local packet:TPacket=New TPacket
    	packet.WriteInt(MilliSecs())
    	Return Send(NETWORK_PINGREQUEST,packet)
    EndMethod
    
    Method Say:Int(text:String)
    	Local packet:TPacket=New TPacket
    	packet.WriteLine(text)
    	Return Send(NETWORK_CHAT,packet)		
    EndMethod
    
    EndType
    
    
    Type TPacket Extends TBankStream
    
    Method New()
    	_bank=New TBank
    EndMethod
    
    EndType
    
    
    Function CreatePacket:TPacket()
    Local packet:TPacket=New TPacket
    Return packet
    EndFunction
    
    
    '----------------------------------------------------------------------------------------------------
    
    Local server:TServer
    Local client1:TClient
    Local client2:TClient
    Local ip:Int=HostIp("127.0.0.1")
    
    server=TServer.Create(ip,7777)
    client1=TClient.Create(ip,7776)
    client2=TClient.Create(ip,7779)
    
    client1.connect(server.ip,server.port)
    client2.connect(server.ip,server.port)
    
    client1.callback=ClientCallBack
    client2.callback=ClientCallBack
    server.callback=ServerCallBack
    
    Repeat
    server.Update()
    client1.Update()
    client2.Update()
    Delay 1
    If Rand(100)=1
    	client1.Ping()
    	client2.Say("Hello!")
    EndIf
    Forever
    
    Function ServerCallBack(server:TServer,id:Int,packet:TPacket)
    Select id
    Case NETWORK_CONNECT
    	Print "New client connected."
    EndSelect
    EndFunction
    
    Function ClientCallBack(client:TClient,id:Int,packet:TPacket)
    Select id
    Case NETWORK_CONNECT
    	Print "Connected to server."
    Case NETWORK_CHAT
    	Print "Says: "+packet.ReadLine()
    Case NETWORK_PINGRESPONSE
    	Print "Ping = "+(MilliSecs()-packet.ReadInt())
    EndSelect
    EndFunction

  4. 1. Move the emitter around with the camera.

     

    2. Render the scene to a depth-only buffer with an orthogonal camera over the player's head looking down. Then use this depth buffer in the particle fragment shader to discard fragments that are behind what the depth buffer sees. This is how STALKER handles rain. Not easy, but if you look at some of the shadow shaders everything you need is there. I have been meaning to do this, but just haven't had time.

  5. 1.-How many polygons can move fluently leadwerks?

    The question really is how many polygons can your GPU render fluently? A 3D engine itself does not make much of a difference, as long as it is using the fast-track rendering pathways. A few hundred thousand polys (plus shadow polys) is usually comfortable. You can easily render tens of thousands of trees and plants.

     

    2.-Hold out much longer mathematical process that BlitzMax?

    I don't understand this.

     

    3.-Do I earn a lot in graphic appearance with the engine change?

    I think so. Look at the user gallery. It's pretty easy for a programmer to download a few good-looking models and put together something that looks really good.

     

    4.-What about efficient processes?

    I don't understand this.

     

    5.-Should we switch to C + +?

    BlitzMax will be fine if you are already comfortable with that.

  6. I am looking for someone to add some animations to the soldier character. I need the following cycles:

     

    -idle

    -run

    -run left

    -run right

    -run backwards

    -turn feet left

    -turn feet right

     

    The character should be posed to hold a rifle-type gun in each animation.

  7. I'm sure you could use a couple of static bodies for the feet, a static body for the pelvis, and a body with mass for the knees. Connect the knees to the pelvis with a ball joint with limits, and the feet to the knees with a hinge. Move the feet wherever you want them to be, and the knees will follow. Parent the knee bones to the knee bodies, and you have IK animation.

×
×
  • Create New...