3.2 Gmain.pas單元
這是引擎控制台的主窗口,就是之前說的那個4500行代碼的單元,對大神來說,這不算什麼,對我看來說,光是理清裡邊的關系就很吃力.我知道也許從程序的架構角度去理解會好一些,但咱不懂那些,只好繼續以一個菜鳥的方式按單元\按頁面逐項查看,期待能獲得一些營養.
接口部分也有近500行代碼,雖然我是初學delphi,但也知道把所有的功能和定義都放到一個單元對以後維護帶來很大不變,這份代碼是誰寫的我不清楚,但是至少不像比較標准的架構,除了重復的復制代碼,就是一些嵌套的過程中的過程和函數函數,這恰是我所需要的,讓我明白了如何去架構一個良好的可維護的程序,以及很容易讓別人讀懂的程序,突然我想到了程序設計中面條式的復雜結構,至少能讓我知道怎麼去避免寫一些不容易看懂的代碼.
主單元的界面如下:
private m_boOpen: Boolean; //開關標志 m_nStartStatus: Integer;//啟動狀態標志,在GShare.pas裡邊有類似聲明 m_dwShowTick: LongWord; m_dwRefTick: LongWord; {定義時間變量,用於啟動腳本和備份腳本} m_btHour: Byte; m_btMinute: Byte; m_dwRunTime: LongWord; m_dwRunTick: LongWord; m_boGateStop: Boolean; m_boGateStopTick: LongWord; {上述幾個適用於檢測啟動的服務的,異常或停止的通過設置狀態重新啟動} {下邊是定義的私有過程,其實可以放到另一個單元} procedure RefGameConsole(); //加載配置信息到可視化界面 procedure GenGameConfig(); //寫入游戲設置文件,以下幾個都是 procedure GenDBServerConfig(); procedure GenLoginServerConfig(); procedure GenLogServerConfig(); procedure GenM2ServerConfig(); procedure GenLoginGateConfig(); procedure GenSelGateConfig(); procedure GenRunGateConfig; procedure GenPlugTopConfig(); {啟動\停止服務,這裡是通過設置狀態,然後通過定時器啟動,啟動方法在GShare裡邊} procedure StartGame(); procedure StopGame(); {發送數據信息,還有一個MainOutMessage被我Ppublic了,為了調試用} procedure MainOutDataListMessage(sMsg: string); {發送進程消息,其實就是將服務的啟動狀態發送到引擎控制帶主界面} procedure ProcessDBServerMsg(wIdent: Word; sData: string); procedure ProcessLoginSrvMsg(wIdent: Word; sData: string); procedure ProcessLogServerMsg(wIdent: Word; sData: string); procedure ProcessPlugTopMsg(wIdent: Word; sData: string); procedure ProcessLoginGateMsg(wIdent: Word; sData: string); procedure ProcessSelGateMsg(wIdent: Word; sData: string); procedure ProcessRunGateMsg(wIdent: Word; sData: string); function ProcessM2ServerMsg(wIdent: Word; sData: string): Integer; {加載RunGate網關的設置,因為不是一個,所以猜測Mut應該是多個的意思} procedure GetMutRunGateConfing(nIndex: Integer); function StartService(): Boolean;//這個是啟動游戲控制台 {以下兩個類似GetMutRunGateConfing,都是循環讀取網關狀態} procedure GenMutSelGateConfig(nIndex: Integer); procedure GenMutLoginGateConfig(nIndex: Integer); procedure LoadBackList();//加載備份列表 procedure RefBackListToView();//這個是將備份信息寫到ListView裡邊 {這是通過Socket發送數據,帶MD5校驗} function SendDataListData(wIdent: Word; sData: string): Boolean; function RefDataListItem(): Boolean;//更新數據函數 procedure ClearDataListItem();//清除舊的數據列表 {下邊幾個是讀取地圖數據用的,暫時有點理解困難} function NewDataListInfo(): pTDataListInfo;//初始化新數據列表 procedure DisposeDataListInfo(DataListInfo: pTDataListInfo);//釋放數據列表 function GetNextData(): Boolean; {取得地圖數據信息} function MapGetFileData(sFileName: string; boBackData: Boolean): Integer; { Private declarations } public {處理消息用的兩個過程} procedure ProcessMessage(var Msg: TMsg; var Handled: Boolean); procedure MyMessage(var MsgData: TWmCopyData); message WM_COPYDATA; procedure MainOutMessage(sMsg: string);//這個原先在private裡邊 { Public declarations } end;
實現的部分東西比較多,也比較亂,按順序一個一個學習,RefGameConsole是重新加載所有配置,為引擎啟動做准備.
procedure TfrmMain.RefGameConsole; begin m_boOpen := False; CheckBoxM2Server.Checked := g_Config.M2Server.GetStart; CheckBoxDBServer.Checked := g_Config.DBServer.GetStart; CheckBoxLoginServer.Checked := g_Config.LoginSrv.GetStart; CheckBoxLogServer.Checked := g_Config.LogServer.GetStart; CheckBoxLoginGate.Checked := g_Config.LoginGate.GetStart; CheckBoxSelGate.Checked := g_Config.SelGate.GetStart1; CheckBoxSelGate1.Checked := g_Config.SelGate.GetStart2; CheckBoxRunGate.Checked := g_Config.RunGate.GetStart[0]; CheckBoxRunGate1.Checked := g_Config.RunGate.GetStart[1]; CheckBoxRunGate2.Checked := g_Config.RunGate.GetStart[2]; CheckBoxRunGate3.Checked := g_Config.RunGate.GetStart[3]; CheckBoxRunGate4.Checked := g_Config.RunGate.GetStart[4]; CheckBoxRunGate5.Checked := g_Config.RunGate.GetStart[5]; CheckBoxRunGate6.Checked := g_Config.RunGate.GetStart[6]; CheckBoxRunGate7.Checked := g_Config.RunGate.GetStart[7]; EditGameDir.Text := g_sGameDirectory; EditHeroDB.Text := g_sHeroDBName; EditGameName.Text := g_sGameName; EditGameExtIPaddr.Text := g_sExtIPaddr; EditGameExtIPAddr2.Text := g_sExtIPAddr2; CheckBoxIP2.Checked := g_boIP2; CheckBoxCloseWuXin.Checked := g_boCloseWuXin; EditDBServer_MainFormX.Value := g_Config.DBServer.MainFormX; EditDBServer_MainFormY.Value := g_Config.DBServer.MainFormY; EditDBServerGatePort.Text := IntToStr(g_Config.DBServer.GatePort); EditDBServerServerPort.Text := IntToStr(g_Config.DBServer.ServerPort); CheckBoxDBServerGetStart.Checked := g_Config.DBServer.GetStart; EditLoginServer_MainFormX.Value := g_Config.LoginSrv.MainFormX; EditLoginServer_MainFormY.Value := g_Config.LoginSrv.MainFormY; EditLoginServerGatePort.Text := IntToStr(g_Config.LoginSrv.GatePort); EditLoginServerServerPort.Text := IntToStr(g_Config.LoginSrv.ServerPort); EditLoginServerMonPort.Text := IntToStr(g_Config.LoginSrv.MonPort); CheckBoxboLoginServer_GetStart.Checked := g_Config.LoginSrv.GetStart; EditM2Server_MainFormX.Value := g_Config.M2Server.MainFormX; EditM2Server_MainFormY.Value := g_Config.M2Server.MainFormY; EditM2ServerGatePort.Text := IntToStr(g_Config.M2Server.GatePort); EditM2ServerMsgSrvPort.Text := IntToStr(g_Config.M2Server.MsgSrvPort); CheckBoxM2ServerGetStart.Checked := g_Config.M2Server.GetStart; EditLogServer_MainFormX.Value := g_Config.LogServer.MainFormX; EditLogServer_MainFormY.Value := g_Config.LogServer.MainFormY; EditLogServerPort.Text := IntToStr(g_Config.LogServer.Port); CheckBoxLogServerGetStart.Checked := g_Config.LogServer.GetStart; CheckBoxboRunGate_GetStart1.Checked := g_Config.RunGate.GetStart[0]; CheckBoxboRunGate_GetStart2.Checked := g_Config.RunGate.GetStart[1]; CheckBoxboRunGate_GetStart3.Checked := g_Config.RunGate.GetStart[2]; CheckBoxboRunGate_GetStart4.Checked := g_Config.RunGate.GetStart[3]; CheckBoxboRunGate_GetStart5.Checked := g_Config.RunGate.GetStart[4]; CheckBoxboRunGate_GetStart6.Checked := g_Config.RunGate.GetStart[5]; CheckBoxboRunGate_GetStart7.Checked := g_Config.RunGate.GetStart[6]; CheckBoxboRunGate_GetStart8.Checked := g_Config.RunGate.GetStart[7]; EditRunGate_MainFormX.Value := g_Config.RunGate.MainFormX; EditRunGate_MainFormY.Value := g_Config.RunGate.MainFormY; EditRunGate_GatePort1.Text := IntToStr(g_Config.RunGate.GatePort[0]); EditRunGate_GatePort2.Text := IntToStr(g_Config.RunGate.GatePort[1]); EditRunGate_GatePort3.Text := IntToStr(g_Config.RunGate.GatePort[2]); EditRunGate_GatePort4.Text := IntToStr(g_Config.RunGate.GatePort[3]); EditRunGate_GatePort5.Text := IntToStr(g_Config.RunGate.GatePort[4]); EditRunGate_GatePort6.Text := IntToStr(g_Config.RunGate.GatePort[5]); EditRunGate_GatePort7.Text := IntToStr(g_Config.RunGate.GatePort[6]); EditRunGate_GatePort8.Text := IntToStr(g_Config.RunGate.GatePort[7]); EditSelGate_MainFormX.Value := g_Config.SelGate.MainFormX; EditSelGate_MainFormY.Value := g_Config.SelGate.MainFormY; CheckBoxboSelGate_GetStart.Checked := g_Config.SelGate.GetStart1; CheckBoxboSelGate_GetStart2.Checked := g_Config.SelGate.GetStart2; EditSelGate_GatePort.Text := IntToStr(g_Config.SelGate.GatePort[0]); EditSelGate_GatePort1.Text := IntToStr(g_Config.SelGate.GatePort[1]); EditLoginGate_MainFormX.Value := g_Config.LoginGate.MainFormX; EditLoginGate_MainFormY.Value := g_Config.LoginGate.MainFormY; CheckBoxboLoginGate_GetStart.Checked := g_Config.LoginGate.GetStart; EditLoginGate_GatePort.Text := IntToStr(g_Config.LoginGate.GatePort); CheckBoxPlugTopGetStart.Checked :=g_Config.PlugTop.GetStart; CheckBoxPlugTop.Checked:=g_Config.PlugTop.GetStart; EditPlugTop_MainFormX.Value:=g_Config.PlugTop.MainFormX; EditPlugTop_MainFormY.Value:=g_Config.PlugTop.MainFormY; m_boOpen := True; end;
看著上邊好多類似的取值方式,讓我想到了繼承,可惜之前定義的都是結構,不然可以優化多,這個函數倒不用多做說明,太通俗易懂了.
下邊幾個過程是將設置寫入服務配置文件,都是類似的,也不用多想就可以看懂,一共9個,第一個是調用其他8個的過程,就是主界面上保存設置按鈕的事件.
procedure TfrmMain.GenGameConfig; begin GenDBServerConfig(); GenLoginServerConfig(); GenM2ServerConfig(); GenLogServerConfig(); GenRunGateConfig(); GenSelGateConfig(); GenLoginGateConfig(); GenPlugTopConfig(); end; procedure TfrmMain.GenDBServerConfig; var sIniFile: string; SaveList: TStringList; I: Integer; begin IfNoDirThenCreate(g_sGameDirectory + 'DBServer\'); IfNoDirThenCreate(g_sGameDirectory + 'DBServer\DB\'); WriteIniValue('Dbsrc.ini',DBSERVERSECTIONNAME2,'ServerName',g_sGameName); WriteIniValue('Dbsrc.ini',DBSERVERSECTIONNAME2, 'ServerAddr', sLocalIPaddr); WriteIniValue('Dbsrc.ini',DBSERVERSECTIONNAME2, 'ServerPort', g_Config.DBServer.ServerPort); WriteIniValue('Dbsrc.ini',DBSERVERSECTIONNAME2, 'GateAddr', sAllIPaddr); WriteIniValue('Dbsrc.ini',DBSERVERSECTIONNAME2, 'GatePort', g_Config.DBServer.GatePort); WriteIniValue('Dbsrc.ini',DBSERVERSECTIONNAME2, 'IDSAddr', sLocalIPaddr); WriteIniValue('Dbsrc.ini',DBSERVERSECTIONNAME2, 'IDSPort', g_Config.LoginSrv.ServerPort); WriteIniValue('Dbsrc.ini',DBSERVERSECTIONNAME2, 'DBName', g_sHeroDBName); WriteIniValue('Dbsrc.ini',DBSERVERSECTIONNAME2, 'DBDir', '.\DB\'); SaveList := TStringList.Create; SaveList.Add(sLocalIPaddr); if g_boIP2 then SaveList.Add(sLocalIPaddr2); SaveList.SaveToFile(sIniFile + '!addrtable.txt'); SaveList.Clear; sIniFile := sLocalIPaddr; for I := Low(g_Config.RunGate.GetStart) to High(g_Config.RunGate.GetStart) do begin if g_Config.RunGate.GetStart[I] then sIniFile := sIniFile + Format(' %s %d', [g_sExtIPaddr, g_Config.RunGate.GatePort[I]]); end; SaveList.Add(sIniFile); if g_boIP2 then begin sIniFile := sLocalIPaddr2; for I := Low(g_Config.RunGate.GetStart) to High(g_Config.RunGate.GetStart) do begin if g_Config.RunGate.GetStart[I] then sIniFile := sIniFile + Format(' %s %d', [g_sExtIPaddr2, g_Config.RunGate.GatePort[I]]); end; SaveList.Add(sIniFile); end; SaveList.SaveToFile(g_sGameDirectory + 'DBServer\!serverinfo.txt'); SaveList.Free; if not FileExists(g_sGameDirectory + 'DBServer\FUserName.txt') then begin SaveList := TStringList.Create; SaveList.Add(';創建人物過濾字符,一行一個過濾'); SaveList.SaveToFile(g_sGameDirectory + 'DBServer\FUserName.txt'); SaveList.Free; end; end;
啟動和停止服務的過程也不是太復雜,不過我看著怎麼就那麼"復雜",等待都過完一遍後要從頭重新寫一遍.
procedure TfrmMain.StartGame; var I: Integer; begin m_dwRunTick := GetTickCount; //返回系統啟動經歷的毫秒數 FillChar(DBServer, SizeOf(TProgram), #0); //用指定的值填充連續的字節為進程啟動做准備 //讀取服務啟動前的初始化狀態,以下類似 DBServer.boGetStart := g_Config.DBServer.GetStart; DBServer.boReStart := True; DBServer.sDirectory := g_sGameDirectory + 'DBServer\'; DBServer.sProgramFile := g_Config.DBServer.ProgramFile; DBServer.nMainFormX := g_Config.DBServer.MainFormX; DBServer.nMainFormY := g_Config.DBServer.MainFormY; FillChar(LoginServer, SizeOf(TProgram), #0); LoginServer.boGetStart := g_Config.LoginSrv.GetStart; LoginServer.boReStart := True; LoginServer.sDirectory := g_sGameDirectory + 'LoginSrv\'; LoginServer.sProgramFile := g_Config.LoginSrv.ProgramFile; LoginServer.nMainFormX := g_Config.LoginSrv.MainFormX; LoginServer.nMainFormY := g_Config.LoginSrv.MainFormY; FillChar(LogServer, SizeOf(TProgram), #0); LogServer.boGetStart := g_Config.LogServer.GetStart; LogServer.boReStart := True; LogServer.sDirectory := g_sGameDirectory + 'LogServer\'; LogServer.sProgramFile := g_Config.LogServer.ProgramFile; LogServer.nMainFormX := g_Config.LogServer.MainFormX; LogServer.nMainFormY := g_Config.LogServer.MainFormY; FillChar(M2Server, SizeOf(TProgram), #0); M2Server.boGetStart := g_Config.M2Server.GetStart; M2Server.boReStart := True; M2Server.sDirectory := g_sGameDirectory + 'Mir200\'; M2Server.sProgramFile := g_Config.M2Server.ProgramFile; M2Server.nMainFormX := g_Config.M2Server.MainFormX; M2Server.nMainFormY := g_Config.M2Server.MainFormY; //RunGate可以啟動8個進程,所以用循環讀取 FillChar(RunGate, SizeOf(RunGate), #0); for I := Low(RunGate) to High(RunGate) do begin RunGate[I].btStartStatus := 0; RunGate[I].boGetStart := g_Config.RunGate.GetStart[I]; RunGate[I].boReStart := True; RunGate[I].sDirectory := g_sGameDirectory + 'RunGate\'; RunGate[I].sProgramFile := g_Config.RunGate.ProgramFile; if ((I + 1) mod 2) = 0 then RunGate[I].nMainFormX := g_Config.RunGate.MainFormX + 276 else RunGate[I].nMainFormX := g_Config.RunGate.MainFormX; if I in [2, 3, 6, 7] then RunGate[I].nMainFormY := g_Config.RunGate.MainFormY + 187 else RunGate[I].nMainFormY := g_Config.RunGate.MainFormY; //187 end; FillChar(SelGate, SizeOf(TProgram), #0); SelGate.boGetStart := g_Config.SelGate.GetStart1; SelGate.boReStart := True; SelGate.sDirectory := g_sGameDirectory + 'SelGate\'; SelGate.sProgramFile := g_Config.SelGate.ProgramFile; SelGate.nMainFormX := g_Config.SelGate.MainFormX; SelGate.nMainFormY := g_Config.SelGate.MainFormY; FillChar(SelGate1, SizeOf(TProgram), #0); SelGate1.boGetStart := g_Config.SelGate.GetStart2; SelGate1.boReStart := True; SelGate1.sDirectory := g_sGameDirectory + 'SelGate\'; SelGate1.sProgramFile := g_Config.SelGate.ProgramFile; SelGate1.nMainFormX := g_Config.SelGate.MainFormX; SelGate1.nMainFormY := g_Config.SelGate.MainFormY; FillChar(LoginGate, SizeOf(TProgram), #0); LoginGate.boGetStart := g_Config.LoginGate.GetStart; LoginGate.boReStart := True; LoginGate.sDirectory := g_sGameDirectory + 'LoginGate\'; LoginGate.sProgramFile := g_Config.LoginGate.ProgramFile; LoginGate.nMainFormX := g_Config.LoginGate.MainFormX; LoginGate.nMainFormY := g_Config.LoginGate.MainFormY; FillChar(LoginGate2, SizeOf(TProgram), #0); LoginGate2.boGetStart := g_Config.LoginGate.GetStart and g_boIP2; LoginGate2.boReStart := True; LoginGate2.sDirectory := g_sGameDirectory + 'LoginGate\'; LoginGate2.sProgramFile := g_Config.LoginGate.ProgramFile; LoginGate2.nMainFormX := g_Config.LoginGate.MainFormX; LoginGate2.nMainFormY := g_Config.LoginGate.MainFormY; FillChar(PlugTop, SizeOf(TProgram), #0); PlugTop.boGetStart := g_Config.PlugTop.GetStart; PlugTop.boReStart := True; PlugTop.sDirectory := g_sGameDirectory + 'Mir200\'; PlugTop.sProgramFile := g_Config.PlugTop.ProgramFile; PlugTop.nMainFormX := g_Config.PlugTop.MainFormX; PlugTop.nMainFormY := g_Config.PlugTop.MainFormY; CheckDBServer.Checked := DBServer.boGetStart; CheckLoginSrv.Checked := LoginServer.boGetStart; CheckM2Server.Checked := M2Server.boGetStart; CheckLogServer.Checked := LogServer.boGetStart; CheckPlugTop.Checked := PlugTop.boGetStart; CheckLoginGate.Checked := LoginGate.boGetStart; CheckSelGate1.Checked := SelGate.boGetStart; CheckSelGate2.Checked := SelGate1.boGetStart; CheckRunGate1.Checked := RunGate[0].boGetStart; CheckRunGate2.Checked := RunGate[1].boGetStart; CheckRunGate3.Checked := RunGate[2].boGetStart; CheckRunGate4.Checked := RunGate[3].boGetStart; CheckRunGate5.Checked := RunGate[4].boGetStart; CheckRunGate6.Checked := RunGate[5].boGetStart; CheckRunGate7.Checked := RunGate[6].boGetStart; CheckRunGate8.Checked := RunGate[7].boGetStart; ButtonStartGame.Caption := g_sButtonStopStartGame; m_nStartStatus := 1; TimerStartGame.Enabled := True;//調用啟動計時器按順序啟動所有服務 end; procedure TfrmMain.StopGame; begin ButtonStartGame.Caption := g_sButtonStopStopGame; MainOutMessage('正在開始停止服務器...'); TimerCheckRun.Enabled := False; //停止服務監測 TimerStopGame.Enabled := True; //調用停止計時器按啟動的相反順序停止服務 m_boGateStop := False; m_nStartStatus := 3; end;
接下來的學習就涉及到了服務啟動配置文件和啟動設置問題,用到的win API較多,尤其是進程的通訊和消息處理,一個函數需要反復調試多遍我才能理解出一點東西,其中的穿插調用也很頻繁,自己先將之前的復習一遍,為後邊的學習做准備.