(* * Hedgewars, a worms-like game * Copyright (c) 2004, 2005 Andrey Korotaev <unC0Rr@gmail.com> * * Distributed under the terms of the BSD-modified licence: * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * with the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *)unit uIO;interfaceuses SDLh;{$INCLUDE options.inc}const ipcPort: Word = 0;procedure SendIPC(s: shortstring);procedure SendIPCXY(cmd: char; X, Y: SmallInt);procedure SendIPCRaw(p: pointer; len: Longword);procedure SendIPCAndWaitReply(s: shortstring);procedure IPCWaitPongEvent;procedure IPCCheckSock;procedure InitIPC;procedure CloseIPC;procedure NetGetNextCmd;implementationuses uConsole, uConsts, uWorld, uMisc, uRandom, uLand;const isPonged: boolean = false;var IPCSock: PTCPSocket = nil; fds: PSDLNet_SocketSet; extcmd: array[word] of packed record Time: LongWord; case byte of 1: (len: byte; cmd: Char; X, Y: SmallInt); 2: (str: shortstring); end; cmdcurpos: integer = 0; cmdendpos: integer = -1;procedure InitIPC;var ipaddr: TIPAddress;beginWriteToConsole('Init SDL_Net... ');SDLTry(SDLNet_Init = 0, true);fds:= SDLNet_AllocSocketSet(1);SDLTry(fds <> nil, true);WriteLnToConsole(msgOK);WriteToConsole('Establishing IPC connection... ');SDLTry(SDLNet_ResolveHost(ipaddr, '127.0.0.1', ipcPort) = 0, true);IPCSock:= SDLNet_TCP_Open(ipaddr);SDLTry(IPCSock <> nil, true);WriteLnToConsole(msgOK)end;procedure CloseIPC;beginSDLNet_FreeSocketSet(fds);SDLNet_TCP_Close(IPCSock);SDLNet_Quitend;procedure ParseIPCCommand(s: shortstring);begincase s[1] of '!': begin {$IFDEF DEBUGFILE}AddFileLog('Ping? Pong!');{$ENDIF}isPonged:= true; end; '?': SendIPC('!'); 'e': ParseCommand(copy(s, 2, Length(s) - 1)); 'E': OutError(copy(s, 2, Length(s) - 1), true); 'W': OutError(copy(s, 2, Length(s) - 1), false); 'T': case s[2] of 'L': GameType:= gmtLocal; 'D': GameType:= gmtDemo; 'N': GameType:= gmtNet; 'S': GameType:= gmtSave; else OutError(errmsgIncorrectUse + ' IPC "T" :' + s[2], true) end; else inc(cmdendpos); extcmd[cmdendpos].Time := SDLNet_Read32(@s[byte(s[0]) - 3]); extcmd[cmdendpos].str := s; {$IFDEF DEBUGFILE}AddFileLog('IPC in: '+s[1]+' ticks '+inttostr(extcmd[cmdendpos].Time)+' at '+inttostr(cmdendpos));{$ENDIF} dec(extcmd[cmdendpos].len, 4) endend;procedure IPCCheckSock;const ss: string = '';var i: integer; buf: array[0..255] of byte; s: shortstring absolute buf;beginfds.numsockets:= 0;SDLNet_AddSocket(fds, IPCSock);while SDLNet_CheckSockets(fds, 0) > 0 do begin i:= SDLNet_TCP_Recv(IPCSock, @buf[1], 255); if i > 0 then begin buf[0]:= i; ss:= ss + s; while (Length(ss) > 1)and(Length(ss) > byte(ss[1])) do begin ParseIPCCommand(copy(ss, 2, byte(ss[1]))); Delete(ss, 1, Succ(byte(ss[1]))) end end else OutError('IPC connection lost', true) end;end;procedure SendIPC(s: shortstring);beginif IPCSock <> nil then begin if s[0]>#251 then s[0]:= #251; SDLNet_Write32(GameTicks, @s[Succ(byte(s[0]))]); {$IFDEF DEBUGFILE}AddFileLog('IPC send: '+s);{$ENDIF} inc(s[0],4); SDLNet_TCP_Send(IPCSock, @s, Succ(byte(s[0]))) endend;procedure SendIPCRaw(p: pointer; len: Longword);beginSDLNet_TCP_Send(IPCSock, p, len)end;procedure SendIPCXY(cmd: char; X, Y: SmallInt);var s: shortstring;begins[0]:= #5;s[1]:= cmd;SDLNet_Write16(X, @s[2]);SDLNet_Write16(Y, @s[4]);SendIPC(s)end;procedure IPCWaitPongEvent;beginisPonged:= false;repeat IPCCheckSock; SDL_Delay(1)until isPongedend;procedure SendIPCAndWaitReply(s: shortstring);beginSendIPC(s);SendIPC('?');IPCWaitPongEventend;procedure NetGetNextCmd;var tmpflag: boolean;beginwhile (cmdcurpos <= cmdendpos)and(extcmd[cmdcurpos].cmd = 's') do begin WriteLnToConsole('> ' + copy(extcmd[cmdcurpos].str, 2, Pred(extcmd[cmdcurpos].len))); AddCaption('> ' + copy(extcmd[cmdcurpos].str, 2, Pred(extcmd[cmdcurpos].len)), $FFFFFF, capgrpNetSay); inc(cmdcurpos) end;if cmdcurpos <= cmdendpos then TryDo(GameTicks <= extcmd[cmdcurpos].Time, 'oops, queue error. in buffer: ' + extcmd[cmdcurpos].cmd + ' (' + inttostr(GameTicks) + ' > ' + inttostr(extcmd[cmdcurpos].Time) + ')', true);tmpflag:= true;while (cmdcurpos <= cmdendpos)and(GameTicks = extcmd[cmdcurpos].Time) do begin case extcmd[cmdcurpos].cmd of 'L': ParseCommand('+left'); 'l': ParseCommand('-left'); 'R': ParseCommand('+right'); 'r': ParseCommand('-right'); 'U': ParseCommand('+up'); 'u': ParseCommand('-up'); 'D': ParseCommand('+down'); 'd': ParseCommand('-down'); 'A': ParseCommand('+attack'); 'a': ParseCommand('-attack'); 'S': ParseCommand('switch'); 'j': ParseCommand('ljump'); 'J': ParseCommand('hjump'); ',': ParseCommand('skip'); 'N': begin tmpflag:= false; {$IFDEF DEBUGFILE}AddFileLog('got cmd "N": time '+inttostr(extcmd[cmdcurpos].Time)){$ENDIF} end; 'p': begin TargetPoint.X:= SDLNet_Read16(@extcmd[cmdcurpos].X); TargetPoint.Y:= SDLNet_Read16(@extcmd[cmdcurpos].Y); ParseCommand('put') end; 'P': begin CursorPoint.X:= SDLNet_Read16(@extcmd[cmdcurpos].X) + WorldDx; CursorPoint.Y:= SDLNet_Read16(@extcmd[cmdcurpos].Y) + WorldDy; end; '1'..'5': ParseCommand('timer ' + extcmd[cmdcurpos].cmd); #128..char(128 + cMaxSlotIndex): ParseCommand('slot ' + char(byte(extcmd[cmdcurpos].cmd) - 79)) end; inc(cmdcurpos) end;isInLag:= (cmdcurpos > cmdendpos) and tmpflagend;end.