-
Posts
23,313 -
Joined
-
Last visited
Content Type
Blogs
Forums
Store
Gallery
Videos
Posts posted by Josh
-
-
Try again.
-
Join my server and let's talk and test.
http://www.leadwerks.com/post/chat3.zip
-----------------------------
Version 3 is up with asynchrous server pinging.
- 1
-
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
- 1
-
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
-
It depends mostly on what your criteria is. If you want good graphics and good physics, this engine is your best bet.
-
Use uncompressed DDS format. DXTC1 is the worst format you can use. It should never be used. Use DXTC5 for compressed textures.
-
I can't view your animation right now because I do not have 3ds max.
If you are not an expert at animating, I would not put any more time into it. Thanks for trying to help, though.
-
How do you want the coordinates? It can be as simple as writing a short script that prints the camera position.
-
This is amazing. You even used the average pixel color to control the light color.
-
I am asking because I don't want to waste his time. I also don't expect this to be free.
-
It confuses me as to why things get hidden from us
Because C++ programmers want to be able to call framework commands with Lua.
-
Do you have a portfolio? What kind of animation work have you done?
-
Make a mesh out of n*2 number of triangles, and move the vertices around to make particles. That's how we all did it in the days of Blitz3D.
-
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.
-
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.
-
You could do that just by rearranging the vertices of a mesh.
-
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.
-
Yes, you can set the occlusion culling mode to 0 (disabled). I believe this problem has been fixed pretty well in more recent versions of the engine.
-
You can't really move a particle on its own, either. Particles are never removed, they just get recycled in a loop.
-
You can't delete a single particle.
-
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.
-
It is possible to render to two separate windows, but you will need to initialize an OpenGL context in each yourself.
-
That is possible.
-
The gray skin has some problems with the gallery and blogs. It's removed.
Use objects from the scene editor
in General Discussion
Posted
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.