DELPHI版传奇引擎学习菜鸟篇(applem2)-01
⼀点废话:因为⾮⼯科出⾝,⼜对编程有点兴趣,杂乱的学习了好多(C,C++,PYTHON…)等好多语⾔,最后发现DELPHI上⼿⽐较快,对于不知道线代和⾼数等是什么的我来说也许是较好的选择了,毕竟只是兴趣⽽已,对于DELPHI的资料不是没有,就是觉得没有⾃⼰可以渐进⼊门的.因为以前玩过⼀个叫传奇的游戏,所以知道最早的传奇是DELPHI开发的,感觉还好,这就了不少服务端学习(呵呵,研究说不上,因为咱没到那层次),⾃⼰动⼿架设修改,有时还提供给⽹友玩公益.然后就传奇的DELPHI源码,不算很多,毕竟现在⼤部分还是⽤C写的,也不会开源给⼤家看,后来听⽹友说APPLEM2引擎不知道因为什么开源了,就到⼀个⽐较全的(当然还是少了很多东西,⽐如三⽅VLC),看着前辈们写的东西,在佩服的同时也觉得⾃⼰对照写⼀遍也许会得到点什么,于是就开始了这个过程,决⼼从头开始把代码都敲⼀遍,尽管时间很长,也有点"盗⽤"(虽说APPLEM2开源了,但是架构模式也还是有知识产权的)嫌疑,呵呵…,不管怎么说,我发现这样学习东西很快,⾄少对我来说是这样的,这样的过程让我知道了什么是记录,什么是类,什么是SOCKET,对于初学的我来说,收获还是颇丰的,当然也发现了早期代码有不少的不妥之处,函数和过程的繁杂让我⼀贯不着北,在试着将⼀些繁杂的代码简化后,突然发现有的函数被我重新写过了,也许这也是⼀种提⾼的⽅式吧,希望我能坚持下去.正题开始.
后续所有内容都是我⾃⼰学习DELPHI过程中对程序设计的⼀点浅显的了解,有的也许会引发前辈门笑喷,但是这恰是我学习的成长过程,也是我提⾼的途径.
1.传奇服务端结构:
⼤部分名字都叫MirServer,基本结构包含⼋个⽂件夹和⼀个GAMECENTER.EXE⽂件和⼀个CONFIG.INI⽂件,以下按照启动顺序说明.
名称说明描述
GAMECENTER控制中⼼引导所有服务端程序启动,早期的端我没看到
DBServer数据库服务器管理⼈物\怪物\物品\魔法数据
LoginSrv登录服务器控制账号登录
LogServer⽇志服务器记录玩家操作⽇志
Mir200游戏主引擎管理游戏庞⼤的脚本和设置
RunGate游戏⽹关呵呵,现在我还不知道什么是⽹关
SelGate⾓⾊⽹关好像进⼊游戏与⾓⾊选择有关吧
LoginGate登录⽹关好像是登录控制和玩家状态检测的
Mud2数据⽂件夹物品\魔法\怪物数据,应该是paradox的
applem2的还有个排⾏榜的,我想⼤部分端应该集成在M2⾥边了吧.
能够看到的就这些,既然从头开始,就先把⽬录硬记下来,虽然后边在"抄写"的过程中会改变⼀些设置.
2.源代码结构
源代码和上述结构⼀样,除了MUD2,每个都对应⼀个⼯程⽂件,⽤了好多插件,准备把不需要的都去掉,把所有的服务端程序集中到⼀个进程⾥边,暂时不考虑性能如何,尽量⽤不带插件的DELPHI完整编译,版本以2007为基准吧.先写完了⼀个GAMECENTER和DBServer,效果如下:
服务端只有⼀个程序,其他服务都集成到⼀个⽗窗⼝中,然后根据主程序设置决定需要启动那些服务,毕竟传奇架设的时候有些服务可能不在⼀个服务器上,虽然是菜鸟,但是咱也得考虑远⼀点,学习前辈们的⼀些先进理念,也是拓展了⾃⼰的学习思路.
3.GAMECENTER
先说说启动中⼼,不说别的,光是主窗⼝4000多⾏的代码就让我眼花缭乱了,这对我来说太难了,有的过程或函数00⾏了,阅读⽐较困难,还是先从⾃⼰的⾓度去理解吧.
GAMECENTER⼯程架构如下(名字都是从⾃⼰理解的⾓度起的):
//本⾝包含的单元
ugamecenter.pas    // 主窗⼝单元
GShare.pas          // 全局常量单元
DataBackUp.pas      // 数据备份单元
//引⽤的单元
DBShare.pas        // 共享数据单元
HUtil32.pas        // ⼈物操作单元
MD5Unit.pas        // 数据校验单元
Common.pas          // 通⽤常量单元
3.1 GShare.pas单元
单元之间的引⽤很复杂,也许是因为早起代码的原因吧,先说说GShare.pas单元,这个单元包含了服务器的配置常量,如⽂件夹名字\服务状态\配置⽂件等全局常量和服务的启动\停⽌函数以及消息处理过程,先记录⼀点⾃⼰能够理解的.
unit GShare;
interface
uses
Windows, Messages, Classes, SysUtils, INIFiles, DataBackUp, ComCtrls;
const
MAXRUNGATECOUNT = 8;  // 最⼤游戏⽹关数量
{以下0-9是每个服务的消息编号常量}
tDBServer = 0;
tLoginSrv = 1;
tLogServer = 2;
tM2Server = 3;
tLoginGate = 4;
tSelGate = 6;
tRunGate = 8;
tPlugTop = 9;
{不⾔⽽喻,这⾥是服务配置INI⽂件的节名称常量}
BasicSectionName = 'GameConfig';
DBServerSectionName = 'DBServer';
LoginSrvSectionName = 'LoginSrv';
M2ServerSectionName = 'M2Server';
LogServerSectionName = 'LogServer';
RunGateSectionName = 'RunGate';
SelGateSectionName = 'SelGate';
LoginGateSectionName = 'LoginGate';
PlugTopSectionName='PlugTop';
{IP设置,APPLEM2⾃带⼀机双IP设置}
sAllIPaddr = '0.0.0.0';
sLocalIPaddr = '127.0.0.1';
sLocalIPaddr2 = '127.0.0.2';
nLimitOnlineUser = 2000;    //服务器最⾼上线⼈数(源码⾃带注释)
{以下是各个服务的配置路径和⽂件常量}
SERVERCONFIGDIR = 'Config\';
SERVERCONFIGFILE = 'Config.ini';
SERVERGAMEDATADIR = 'GameData\';
SERVERLOGDIR = 'Log\';
DBSERVERSECTIONNAME2 = 'DBServer';
DBSERVERDBDIR = 'DB\';
DBSERVERALLOWADDR = '';
DBSERVERGATEINFO = '';
LOGINSRVSECTIONNAME2 = 'LoginSrv';
LOGINSRVCHRLOGNAME = SERVERLOGDIR + 'ChrLog\';
LOGINSRVALLOWADDR = '';
LOGINSRVGETINFO = '';
LOGINSRVUSERLIMIT = '';
M2SERVERCONFIGFILE = '!';
M2SERVERSECTIONNAME1 = 'Server';
M2SERVERSECTIONNAME2 = 'Share';
M2SERVERSEGuildBase = SERVERGAMEDATADIR + 'GuildBase\';
M2SERVERSEGuildDir = M2SERVERSEGuildBase + 'Guilds\';
M2SERVERSEGuildFile = M2SERVERSEGuildBase + '';
M2SERVERSEConLogDir = SERVERLOGDIR + 'M2ConLog\';
M2SERVERSECastleDir = SERVERGAMEDATADIR + 'Castle\';
M2SERVERSECastleFile = SERVERGAMEDATADIR + '';
M2SERVERSELogDir = SERVERLOGDIR + 'M2Log\';
M2SERVERSEEMailDir = SERVERLOGDIR + 'M2Log\';
M2SERVERSEnvirDir = 'Envir\';
M2SERVERSMapDir = 'Map\';
M2SERVERSALLOWADDR = '';
M2SERVERSEmailDir = SERVERGAMEDATADIR + 'EMail\';
LOGSERVERSECTIONNAME2 = 'LogDataServer';
LOGSERVERBaseDir = SERVERGAMEDATADIR + 'GameLog\';
RunGateSectionName2 = 'RunGate';
SelGateSectionName2 = 'SelGate';
LoginGateSectionName2 = 'LoginGate';
PlugTopDIR=SERVERGAMEDATADIR +'\mir200\';
type
{定义每个服务的应⽤程序状态结构指针}
pTProgram = ^TProgram;
TProgram = packed record
boGetStart: Boolean; //DBServer启动标志 (源码⾃带注释)
boReStart: Boolean; //程序异常停⽌,是否重新启动 (源码⾃带注释)
btStartStatus: Byte;//0,1,2,3 未启动,正在启动,已启动,正在关闭 (源码⾃带注释)    sProgramFile: string[50];
sDirectory: string[100];
ProcessInfo: TProcessInformation; //服务的进程信息(进程,线程,进程ID,线程ID)    ProcessHandle: THandle;          //进程句柄
MainFormHandle: THandle;          //主窗⼝句柄,后续改为每个服务对应的活动窗⼝句柄    nMainFormX: Integer;  //服务端启动后窗⼝位置
nMainFormY: Integer;
end;
{应该是加载地图⽂件的结构指针}
pTDataListInfo = ^TDataListInfo;
TDataListInfo = packed record
sFileName: string[255];
MapFileHandle: THandle;
MapFileBuffer: PChar;
DateTime: TDateTime;
Data: PChar;
DataSize: Integer;
Item: TListItem;
end;
{检测服务运⾏状态}
TCheckCode = packed record
dwThread0: LongWord;
sThread0: string;
end;
{下边的⼀堆CONFIG是对应的每个服务状态的结构}
TDBServerConfig = packed record
MainFormX: Integer;
MainFormY: Integer;
GatePort: Integer;
ServerPort: Integer;
GetStart: Boolean;
ProgramFile: string[50];
end;
TLoginSrvConfig = packed record
MainFormX: Integer;
MainFormY: Integer;
GatePort: Integer;
ServerPort: Integer;
MonPort: Integer;
GetStart: Boolean;
ProgramFile: string[50];
end;
TM2ServerConfig = packed record
MainFormX: Integer;
MainFormY: Integer;
GatePort: Integer;
MsgSrvPort: Integer;
GetStart: Boolean;
博客为什么没人用了ProgramFile: string[50];
end;
TLogServerConfig = packed record
MainFormX: Integer;
MainFormY: Integer;
Port: Integer;
GetStart: Boolean;
ProgramFile: string[50];
end;
TPlugTopConfig = packed record
MainFormX: Integer;
MainFormY: Integer;
Port: Integer;
GetStart: Boolean;
ProgramFile: string[50];
end;
TRunGateConfig = packed record
MainFormX: Integer;
MainFormY: Integer;
GetStart: array[0..MAXRUNGATECOUNT - 1] of Boolean;
GatePort: array[0..MAXRUNGATECOUNT - 1] of Integer;
ProgramFile: string[50];
end;
TSelGateConfig = packed record
MainFormX: Integer;
MainFormY: Integer;
GatePort: array[0..1] of Integer;
GetStart1: Boolean;
GetStart2: Boolean;
ProgramFile: string[50];
end;
TLoginGateConfig = packed record
MainFormX: Integer;
MainFormY: Integer;
GatePort: Integer;
GetStart: Boolean;
ProgramFile: string[50];
end;
{将所有的服务状态声明为⼀个结构指针}
pTConfig = ^TConfig;
TConfig = packed record
DBServer: TDBServerConfig;
LoginSrv: TLoginSrvConfig;
M2Server: TM2ServerConfig;
LogServer: TLogServerConfig;
RunGate: TRunGateConfig;
SelGate: TSelGateConfig;
LoginGate: TLoginGateConfig;
PlugTop: TPlugTopConfig;
end;
procedure LoadConfig();  //加载启动设置
procedure SaveConfig();  //保存启动设置
{下边2个是启动和停⽌每个服务的函数}
function RunProgram(var ProgramInfo: TProgram; sHandle: string; dwWaitTime: LongWord): LongWord; function StopProgram(var ProgramInfo: TProgram; dwWaitTime: LongWord): Integer;
{发送每个服务当前状态的消息处理过程}
procedure SendProgramMsg(DesForm: THandle; wIdent: Word; sSendMsg: string);
先将学习过的温习⼀下,然后再将服务器的状态处理连贯做⼀下记录.

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。