Page 5 of 7 FirstFirst ... 34567 LastLast
Results 41 to 50 of 66

Thread: Game Network Engine

  1. #41

    Game Network Engine

    Any news on the network engine endeavor?
    Its not has fun as AI or 3D rendering but, sadly, it has to be done

    I want to (re)start working on my RTS-TBS game and for that I need reliable TSP/IP based networking.

    It could have been nice to have WCF/Remoting style in Delphi, is there something like that available?
    Any ideas/request for approaching this?
    I was thinking about a simple approach, send command records with a known format:
    [pascal]TBasePacket = packed record
    ID: cardinal;
    Size: cardinal;
    End;
    TDoSomthingPacket = packed record
    ID: cardinal;
    Size: cardinal;
    NewX, NewY: integer;
    ...
    End;
    [/pascal]This way the software reads the stream, with the ID it knows what type of packet it is (for casting).
    [size=9px]BEGIN GEEK CODE BLOCK
    <br />d s-- : a24 GB GCS GTW GE C++ P L+ W++ N+ K- w++++ M- PS+ PE+ Y- t+ 5+++ X+ R*
    <br />tv b+ DI++ D+ e++ h+ G-
    <br />END GEEK CODE BLOCK[/size]
    <br />Create your own GeekCode block at: <a href="">...</a>

  2. #42

    Game Network Engine

    variant record?
    From brazil (:

    Pascal pownz!

  3. #43

    Game Network Engine

    I dropped the idea of building a Net work engine in favour of building a 3D game engine InfintEngine for the InfiniteSpace-Online project.

    I have recently started using ENet as a basis for the Network engine as it provides Reliable UDP support. However I am using Indy as well but this detils will be wrapped up under one simple interface.
    <A HREF="http://www.myhpf.co.uk/banner.asp?friend=139328">
    <br /><IMG SRC="http://www.myhpf.co.uk/banners/60x468.gif" BORDER="0">
    <br /></A>

  4. #44

    Game Network Engine

    arthurprs: no, simple record.
    You read a stream of data, you know that the 1st word has the Type ID. so you can read the next SizeOf(OurRecord) directly into the record's pointer.
    Nothing smart, I don't understand the data I simply dump it into the correct record type.

    technomage: Sent you a PM.
    [size=9px]BEGIN GEEK CODE BLOCK
    <br />d s-- : a24 GB GCS GTW GE C++ P L+ W++ N+ K- w++++ M- PS+ PE+ Y- t+ 5+++ X+ R*
    <br />tv b+ DI++ D+ e++ h+ G-
    <br />END GEEK CODE BLOCK[/size]
    <br />Create your own GeekCode block at: <a href="">...</a>

  5. #45
    Legendary Member cairnswm's Avatar
    Join Date
    Nov 2002
    Location
    Randburg, South Africa
    Posts
    1,537

    Game Network Engine

    What I have done before for networking was through a use of a case inside the record. So the recieving side can always load it directly into a record because every message is the same size:

    [pascal]type
    TShapeList = (Rectangle, Triangle, Circle, Ellipse, Other);
    TFigure = record
    ID : TShapeList
    case TShapeList of
    Rectangle: (Height, Width: Real);

    Triangle: (Side1, Side2, Angle: Real);
    Circle: (Radius: Real);
    Ellipse, Other: ();
    end;
    [/pascal]

    And then you dont need to do fancy tricks reading off the stream as every record is the same size.
    William Cairns
    My Games: http://www.cairnsgames.co.za (Currently very inactive)
    MyOnline Games: http://TheGameDeveloper.co.za (Currently very inactive)

  6. #46

    Game Network Engine

    That’s a nice idea but it works for simple objects, as the more complex are the object the more overhead you’ll get.
    but its a good idea to keep in mind
    [size=9px]BEGIN GEEK CODE BLOCK
    <br />d s-- : a24 GB GCS GTW GE C++ P L+ W++ N+ K- w++++ M- PS+ PE+ Y- t+ 5+++ X+ R*
    <br />tv b+ DI++ D+ e++ h+ G-
    <br />END GEEK CODE BLOCK[/size]
    <br />Create your own GeekCode block at: <a href="">...</a>

  7. #47

    Game Network Engine

    cairnswm code is a variant record, whats the problem with then?

    of course they are not good for complex objects but they are very simple and easy to manage
    From brazil (:

    Pascal pownz!

  8. #48

    Game Network Engine

    No problem with them, simply not what I want to do
    I am reading a few articles about networking. I’ll post my finding in a separate post.
    [size=9px]BEGIN GEEK CODE BLOCK
    <br />d s-- : a24 GB GCS GTW GE C++ P L+ W++ N+ K- w++++ M- PS+ PE+ Y- t+ 5+++ X+ R*
    <br />tv b+ DI++ D+ e++ h+ G-
    <br />END GEEK CODE BLOCK[/size]
    <br />Create your own GeekCode block at: <a href="">...</a>

  9. #49

    Game Network Engine

    I'm not a networking guru, but I'd like to share my knowledge with you.

    In past few years I worked with two ways of dealing with the networking. The first way was based on strings. Consider this:
    Code:
    Packet Type|User ID|Param Count|Param0|Param1...|Paramn
    Using strings like that you can transfer data pretty easily. Look at this example:
    [pascal]
    const
    PACKET_TYPE_LOGIN = 'LOG';
    PACKET_TYPE_LOGOFF = 'OFF';
    PACKET_TYPE_CHAT = 'CHT';
    PACKET_TYPE_MOVE = 'MOV';
    PACKET_TYPE_SHOOT = 'SHT';

    var
    Msg: ShortString;
    UserID: Integer;
    begin
    UserID := 20;
    Msg := PACKET_TYPE_LOGOFF + '|' + IntToStr(UserID) + '|' + '0';
    end;
    [/pascal]
    This is an example of the message send to the server when user tries to log off. As for the server, it could use something like that to read the data:
    [pascal]
    const
    PACKET_TYPE_LOGIN = 'LOG';
    PACKET_TYPE_LOGOFF = 'OFF';
    PACKET_TYPE_CHAT = 'CHT';
    PACKET_TYPE_MOVE = 'MOV';
    PACKET_TYPE_SHOOT = 'SHT';

    procedure Split(const AOutput: TStrings; const AText, ASeparator: String);
    var
    S1, S2: string;
    begin
    AOutput.Clear();
    S2 := AText + ASeparator;
    repeat
    S1 := Copy(S2, 0, Pos(ASeparator, S2) - 1);
    AOutput.Add(S1);
    Delete(S2, 1, Length(S1 + ASeparator));
    until (S2 = '');
    end;

    var
    RcvdMsg: String;
    SL: TStringList;
    begin
    // before calling this, RcvdMsg has to be filled with data
    Split(SL, RcvdMsg, '|');

    // check if the packet type is logging in
    if (SL[0] = PACKET_TYPE_LOGOFF) then
    begin
    if not UserList.UserConnected(SL[1]) then // user is connected
    exit;
    if (StrToInt(SL[2]) <> 0) then // invalid paramater count
    exit;
    UserList.Delete(StrToInt(SL[1]));
    end;

    end;
    [/pascal]
    I think this way is good for small games.

    Another idea is to use variant records. I think someone has mentioned an example of a variant record before, yet I'm doing it again:
    [pascal]
    type
    { .: TPacketType :. }
    TPacketType = (ptLogin, ptLogoff, ptChat, ptMove, ptShoot);

    { .: TPacket :. }
    TPacket = packed record
    PkgType: TPacketType;
    UserID: Integer;
    case TPacketType of
    ptLogin: (Login: String[15]; Password: String[15]);
    ptChat: (Destination: String[15]; ChatText: String[255]);
    ptMove: (X, Z: Single);
    ptShoot: (StartX, StartZ: Single);
    end;
    [/pascal]
    Personally, I'd stick with variant records, because the size of the record is always the same, no matter what type it is.

    Now, let's compare the bandwidth used by both solutions. With strings, it varies, because it depends on the packet type. But let's assume that each packet is 255 bytes. It's around 21,5 MB/day for one person. Similar situation is with variant record. Its size is 277 bytes and the bandwidth is around 23,3 MB/day. It's quite a lot, but with records, you can reduce the size by using Word type instead of Integer.

    Correct me if I'm wrong.

  10. #50

    Game Network Engine

    Hi guys,
    I am definitely not a networking guru either, but I have whipped up a quick example of a possible way to do the packets which should be very flexible too.

    see the code below:

    Code:
    Unit packet_types;
    &#123;$IFDEF fpc&#125;
    &#123;$MODE DELPHI&#125; &#123;$H+&#125;
    &#123;$ENDIF&#125;
    Interface
    
    Type
    &#123;..............................................................................&#125;
        TPacketType = &#40;
            ePacketType_Login,
            ePacketType_Logoff,
            ePacketType_Chat
        &#41;;
        TPacket = Packed Record
            PacketType &#58; TPacketType;
        End;
        TPacket_Login = Packed Record
            PacketType &#58; TPacketType;
            Username   &#58; String&#91;15&#93;;
            Password   &#58; String&#91;15&#93;;
        End;
        TPacket_Logoff = Packed Record
            PacketType &#58; TPacketType;
            Username   &#58; String&#91;15&#93;;
            Password   &#58; String&#91;15&#93;;
        End;
        TPacket_Chat = Packed Record
            PacketType &#58; TPacketType;
            Msg        &#58; ShortString;
        End;
        PPacket        = ^TPacket;
        PPacket_Login  = ^TPacket_Login;
        PPacket_Logoff = ^TPacket_Logoff;
        PPacket_Chat   = ^TPacket_Chat;
    &#123;..............................................................................&#125;
    
    Implementation
    
    End.
    Code:
    Unit packet_classes;
    &#123;$IFDEF fpc&#125;
    &#123;$MODE DELPHI&#125; &#123;$H+&#125;
    &#123;$ENDIF&#125;
    Interface
    
    Uses
        packet_types;
    
    Type
    &#123;..............................................................................&#125;
        TPacketReader = Class
        Private
        Protected
            Function  ReadData&#40;Const AData &#58; Pointer; Const ADataSize &#58; LongInt&#41; &#58; Boolean;  Virtual;
        Public
            Function  ReadPacket&#40;Var APacket &#58; Pointer&#41; &#58; Boolean;
            Procedure FreePacket&#40;Var APacket &#58; Pointer&#41;;
        End;
    &#123;..............................................................................&#125;
    
    &#123;..............................................................................&#125;
        TPacketWriter = Class
        Private
            Function  WritePacket&#40;Const APacket &#58; PPacket&#41; &#58; Boolean;
        Protected
            Function  WriteData&#40;Const AData &#58; Pointer; Const ADataSize &#58; LongInt&#41; &#58; Boolean; Virtual;
        Public
            Function  WriteLoginPacket &#40;Const AUserName,APassWord &#58; AnsiString&#41; &#58; Boolean;
            Function  WriteLogoffPacket&#40;Const AUserName,APassWord &#58; AnsiString&#41; &#58; Boolean;
            Function  WriteChatPacket  &#40;Const AMsg                &#58; AnsiString&#41; &#58; Boolean;
        End;
    &#123;..............................................................................&#125;
    
    
    Implementation
    
    &#123;..............................................................................&#125;
    
    &#123;..............................................................................&#125;
    Function TPacketWriter.WriteData&#40;Const AData &#58; Pointer; Const ADataSize &#58; LongInt&#41; &#58; Boolean;
    Begin
        Result &#58;= False;
        &#123;Write ADataASize bytes from AData to the network and return true if successfull&#125;
        &#123;override this in descendent classes&#125;
    End;
    &#123;..............................................................................&#125;
    
    &#123;..............................................................................&#125;
    Function TPacketReader.ReadData&#40;Const AData &#58; Pointer; Const ADataSize &#58; LongInt&#41; &#58; Boolean;
    Begin
        Result &#58;= False;
       &#123;fill AData with ADataSize bytes from the network and return true if successfull&#125;
        &#123;override this in descendent classes&#125;
    End;
    &#123;..............................................................................&#125;
    
    &#123;..............................................................................&#125;
    Function TPacketReader.ReadPacket&#40;Var APacket &#58; Pointer&#41; &#58; Boolean;
    Var
        DataSize &#58; LongInt;
        Packet   &#58; Pointer;
    Begin
        Result &#58;= False;
        If Not ReadData&#40;@DataSize,SizeOf&#40;DataSize&#41;&#41; Then Exit;
        GetMem&#40;Packet,DataSize&#41;;
        If Not ReadData&#40;Packet,DataSize&#41; Then
        Begin
            FreeMem&#40;Packet&#41;;
            Exit;
        End;
        APacket &#58;= Packet;
        Result  &#58;= True;
    End;
    &#123;..............................................................................&#125;
    
    &#123;..............................................................................&#125;
    Procedure TPacketReader.FreePacket&#40;Var APacket &#58; Pointer&#41;;
    Begin
        If APacket = Nil Then Exit;
        FreeMem&#40;APacket&#41;;
        APacket &#58;= Nil;
    End;
    &#123;..............................................................................&#125;
    
    &#123;..............................................................................&#125;
    Function  TPacketWriter.WritePacket&#40;Const APacket &#58; PPacket&#41; &#58; Boolean;
    Var
        DataSize &#58; LongInt;
    Begin
        Result &#58;= False;
        Case APacket^.PacketType Of
            ePacketType_Login  &#58; DataSize &#58;= SizeOf&#40;TPacket_Login&#41;;
            ePacketType_Logoff &#58; DataSize &#58;= SizeOf&#40;TPacket_Logoff&#41;;
            ePacketType_Chat   &#58; DataSize &#58;= SizeOf&#40;TPacket_Chat&#41;;
        Else
            Exit;
        End;
        If Not WriteData&#40;@DataSize,SizeOf&#40;DataSize&#41;&#41; Then Exit;
        If Not WriteData&#40;APacket,DataSize&#41;           Then Exit;
        Result &#58;= True;
    End;
    &#123;..............................................................................&#125;
    
    &#123;..............................................................................&#125;
    Function  TPacketWriter.WriteLoginPacket&#40;Const AUserName,APassWord &#58; AnsiString&#41; &#58; Boolean;
    Var
        LoginPacket &#58; TPacket_Login;
    Begin
        LoginPacket.PacketType &#58;= ePacketType_Login;
        LoginPacket.Username   &#58;= AUserName;
        LoginPacket.PassWord   &#58;= APassWord;
        Result &#58;= WritePacket&#40;@LoginPacket&#41;;
    End;
    &#123;..............................................................................&#125;
    
    &#123;..............................................................................&#125;
    Function  TPacketWriter.WriteLogoffPacket&#40;Const AUserName,APassWord &#58; AnsiString&#41; &#58; Boolean;
    Var
        LogoffPacket &#58; TPacket_Logoff;
    Begin
        LogoffPacket.PacketType &#58;= ePacketType_Logoff;
        LogoffPacket.Username   &#58;= AUserName;
        LogoffPacket.PassWord   &#58;= APassWord;
        Result &#58;= WritePacket&#40;@LogoffPacket&#41;;
    End;
    &#123;..............................................................................&#125;
    
    &#123;..............................................................................&#125;
    Function  TPacketWriter.WriteChatPacket&#40;Const AMsg &#58; AnsiString&#41; &#58; Boolean;
    Var
        ChatPacket &#58; TPacket_Chat;
    Begin
        ChatPacket.PacketType &#58;= ePacketType_Chat;
        ChatPacket.Msg        &#58;= AMsg;
        Result &#58;= WritePacket&#40;@ChatPacket&#41;;
    End;
    &#123;..............................................................................&#125;
    
    &#123;..............................................................................&#125;
    End.
    Example usage:

    Code:
    Type
    &#123;..............................................................................&#125;
        TPacketReader_Stream = Class&#40;TPacketReader&#41;
        Private
            FStream &#58; TStream;
        Protected
            Function ReadData&#40;Const AData &#58; Pointer; Const ADataSize &#58; LongInt&#41; &#58; Boolean;  Override;
        Public
            Constructor Create&#40;Const AStream &#58; TStream&#41;;
        End;
    &#123;..............................................................................&#125;
    
    &#123;..............................................................................&#125;
        TPacketWriter_Stream = Class&#40;TPacketWriter&#41;
        Private
            FStream &#58; TStream;
        Protected
            Function WriteData&#40;Const AData &#58; Pointer; Const ADataSize &#58; LongInt&#41; &#58; Boolean; Override;
        Public
            Constructor Create&#40;Const AStream &#58; TStream&#41;;
        End;
    &#123;..............................................................................&#125;
    
    Constructor TPacketReader_Stream.Create&#40;Const AStream &#58; TStream&#41;;
    Begin
        Inherited Create;
        FStream &#58;= AStream;
    End;
    &#123;..............................................................................&#125;
    
    &#123;..............................................................................&#125;
    Function TPacketReader_Stream.ReadData&#40;Const AData &#58; Pointer; Const ADataSize &#58; LongInt&#41; &#58; Boolean;
    Type
        PByte = ^Byte;
    Begin
        Result &#58;= FStream.Read&#40;PByte&#40;AData&#41;^,ADataSize&#41; = ADataSize;
    End;
    &#123;..............................................................................&#125;
    
    &#123;..............................................................................&#125;
    Constructor TPacketWriter_Stream.Create&#40;Const AStream &#58; TStream&#41;;
    Begin
        Inherited Create;
        FStream &#58;= AStream;
    End;
    &#123;..............................................................................&#125;
    
    &#123;..............................................................................&#125;
    Function TPacketWriter_Stream.WriteData&#40;Const AData &#58; Pointer; Const ADataSize &#58; LongInt&#41; &#58; Boolean;
    Type
        PByte = ^Byte;
    Begin
        Result &#58;= FStream.Write&#40;PByte&#40;AData&#41;^,ADataSize&#41; = ADataSize;
    End;
    &#123;..............................................................................&#125;
    
    &#123;..............................................................................&#125;
    Procedure WritePackets&#40;Const APacketWriter &#58; TPacketWriter&#41;;
    Begin
        APacketWriter.WriteLoginPacket &#40;'UserName','PassWord'&#41;;
        APacketWriter.WriteChatPacket  &#40;'Message#1'&#41;;
        APacketWriter.WriteChatPacket  &#40;'Message#2'&#41;;
        APacketWriter.WriteChatPacket  &#40;'Message#3'&#41;;
        APacketWriter.WriteChatPacket  &#40;'Message#4'&#41;;
        APacketWriter.WriteChatPacket  &#40;'Message#5'&#41;;
        APacketWriter.WriteChatPacket  &#40;'Message#6'&#41;;
        APacketWriter.WriteLogoffPacket&#40;'UserName','PassWord'&#41;;
    End;
    &#123;..............................................................................&#125;
    
    &#123;..............................................................................&#125;
    Procedure ProcessLoginPacket&#40;Const APacket &#58; PPacket_Login&#41;;
    Begin
        WriteLn&#40;'Login Packet&#58;'&#41;;
        WriteLn&#40;'  ',APacket^.UserName&#41;;
        WriteLn&#40;'  ',APacket^.PassWord&#41;;
    End;
    &#123;..............................................................................&#125;
    
    &#123;..............................................................................&#125;
    Procedure ProcessLogoffPacket&#40;Const APacket &#58; PPacket_Logoff&#41;;
    Begin
        WriteLn&#40;'Logoff Packet&#58;'&#41;;
        WriteLn&#40;'  ',APacket^.UserName&#41;;
        WriteLn&#40;'  ',APacket^.PassWord&#41;;
    End;
    &#123;..............................................................................&#125;
    
    &#123;..............................................................................&#125;
    Procedure ProcessChatPacket&#40;Const APacket &#58; PPacket_Chat&#41;;
    Begin
        WriteLn&#40;'Chat Packet&#58; '&#41;;
        WriteLn&#40;'  ',APacket^.Msg&#41;;
    End;
    &#123;..............................................................................&#125;
    
    &#123;..............................................................................&#125;
    Procedure ReadPackets&#40;Const APacketReader &#58; TPacketReader&#41;;
    Var
        Packet &#58; Pointer;
    Begin
        While APacketReader.ReadPacket&#40;Packet&#41; Do
        Begin
            Case PPacket&#40;Packet&#41;^.PacketType Of
                ePacketType_Login  &#58; ProcessLoginPacket &#40;Packet&#41;;
                ePacketType_Logoff &#58; ProcessLogoffPacket&#40;Packet&#41;;
                ePacketType_Chat   &#58; ProcessChatPacket  &#40;Packet&#41;;
            Else
                &#123;unknown packet so do error or something&#125;
            End;
            APacketReader.FreePacket&#40;Packet&#41;;
        End;
    End;
    &#123;..............................................................................&#125;
    
    &#123;..............................................................................&#125;
    Var
        PacketReader &#58; TPacketReader;
        PacketWriter &#58; TpacketWriter;
        MemoryStream &#58; TMemoryStream;
    begin
        MemoryStream &#58;= TMemoryStream.Create;
        PacketWriter &#58;= TPacketWriter_Stream.Create&#40;MemoryStream&#41;;
        PacketReader &#58;= TPacketReader_Stream.Create&#40;MemoryStream&#41;;
        WritePackets&#40;PacketWriter&#41;;
        MemoryStream.Position &#58;= 0;
        ReadPackets&#40;PacketReader&#41;;
        MemoryStream.Free;
        WriteLn&#40;'Finished!'&#41;;
        ReadLn;
    End.
    It does work (I tried it on a Stream packet reader writer descendants as a test), and should be easy to modify.
    It should be fairly easy to make TPacketReader/Writer descendants to read and write from sockets too (synapse, indy, etc).

    cheers,
    Paul

Page 5 of 7 FirstFirst ... 34567 LastLast

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •