DELPHI版传奇引擎学习菜鸟篇(applem2)-03

3.2 Gmain.pas单元

这是引擎控制台的主窗口,就是之前说的那个4500行代码的单元,对大神来说,这不算什么,对我看来说,光是理清里边的关系就很吃力.我知道也许从程序的架构角度去理解会好一些,但咱不懂那些,只好继续以一个菜鸟的方式按单元\按页面逐项查看,期待能获得一些营养.

接口部分也有近500行代码,虽然我是初学delphi,但也知道把所有的功能和定义都放到一个单元对以后维护带来很大不变,这份代码是谁写的我不清楚,但是至少不像比较标准的架构,除了重复的复制代码,就是一些嵌套的过程中的过程和函数函数,这恰是我所需要的,让我明白了如何去架构一个良好的可维护的程序,以及很容易让别人读懂的程序,突然我想到了程序设计中面条式的复杂结构,至少能让我知道怎么去避免写一些不容易看懂的代码.

主单元的界面如下:

可以看出来这么多的界面集成到一个单元是多么的不容易,我觉得可以把界面封装到几个或几组dll里边,界面只实现与VCL状态有关的代码,应该好维护一点,500行声明有400行是界面的控件声明和过程声明,仔细过一遍发现很多过程实现都在窗体控件的方法里边,重用的可能性几乎为零.也许是早期代码的原因,但是有一点我不明白,delphi是很好的面向对象设计的IDE,怎么前辈们就没有想到或利用呢?开始怀疑这个源代码也许是高手写的初级版本,毕竟较成熟的版本很少拿来开源.

窗口自身的单元不用介绍,看界面就知道是干什么的,其定义的其他方法如下:

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较多,尤其是进程的通讯和消息处理,一个函数需要反复调试多遍我才能理解出一点东西,其中的穿插调用也很频繁,自己先将之前的复习一遍,为后边的学习做准备.

时间: 2024-11-17 23:56:52

DELPHI版传奇引擎学习菜鸟篇(applem2)-03的相关文章

DELPHI版传奇引擎学习菜鸟篇(applem2)

一点废话:因为非工科出身,又对编程有点兴趣,杂乱的学习了好多(C,C++,PYTHON…)等好多语言,最后发现DEKLPI上手比较快,对于不知道线代和高数等是什么的我来说也许是较好的选择了,毕竟只是兴趣而已,对于DELPHI的资料不是没有,就是觉得没有自己可以渐进入门的.因为以前玩过一个叫传奇的游戏,所以知道最早的传奇是DELPHI开发的,感觉还好,这就找了不少服务端学习(呵呵,研究说不上,因为咱没到那层次),自己动手架设修改,有时还提供给网友玩公益.然后就找传奇的DELPHI源码,不算很多,毕

DELPHI版传奇引擎学习菜鸟篇(applem2)-05

1-4是大概把GAMECENTER过了一遍,终于把消息机制入了一点门,接下来是服务端第一个服务的学习--DBServer.是一个数据库服务器,在学习这个单元的时候,发现了这个端的大概由来,不知道是哪个大牛反编译后重写的,看来之前我理解的是错误的,代码杂乱的原因不是没有考虑到正题设计,这是由DEDEDARK反编译的端,根据自己的经验补写的实现代码,不知道我这辈子能不能达到这样的水平,那得需要对汇编多熟悉才行啊. function TFrmNewChr.sub_49BD60(var sChrName

DELPHI版传奇引擎学习菜鸟篇(applem2)-06

引擎源代码的学习暂时放下了几天,因为需要掌握一些进程处理方面的消息,之前在GAMECENTER中的启动服务过程好好琢磨了一下,将服务启动过程单独拿出来,原先是用主界面的过程判断处理启动,好长的代码,终于提炼出来了一个通用启动过程,停止服务的过程和这个是类似的. {运行外部程序的函数} function RunProgram(var ProgramInfo: TProgram; sHandle: string; dwWaitTime: LongWord): LongWord; var Startu

DELPHI版传奇引擎学习菜鸟篇(applem2)-04

接着学习,从学习的过程中,我发现了这个引擎控制台的主要功能,这也是一行一行代码敲进去的结果,之前我对这个单元的功能了解的还是少,不知不觉中就发现了它主要实现的功能,对里边的代码理解也进了一步. 从我的理解它大概有如下功能: a.实现整个服务端的启动配置. b.进行数据更新,这里指的是对数据库(人物\物品\怪物…)的更新. c.服务端初始化(清理数据和M2的变量复位) d.启动所有服务并监控其运行状态. e.备份数据. 除了d,其他的都还容易理解,基本上拖拉控件写上事件就可以完成,唯独对服务进程进

DELPHI版传奇引擎学习菜鸟篇(applem2)-02

每天只学习一个知识点,也是一种进步. 接着学习GShare.pas的实现部分,其实这个应该叫做GAMECENTER共享单元,我刚开始理解的是错误的,这是根据名字起的. 在学习实现部分之前,声明部分还有一些变量: //虽然光看这些变量不可能全部知道带表什么,但是为了学习,还是注释一下 var //下面4个应该是更新数据(格式)用的,默认为本机更新 g_sDataListAddrs: string = '127.0.0.1'; g_wDataListPort: Word = 18888; g_sDa

Xshell学习--菜鸟篇

1)关于Xshell 网上更多的资料里提到的SSH客户端是putty,因为简单.开源.免费.但是也正是由于功能过于简单,所以在这里推荐大家使用Xshell. Xshell最初并不能免费使用,而且也没有带中文语言,所以导致用户非常少,但是现在已经可以免费安装并且能设置中文,相信使用的人会越来越多. 简单说下个人认为Xshell的优点: 1,界面设计简洁,很人性化,用起来让人觉得很舒服. 2,支持标签,打开多个链接的时候很方便. 3,可以保存密码.(至于安全问题,见仁见智吧,个人觉得,如果能拿到保存

Docker虚拟化实战学习——基础篇(转)

Docker虚拟化实战学习--基础篇 2018年05月26日 02:17:24 北纬34度停留 阅读数:773更多 个人分类: Docker Docker虚拟化实战和企业案例演练 深入剖析虚拟化技术概念和应用场景 虚拟化,一是项技术--,是一种资源解决方案. 虚拟化技术是将物理资源转变为逻辑上可以管理的资源,以打破物理结构之间的壁垒,使计算元件运行在虚拟的基础上,而不是真实的物理资源上. 通过虚拟化技术,可以将物理资源转变为逻辑资源(虚拟机),应用程序服务运行在虚拟资源上,而不是真实的物理机上.

如何制作一款HTML5 RPG游戏引擎——第四篇,情景对话

今天我们来实现情景对话.这是一个重要的功能,没有它,游戏将变得索然无味.所以我们不得不来完成它. 但是要知道,使用对话可不是一件简单的事,因为它内部的东西很多,比如说人物头像,人物名称,对话内容... 因此我们只能通过数组+JSON来将对话信息装起来,然后根据信息作出不同的显示.接下来我便要向大家展示实现方法. 先看本系列文章目录: 如何制作一款HTML5 RPG游戏引擎--第一篇,地图类的实现 http://blog.csdn.net/yorhomwang/article/details/88

如何制作一款HTML5 RPG游戏引擎——第五篇,人物&人物特效

上一次,我们实现了对话类,今天就来做一个游戏中必不可少的--人物类. 当然,你完全是可以自己写一个人物类,但是为了方便起见,还是决定把人物类封装到这个引擎里. 为了使这个类更有意义,我还给人物类加了几个特效,在以下讲解中会提到. 以下是本系列文章的目录: 如何制作一款HTML5 RPG游戏引擎--第一篇,地图类的实现 http://blog.csdn.net/yorhomwang/article/details/8892305 如何制作一款HTML5 RPG游戏引擎--第二篇,烟雨+飞雪效果 h