-
Notifications
You must be signed in to change notification settings - Fork 2
/
frmMain.pas
1167 lines (1063 loc) · 41.7 KB
/
frmMain.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
unit frmMain;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, IdSocketHandle, IdBaseComponent, IdComponent, IdUDPBase,
IdUDPServer, StdCtrls, IdGlobal, IdContext, IdCustomTCPServer,
IdTCPServer,shellapi,sys,IdBuffer, IdTCPConnection,
IdTCPClient, IdHTTP, IdCustomHTTPServer, IdHTTPServer,IdThreadComponent,
ExtCtrls, IdIntercept, IdServerInterceptLogBase, IdServerInterceptLogFile,
ygo_server_userinfo,TLHelp32, IdDNSResolver,winsock,IdSync,
IdMappedPortTCP, Crypt, StrUtils ,DateUtils;
const
CVN_NewCopy = wm_user +200;
type
TForm1 = class(TForm)
IdTCPServer1: TIdTCPServer;
Memo1: TMemo;
IdHTTPServer1: TIdHTTPServer;
Panel1: TPanel;
breg: TButton;
bserver: TButton;
eserverpost: TEdit;
bserverpost: TButton;
barena: TButton;
bmaskroom: TButton;
Button1: TButton;
Button2: TButton;
ebroadcast: TEdit;
Button3: TButton;
Button4: TButton;
Button5: TButton;
procedure IdTCPServer1Execute(AContext: TIdContext);
procedure IdTCPServer2Execute(AContext: TIdContext);
procedure FormCreate(Sender: TObject);
procedure IdTCPServer1Connect(AContext: TIdContext);
procedure FormDestroy(Sender: TObject);
procedure IdTCPServer1Disconnect(AContext: TIdContext);
procedure IdTCPServer1Exception(AContext: TIdContext;
AException: Exception);
procedure IdHTTPServer1CommandGet(AContext: TIdContext;
ARequestInfo: TIdHTTPRequestInfo;
AResponseInfo: TIdHTTPResponseInfo);
procedure bserverpostClick(Sender: TObject);
procedure barenaClick(Sender: TObject);
procedure refUI;
procedure bmaskroomClick(Sender: TObject);
procedure bregClick(Sender: TObject);
procedure bserverClick(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
procedure Button5Click(Sender: TObject);
private
{ Private declarations }
function replacename(str:string):string;
public
{ Public declarations }
exepath:string;
canregist:boolean;
iskeepversion:boolean;
lasthttpget:tdatetime;
lastjsonget:tdatetime;
lasthttpgetString,lastjsongetstring_delphi,lastjsongetString:string;
needcache:boolean;
end;
var
Form1: TForm1;
isSTART:boolean;
serverpost:string;
roomlists:tstringlist;
implementation
uses ygo_client_protocol,messageSend, messagePackage, IpRtrMib, IPFunctions, IniFiles;
{$R *.dfm}
//转换
function Str_Gb2UniCode(text: string;aw:boolean): String;
var
i,len: Integer;
cur: Integer;
t: String;
ws: WideString;
begin
if not aw then
begin
Result:=text;
exit;
end;
Result := '';
ws := text;
len := Length(ws);
i := 1;
while i <= len do
begin
cur := Ord(ws[i]);
FmtStr(t,'%4.4X',[cur]);
Result := Result + t;
Inc(i);
end;
end;
function showusername(user:tuserinfo):string;
begin
if g_userlist.Count>0 then
begin
if user.isUserInList then
result:='<font color="blue">'+user.username+'</font>'
else
result:='<font color="gray">'+user.username+'(未认证)</font>'
end
else
result:=user.username;
end;
function getPort: integer;
var
randomport:integer;
retrycount:integer;
function checkrandomport(ran:integer):boolean;
var idtcpserver:tidtcpserver;
begin
idtcpserver:=tidtcpserver.Create(nil);
try
try
idtcpserver.DefaultPort:=ran;
idtcpserver.OnExecute:=Form1.IdTCPServer2Execute;
idtcpserver.Active:=true;
idtcpserver.Active:=false;
except
result:=false;
exit;
end;
result:=true;
finally
idtcpserver.Free;
end;
end;
const maxport=19000;
minport=11000;
function getarandomint():integer;
begin
Randomize;
result:=0;
while (result>maxport) or (result<minport) do
result:=Random(maxport);
end;
begin
randomport:=getarandomint;
retrycount:=0;
while (not checkrandomport(randomport)) do
begin
inc(retrycount);
if retrycount>100 then
begin
result:=0;
exit;
end;
randomport:=getarandomint;
end;
result:=randomport;
end;
procedure JoinRoom(acontext:tuserinfo);
var tmproom:troom;
i:integer;
rule,mode:char;
enable_priority,no_check_deck,no_shuffle_deck:string[1];
start_lp,start_hand,draw_count:integer;
tmpstr:string;
strlist:tstringlist;
exepath,exeparms,exedir:pchar;
startupInfo :TStartupInfo;
procedure analyzeRoom(tmproom:troom);
begin
rule:='0';
mode:='0';
enable_priority:='F';
no_check_deck:='F';
no_shuffle_deck:='F';
start_lp:=8000;
start_hand:=5;
draw_count:=1;
tmproom.isshow:=true;
tmproom.ismarch:=false;
//roomname:='00ttt5000,5,1,asd';
//确定房间类型、模式、自定义
if copy(acontext.roomname,0,2)='T#' then
begin
mode:='2';
end;
if copy(acontext.roomname,0,2)='M#' then
begin
mode:='1';
end;
if pos('$',acontext.roomname)>0 then
tmproom.isprivate:=true
else
tmproom.isprivate:=false;
if copy(acontext.roomname,0,2)='P#' then
begin
tmproom.ismarch:=true;
end;
if copy(acontext.roomname,0,3)='PM#' then
begin
tmproom.ismarch:=true;
mode:='1';
end;
//确定房间的JSON名
if tmproom.isprivate then
tmproom.roomname_json:=copy(tmproom.roomname_real,0,pos('$',tmproom.roomname_real)-1)
else
tmproom.roomname_json:=tmproom.roomname_real;
//显示
if maskRoom then
begin
if length(tmproom.roomname_json)>6 then
tmproom.roomname_html:=copy(tmproom.roomname_json,0,6)+'...(<font color="red" title="'+tmproom.roomname_real+'">详</font>)'
else
tmproom.roomname_html:=copy(tmproom.roomname_json,0,6);
end
else
tmproom.roomname_html:=tmproom.roomname_json;
//模式
if tmproom.ismarch then
begin
tmproom.roomname_html:=tmproom.roomname_html+'<font color="d28311" title="竞技场模式">[竞]</font>'
end;
//私有
if tmproom.isprivate then
begin
tmproom.roomname_html:=tmproom.roomname_html+'<font color="red" title="密码房间">[密]</font>'
end;
//自定义
if length(acontext.roomname)>13 then
begin
tmpstr:=copy(acontext.roomname,6,length(acontext.roomname));
strlist:=tstringlist.Create;
try
try
strlist.DelimitedText:=tmpstr;
strlist.Delimiter:=',';
start_lp:=strtoint(strlist[0]);
start_hand:=strtoint(strlist[1]);
draw_count:=strtoint(strlist[2]);
rule:=acontext.roomname[1];
mode:=acontext.roomname[2];
enable_priority:=uppercase(acontext.roomname[3]);
no_check_deck:=uppercase(acontext.roomname[4]);
no_shuffle_deck:=uppercase(acontext.roomname[5]);
except
rule:='0';
mode:='0';
enable_priority:='F';
no_check_deck:='F';
no_shuffle_deck:='F';
start_lp:=8000;
start_hand:=5;
draw_count:=1;
end;
finally
strlist.Free;
end;
end;
end;
begin
if not tuserinfo(acontext).Connection.Connected then
exit;
if tuserinfo(acontext).isbaned then exit;
EnterCriticalSection(sys_LOCKroom);
try
//找房间
for i:=0 to HASH_ROOM.Count-1 do
begin
if troom(HASH_room[I]).roomname_real=acontext.roomname then
begin
//竞技场非注册不得进入
if troom(HASH_room[I]).ismarch and (not tuserinfo(acontext).isUserInList) then
begin
tuserinfo(acontext).postandexit('竞技场非注册用户不能加入');
exit;
end;
//如果决斗已经开始则退出
if troom(HASH_room[I]).duelstart then
begin
tuserinfo(acontext).postandexit('决斗已开始,无法加入');
exit;
end;
//否则添加用户信息
tmproom:=HASH_room[I];
tmproom.userlist.Add(acontext);
acontext.room:=HASH_room[I];
exit;
end;
end;
if not tuserinfo(acontext).isUserInList and (g_userlist.Count>0) then
begin
tuserinfo(acontext).postandexit('非注册用户不能建房');
exit;
end;
//找不到
if acontext.room=nil then
begin
//建房间
tmproom:=troom.Create(form1);
try
tmproom.roomname_real:=acontext.roomname;
analyzeRoom(tmproom);
tmproom.roomport:=getPort;
if tmproom.roomport=0 then
begin
tmproom.free;
exit;
end;
tmproom.creator:=acontext;
//need
tmpstr:= inttostr(tmproom.roomport)+' 0 '+rule+' '+mode+' '+enable_priority+' '
+no_check_deck+' '+no_shuffle_deck+' '+inttostr(start_lp)+' '+inttostr(start_hand)+' '+inttostr(draw_count);
//roomlists.Add(tmpstr);
//postmessage(form1.Handle,CVN_NewCopy,0,0);
exepath:=pchar(ExtractFilePath(ParamStr(0))+'ygocore.exe');
exeparms:=pchar(inttostr(tmproom.roomport)+' 0 '+rule+' '+mode+' '+enable_priority+' '
+no_check_deck+' '+no_shuffle_deck+' '+inttostr(start_lp)+' '+inttostr(start_hand)+' '+inttostr(draw_count));
exedir:=pchar(ExtractFilePath(ParamStr(0)));
FillChar(startupInfo,sizeof(StartupInfo),0);
//创建一个YGOCORE副本
if not CreateProcess(nil,pchar(exepath+' '+exeparms),Nil,Nil,True,CREATE_NO_WINDOW,Nil,exedir,startupInfo,tmproom.roomprocess) then
begin
tmproom.Free;
form1.Memo1.Lines.Add('room create fail');
acontext.room:=nil;
exit;
end;
HASH_room.Add(tmproom);
tmproom.userlist:=tlist.Create;
tmproom.userlist.Add(acontext);
acontext.room:=tmproom;
except
acontext.room:=nil;
tmproom.Free;
end;
end;
finally
LeaveCriticalSection(sys_LOCKroom);
end;
end;
procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var i:integer;
stream:tmemorystream;
recv:pointer;
buff:TIdBytes;
name,pass:string;
//maincardnum,sidebum:integer;
begin
AContext.Connection.IOHandler.ReadBytes(buff,2,false);
i:=BytesToWord(buff);
stream:=tmemorystream.Create;
try
assert(i<2000);
AContext.Connection.IOHandler.ReadStream(stream,i);
recv:=stream.Memory;
if tuserinfo(acontext).isbaned then exit;
case ord(tpackage(recv^).protocolhead1) of
CTOS_PLAYER_INFO://第一个包,用户信息
begin
tuserinfo(AContext).username:=tDuelPlayer(recv^).name;
if g_userlist.Count>0 then//如果需要做实名认证
begin
//获取用户信息
try
i:=pos('$',tuserinfo(AContext).username);
if i=0 then//找不到密码就不认证
tuserinfo(AContext).isUserInList:=false;
if i>0 then
begin
name:=copy(tuserinfo(AContext).username,0,i-1);
pass:=copy(tuserinfo(AContext).username,i+1,length(tuserinfo(AContext).username)-1);
tuserinfo(AContext).username:=replacename(name);
tuserinfo(AContext).uerpass:=encryptString(pass);
if tuserinfo(AContext).uerpass='' then
begin
tuserinfo(acontext).postandexit('无法通过认证,请确认后重连');
exit;
end;
if g_userlist.values[tuserinfo(AContext).username]<>tuserinfo(AContext).uerpass then
begin
tuserinfo(acontext).postandexit('无法通过认证,请确认后重连');
exit;
end;
tuserinfo(AContext).isUserInList:=true;
StringToWideChar(tuserinfo(AContext).username,tDuelPlayer(recv^).name,19);
end;
except
tuserinfo(AContext).isUserInList:=false;
end;
end;
move(recv^,tuserinfo(AContext).userlogininfo,41);//记录下登录的包
end;
//加入一个游戏
CTOS_JOIN_GAME://第二个包,加入游戏,使用密码作为房间名
begin
if not tuserinfo(acontext).connected then exit;
//Memo1.Lines.Add(tDuelRoom(recv^).password2name);
//版本确认102C
//showmessage(inttostr(ord(tDuelRoom(recv^).seed[0])));
if not ((ord(tDuelRoom(recv^).seed[1])=18)
and (ord(tDuelRoom(recv^).seed[0])=208)) then
begin
tuserinfo(acontext).postandexit('版本102D0,请确认');
//memo1.Lines.Add(tuserinfo(AContext).username+'dissconnect 版本不正确');
// acontext.Connection.Disconnect;
exit;
end;
tuserinfo(AContext).roomname:= replacename(tDuelRoom(recv^).password2name);
if tuserinfo(AContext).roomname='' then
begin
//memo1.Lines.Add(tuserinfo(AContext).username+'dissconnect cause noroomname');
tuserinfo(acontext).postandexit('房间为空,请修改房间名');
exit;
end;
//开始查找房间,如果找不到就创建一个
JoinRoom(tuserinfo(AContext));
sleep(500);
//ygocore.exe 7933 0 0 t t t 1000 1 1
if tuserinfo(AContext).room=nil then exit;
//创建一个TCP客户端
try
tuserinfo(AContext).CreateRoomClient;
except
exit;
end;
end;
end;
//把当前的包发给副本服务器
if assigned(tuserinfo(AContext).peerTcpClient) then
if tuserinfo(AContext).peerTcpClient.Connected then
sendstream(tuserinfo(AContext).peerTcpClient,tuserinfo(AContext).sendlock,stream);
finally
stream.Free;
end;
end;
procedure TForm1.IdTCPServer2Execute(AContext: TIdContext);
begin
AContext.Connection.Disconnect;
end;
function HostToIP(Name: string; var Ip: string): Boolean; //hosttoip 函数作用是将域名解析成ip
var
wsdata : TWSAData;
hostName : array [0..255] of char;
hostEnt : PHostEnt;
addr : PChar;
begin
WSAStartup ($0101, wsdata);
try
gethostname (hostName, sizeof (hostName));
StrPCopy(hostName, Name);
hostEnt := gethostbyname (hostName);
if Assigned (hostEnt) then
if Assigned (hostEnt^.h_addr_list) then begin
addr := hostEnt^.h_addr_list^;
if Assigned (addr) then begin
IP := Format ('%d.%d.%d.%d', [byte (addr [0]),
byte (addr [1]), byte (addr [2]), byte (addr [3])]);
Result := True;
end
else
Result := False;
end
else
Result := False
else begin
Result := False;
end;
finally
WSACleanup;
end
end;
procedure TForm1.FormCreate(Sender: TObject);
var strlist:tstringlist;
begin
iskeepversion:=false;
canregist:=false;
isarena:=false;
exepath:= ExtractFilePath(Application.ExeName);
Idtcpserver1.ContextClass:=tuserinfo;
InitializeCriticalSection(sys_LOCKroom);
InitializeCriticalSection(sys_LOCKFile);
g_userlist:=tstringlist.Create;
if fileexists(exepath+'userlist.conf') then
g_userlist.LoadFromFile(exepath+'userlist.conf');
lasthttpget:=now();
lastjsonget:=now();
needcache:=true;
HASH_ROOM:=tlist.Create;
isSTART:=true;
if fileexists(exepath+'server.conf') then
begin
try
strlist:=tstringlist.Create;
try
strlist.LoadFromFile(exepath+'server.conf');
if strlist.Values['canRegist']<>'' then
canregist:=strtobool(strlist.Values['canRegist']);
serverPort:=strtoint(strlist.Values['serverPort']);
serverHTTPPort:=strtoint(strlist.Values['serverHTTPPort']);
serverDisplayIP:=strlist.Values['serverDisplayIP'];
historyPublicURL:=strlist.Values['historyPublicURL'];
serverLogo :=strlist.Values['serverLogo'];
managepass:=strlist.Values['managepass'];
maxuser:=strtoint(strlist.Values['maxuser']);
serverURL:=strlist.Values['serverURL'];
needcache:=strtobool(strlist.Values['needHttpCache']);
if managepass='' then managepass:='showme';
if uppercase(strlist.Values['maskRoom'])='TRUE' then
maskRoom:=true
else
maskRoom:=false;
if uppercase(strlist.Values['recordReplay'])='TRUE' then
needrecordReplay:=true
else
needrecordReplay:=false;
finally
strlist.Free;
end;
except
showmessage('配置文件存在错误');
exit;
end;
end;
if serverDisplayIP='' then
HostToIP(serverURL,serverDisplayIP);
Idtcpserver1.DefaultPort:=serverPort;
IdHTTPServer1.DefaultPort:=serverHTTPPort;
Idtcpserver1.Active:=true;
IdHTTPServer1.Active:=true;
refui;
memo1.Lines.Add('对战服务启动于:'+inttostr(serverport));
memo1.Lines.Add('WEB服务启动于:'+inttostr(serverHTTPport));
memo1.Lines.Add('队标等信息在配置文件:server.conf修改相应配置');
memo1.Lines.Add('第一个用户注册后场地|公会服务生效');
memo1.Lines.Add('注册页面模板为:regist.html,请另找空间安置');
memo1.Lines.Add('修改其中的: var serverurl=''http://127.0.0.1:7922/''为本队服务器对应的HTTP服务');
memo1.Lines.add('其他配置请先详细阅读帮助文档,有任何不清楚的地方请GOOGLE,不解释');
end;
procedure TForm1.IdTCPServer1Connect(AContext: TIdContext);
begin
tuserinfo(acontext).connected:=false;
if sys_LOCKroom.LockCount>4 then
begin
tuserinfo(acontext).postandexit('服务器正忙,请稍后重连');
exit;
end;
tuserinfo(acontext).connected:=true;
if not isSTART then
begin
tuserinfo(acontext).postandexit('服务器暂停建房');
sleep(3000);
tuserinfo(acontext).Connection.Disconnect;
exit;
end;
if HASH_ROOM.Count>maxuser then
begin
tuserinfo(acontext).postandexit('服务器超负');
exit;
end;
tuserinfo(acontext).Connection.Socket.ReadTimeout:=1800000;
tuserinfo(acontext).Connection.Socket.UseNagle:=false;
end;
procedure TForm1.IdTCPServer1Disconnect(AContext: TIdContext);
var i:integer;
f:TFormatSettings;
begin
if not tuserinfo(acontext).connected then exit;
tuserinfo(AContext).connected:=false;
tuserinfo(AContext).isbaned:=true;
EnterCriticalSection(sys_LOCKroom);
try
if assigned(tuserinfo(Acontext).room) then
if tuserinfo(AContext).room<>nil then //删除房间的用户列表中对应的用户信息
begin
if tuserinfo(AContext).room.userlist<>nil then
begin
//删除房间的本用户信息
tuserinfo(AContext).room.userlist.Remove(Acontext);
tuserinfo(AContext).room.userlist.pack;
end;
if tuserinfo(acontext).room.creator = acontext then //房间的创建者,则释放所有的房间资源
begin
//杀掉进程
TerminateProcess(tuserinfo(AContext).room.roomprocess.hProcess,0);
//总表中移除本房间
HASH_ROOM.Remove(tuserinfo(AContext).room);
HASH_ROOM.Pack;
//释放ROOM资源
for i:=0 to tuserinfo(AContext).room.userlist.Count-1 do
begin//所有用户房间置空
if tuserinfo(tuserinfo(AContext).room.userlist[i]).Connection.Connected then
tuserinfo(tuserinfo(AContext).room.userlist[i]).Connection.Disconnect;
tuserinfo(tuserinfo(AContext).room.userlist[i]).room:=nil;
end;
//删除临时replay
if tuserinfo(AContext).room.duelstart then
if not tuserinfo(AContext).room.recorded then
if DirectoryExists(ExtractFilePath(ParamStr(0))+'replay_error\') then
if fileexists(ExtractFilePath(ParamStr(0))+'replay\'+inttostr(tuserinfo(AContext).room.roomport)+'Replay.yrp') then
begin
f.ShortDateFormat:='yyyy-MM-dd';
f.LongTimeFormat:='hh-mm-ss-ZZZ';
copyfile(pchar(ExtractFilePath(ParamStr(0))+'replay\'+inttostr(tuserinfo(AContext).room.roomport)+'Replay.yrp'),
pchar(ExtractFilePath(ParamStr(0))+'replay_error\'+datetimetostr(now(),f)+'='
+tuserinfo(AContext).room.player1+'='+tuserinfo(AContext).room.player2
+'='+booltostr(tuserinfo(AContext).room.player1reg)+'='+booltostr(tuserinfo(AContext).room.player2reg)
+'='+inttostr(tuserinfo(AContext).room.winner)+'='+inttostr(tuserinfo(AContext).room.wincause)+'.yrp'),false);
end;
if fileexists(ExtractFilePath(ParamStr(0))+'replay\'+inttostr(tuserinfo(AContext).room.roomport)+'Replay.yrp') then
deletefile(ExtractFilePath(ParamStr(0))+'replay\'+inttostr(tuserinfo(AContext).room.roomport)+'Replay.yrp');
//释放用户列表
freeandnil(tuserinfo(AContext).room.userlist);
//释放本房间
freeandnil(tuserinfo(AContext).room);
end;
end;
finally
leaveCriticalSection(sys_LOCKroom);
end;
end;
procedure TForm1.IdTCPServer1Exception(AContext: TIdContext;
AException: Exception);
begin
//memo1.Lines.Add(datetimetostr(now())+tuserinfo(AContext).username+'error diss:'+AException.Message);
AContext.Connection.Disconnect;
end;
procedure TForm1.IdHTTPServer1CommandGet(AContext: TIdContext;
ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var i,j,hiddennum:integer;
transcode:boolean;
begin
hiddennum:=0;//需要隐藏的房间号
//解析
AResponseInfo.ContentType:='text/html';
if ARequestInfo.Params.Values['operation']='passcheck' then
begin
if g_userlist.Values[utf8toansi(ARequestInfo.Params.Values['username'])]=EncryptString(ARequestInfo.Params.Values['pass']) then
AResponseInfo.ContentText:='true'
else
AResponseInfo.ContentText:='false';
exit;
end;
if (ARequestInfo.Params.Values['operation']='getroomjson') or (ARequestInfo.Params.Values['operation']='getroomjsondelphi') then
begin
if ARequestInfo.Params.Values['operation']='getroomjsondelphi' then
transcode:=true;
if (SecondsBetween(now,lastjsonget)<2) and needcache then
begin
if transcode then
AResponseInfo.ContentText:=lastjsongetstring
else
AResponseInfo.ContentText:=lastjsongetstring_delphi;
exit;
end;
if tryEnterCriticalSection(sys_LOCKroom) then
begin
try
AResponseInfo.ContentText:='{"rooms":[';
for i:= hash_room.Count-1 downto 0 do
begin
//是否显示房间的处理
if troom(HASH_room[I]).roomport=hiddennum then troom(HASH_room[I]).isshow:=false;
if not troom(HASH_room[I]).isshow then continue;
if i<hash_room.Count-1 then AResponseInfo.ContentText:=AResponseInfo.ContentText+',';
AResponseInfo.ContentText:=AResponseInfo.ContentText+'{"roomid":"'+inttostr(troom(HASH_room[I]).roomport)
+'","roomname":"'+Str_Gb2UniCode(troom(HASH_room[I]).roomname_json,transcode)+'"';
if troom(HASH_room[I]).isprivate then
AResponseInfo.ContentText:=AResponseInfo.ContentText+',"needpass":"true"'
else
AResponseInfo.ContentText:=AResponseInfo.ContentText+',"needpass":"false"';
AResponseInfo.ContentText:=AResponseInfo.ContentText+',"users":[';
for j:=0 to troom(HASH_room[I]).userlist.Count-1 do
begin
if j>0 then AResponseInfo.ContentText:=AResponseInfo.ContentText+',';
AResponseInfo.ContentText:=AResponseInfo.ContentText+'{"id":"'+booltostr(tuserinfo(troom(HASH_room[I]).userlist[j]).isUserInList);
AResponseInfo.ContentText:=AResponseInfo.ContentText+'","name":"'+Str_Gb2UniCode(tuserinfo(troom(HASH_room[I]).userlist[j]).username,transcode);
AResponseInfo.ContentText:=AResponseInfo.ContentText+'","pos":"'+inttostr(tuserinfo(troom(HASH_room[I]).userlist[j]).pos)+'"}';
end;
AResponseInfo.ContentText:=AResponseInfo.ContentText+']';
if troom(HASH_room[I]).duelstart then
AResponseInfo.ContentText:=AResponseInfo.ContentText+',"istart":"start"}'
else
AResponseInfo.ContentText:=AResponseInfo.ContentText+',"istart":"wait"}';
end;
AResponseInfo.ContentText:=AResponseInfo.ContentText+']}';
if transcode then
lastjsongetstring:=AResponseInfo.ContentText
else
lastjsongetstring_delphi:=AResponseInfo.ContentText;
lastjsonget:=now();
// AResponseInfo.ContentText:=UnicodeEncode(AResponseInfo.ContentText,CP_OEMCP);
finally
leaveCriticalSection(sys_LOCKroom);
end;
end
else
AResponseInfo.ContentText:='[server busy]';
exit;
end;
//管理段
if ARequestInfo.Params.Values['pass']=managepass then
begin
if ARequestInfo.Params.Values['operation']='close' then
begin
isSTART:=false;
AResponseInfo.ContentText:='服务器建房关闭';
exit;
end;
if ARequestInfo.Params.Values['operation']='forceuserpass' then
begin
ARequestInfo.Params.Values['username']:=replaceName(ARequestInfo.Params.Values['username']);
g_userlist.Values[utf8toansi(ARequestInfo.Params.Values['username'])]:=EncryptString(ARequestInfo.Params.Values['password']);
caption:=g_userlist.Values[utf8toansi(ARequestInfo.Params.Values['username'])];
AResponseInfo.ContentText:='ok';
exit;
end;
if ARequestInfo.Params.Values['operation']='serverpost' then
begin
serverpost:=utf8toansi(ARequestInfo.Params.Values['serverpost']);
end;
if ARequestInfo.Params.Values['operation']='start' then
begin
isSTART:=true;
AResponseInfo.ContentText:='服务器建房开启';
exit;
end;
if ARequestInfo.Params.Values['operation']='maskroom' then
begin
maskRoom:=true;
AResponseInfo.ContentText:='命名管制开启';
exit;
end;
if ARequestInfo.Params.Values['operation']='unmuskroom' then
begin
maskRoom:=false;
AResponseInfo.ContentText:='命名管制关闭';
exit;
end;
if ARequestInfo.Params.Values['operation']='reloaduser' then
begin
g_userlist.Clear;
if fileexists(exepath+'userlist.conf') then
g_userlist.LoadFromFile(exepath+'userlist.conf');
AResponseInfo.ContentText:='用户重载完成';
exit;
end;
if ARequestInfo.Params.Values['operation']='saveuser' then
begin
if iskeepversion then exit;
g_userlist.SaveToFile(exepath+'userlist.conf');
AResponseInfo.ContentText:='用户保存完成';
exit;
end;
if ARequestInfo.Params.Values['operation']='openreg' then
begin
if iskeepversion then exit;
canregist:=true;
AResponseInfo.ContentText:='服务器注册开启';
exit;
end;
if ARequestInfo.Params.Values['operation']='arenastart' then
begin
if iskeepversion then exit;
isarena:=true;
AResponseInfo.ContentText:='场地|竞技场效果发动';
exit;
end;
if ARequestInfo.Params.Values['operation']='arenastop' then
begin
if iskeepversion then exit;
isarena:=false;
AResponseInfo.ContentText:='场地|竞技场效果关闭';
exit;
end;
if ARequestInfo.Params.Values['operation']='closereg' then
begin
if iskeepversion then exit;
canregist:=false;
AResponseInfo.ContentText:='服务器注册关闭';
exit;
end;
if ARequestInfo.Params.Values['operation']='hiddenroom' then
begin
if ARequestInfo.Params.Values['roomid']<>'' then
begin
try
hiddennum:=strtoint(ARequestInfo.Params.Values['roomid']);
except
end;
end;
end;
end;
if ARequestInfo.Params.Values['pass']<>'' then
if ARequestInfo.Params.Values['pass']<>managepass then
begin
AResponseInfo.ContentText:='密码错误';
exit;
end;
//注册段
if ARequestInfo.Params.Values['userregist']<>'' then
begin
if not canregist then
begin
AResponseInfo.ContentText:='用户注册禁止';
exit;
end;
if uppercase(ARequestInfo.Params.Values['userregist'])='NEW' then
begin
if g_userlist.Values[utf8toansi(ARequestInfo.Params.Values['username'])]<>'' then
begin
AResponseInfo.ContentText:='用户已存在';
exit;
end;
if (ARequestInfo.Params.Values['username']<>'') and (ARequestInfo.Params.Values['password']<>'') then
begin
ARequestInfo.Params.Values['username']:=replaceName(ARequestInfo.Params.Values['username']);
g_userlist.Values[utf8toansi(ARequestInfo.Params.Values['username'])]:=EncryptString(ARequestInfo.Params.Values['password']);
AResponseInfo.ContentText:=ARequestInfo.Params.Values['username']+'注册成功';
g_userlist.SaveToFile(exepath+'userlist.conf');
exit;
end
else
begin
AResponseInfo.ContentText:='注册失败';
exit;
end;
end;
if uppercase(ARequestInfo.Params.Values['userregist'])='CHANGEPASS' then
begin
if g_userlist.Values[utf8toansi(ARequestInfo.Params.Values['username'])]<>EncryptString(ARequestInfo.Params.Values['oldpass']) then
begin
AResponseInfo.ContentText:='用户名密码不匹配';
exit;
end
else
begin
g_userlist.Values[utf8toansi(ARequestInfo.Params.Values['username'])]:=EncryptString(ARequestInfo.Params.Values['password']);
AResponseInfo.ContentText:='修改成功';
exit;
end;
end;
end;
if ARequestInfo.Params.Values['adv']<>'' then
begin
AResponseInfo.ContentText:='<head>'+#10#13
+'<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />'+#10#13
+'<meta name ="keywords" content="游戏王,自动化对战,服务器,公会对战平台,游戏,卡牌游戏,卡组分析"> '+#10#13
+'<title>DUEL SERVER</title>'+#10#13
+'</head>'+#10#13;
AResponseInfo.ContentText:=AResponseInfo.ContentText+'<div style="width:468px;position:absolute; left:0px; top:0px; height:100px;">'+#10#13;
AResponseInfo.ContentText:=AResponseInfo.ContentText+'<script type="text/javascript"><!--'+#10#13
+'google_ad_client = "ca-pub-9520543693264555";'+#10#13
+'/* YGOad */'+#10#13
+'google_ad_slot = "2745459735";'+#10#13
+'google_ad_width = 468;'+#10#13
+'google_ad_height = 60;'+#10#13
+'//-->'+#10#13
+'</script>'+#10#13
+'<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js">'+#10#13
+'</script></div>'+#10#13;
exit;
end;
if (SecondsBetween(now,lasthttpget)<2) and needcache then
begin
AResponseInfo.ContentText:=lasthttpgetstring;
exit;
end;
//服务器状态显示
if tryEnterCriticalSection(sys_LOCKroom) then
begin
try
AResponseInfo.ContentText:='<head>'+#10#13
+'<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />'+#10#13
+'<meta name ="keywords" content="游戏王,自动化对战,服务器,公会对战平台,游戏,卡牌游戏,卡组分析"> '+#10#13
+'<title>DUEL SERVER</title>'+#10#13
+'</head>'+#10#13;
AResponseInfo.ContentText:=AResponseInfo.ContentText+'<div align="center"><img src="'+serverLogo+' "></img></div><div style="width:468px;position:absolute; right:10px; top:137px; height:100px;">'+#10#13;
AResponseInfo.ContentText:=AResponseInfo.ContentText+'<script type="text/javascript"><!--'+#10#13
+'google_ad_client = "ca-pub-9520543693264555";'+#10#13
+'/* YGOad */'+#10#13
+'google_ad_slot = "2745459735";'+#10#13
+'google_ad_width = 468;'+#10#13
+'google_ad_height = 60;'+#10#13
+'//-->'+#10#13
+'</script>'+#10#13
+'<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js">'+#10#13
+'</script></div>'+#10#13;
AResponseInfo.ContentText:=AResponseInfo.ContentText+'<br/>当前房间数量:'+inttostr(HASH_ROOM.Count)+'/'+inttostr(maxuser)+' 服务器地址:'+serverDisplayIP;
if needrecordReplay then
AResponseInfo.ContentText:=AResponseInfo.ContentText+' <a href="'+historyPublicURL+'" target="_blank" style="color:red">历史对战记录</a>';
if maskRoom then
AResponseInfo.ContentText:=AResponseInfo.ContentText+' <div style="color:red" title="命名管制模式下只显示房间和用户ID的前5位">命名管制模式</div>';
if g_userlist.Count>0 then
AResponseInfo.ContentText:=AResponseInfo.ContentText+' <div style="color:green; float:left" title="叠放场地|公会服务:只允许通过实名认证的用户建立房间,允许和叠放场地|竞技场一起发动">[叠放场地|公会服务]</div>';
if isarena then
AResponseInfo.ContentText:=AResponseInfo.ContentText+' <div style="color:red; float:left" title="叠放场地|竞技场:本模式下M#房间不允许录像,允许和叠放场地|公会服务一起发动">[叠放场地|竞技场]</div>';
AResponseInfo.ContentText:=AResponseInfo.ContentText+'<br/>';
if serverpost<>'' then
AResponseInfo.ContentText:=AResponseInfo.ContentText+'<div style="color:red" >公告:'+serverpost+'</div>';
if isSTART then
AResponseInfo.ContentText:=AResponseInfo.ContentText+'服务器状态:启动'
else
AResponseInfo.ContentText:=AResponseInfo.ContentText+'服务器状态:关闭';
AResponseInfo.ContentText:=AResponseInfo.ContentText+'</br>';
AResponseInfo.ContentText:=AResponseInfo.ContentText+'<hr/>';
for i:= hash_room.Count-1 downto 0 do
begin
//是否显示房间的处理
if troom(HASH_room[I]).roomport=hiddennum then troom(HASH_room[I]).isshow:=false;
if not troom(HASH_room[I]).isshow then continue;
if troom(HASH_room[I]).duelstart then
AResponseInfo.ContentText:=AResponseInfo.ContentText+'<div style="width:300px; height:150px; border:1px #ececec solid; float:left;padding:5px; margin:5px;">房间名称:'+troom(HASH_room[I]).roomname_html+' <font color=red>决斗已开始!</font>'
else
AResponseInfo.ContentText:=AResponseInfo.ContentText+'<div style="width:300px; height:150px; border:1px #ececec solid; float:left;padding:5px; margin:5px;">房间名称:'+troom(HASH_room[I]).roomname_html+' <font color=blue>等待</font>';
AResponseInfo.ContentText:=AResponseInfo.ContentText+'<font size="1">(ID:'+inttostr(troom(HASH_room[I]).roomport)+')</font>';
if assigned(troom(HASH_room[I]).userlist) then
for j:=0 to troom(HASH_room[I]).userlist.Count -1 do