CentrED/Server/UConfig.pas

371 lines
10 KiB
Plaintext

(*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at
* http://www.opensource.org/licenses/cddl1.php.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at
* http://www.opensource.org/licenses/cddl1.php. If applicable,
* add the following below this CDDL HEADER, with the fields enclosed
* by brackets "[]" replaced with your own identifying * information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
*
* Portions Copyright 2013 Andreas Schneider
*)
unit UConfig;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, DOM, XMLRead, XMLWrite, Keyboard, UAccount, UXmlHelper,
UInterfaces, UEnums, URegions;
type
TInvalidConfigException = class(Exception);
{ TMapInfo }
TMapInfo = class(TObject, ISerializable)
constructor Create(AOwner: IInvalidate);
constructor Deserialize(AOwner: IInvalidate; AElement: TDOMElement);
procedure Serialize(AElement: TDOMElement);
protected
FOwner: IInvalidate;
FMapFile: string;
FStaticsFile: string;
FStaIdxFile: string;
FWidth: Word;
FHeight: Word;
procedure SetHeight(const AValue: Word);
procedure SetMapFile(const AValue: string);
procedure SetStaIdxFile(const AValue: string);
procedure SetStaticsFile(const AValue: string);
procedure SetWidth(const AValue: Word);
public
property MapFile: string read FMapFile write SetMapFile;
property StaticsFile: string read FStaticsFile write SetStaticsFile;
property StaIdxFile: string read FStaIdxFile write SetStaIdxFile;
property Width: Word read FWidth write SetWidth;
property Height: Word read FHeight write SetHeight;
end;
{ TConfig }
TConfig = class(TObject, ISerializable, IInvalidate)
constructor Create(AFilename: string);
constructor Init(AFilename: string);
destructor Destroy; override;
procedure Serialize(AElement: TDOMElement);
protected
FFilename: string;
FPort: Integer;
FMap: TMapInfo;
FTiledata: string;
FRadarcol: string;
FRegions: TRegionList;
FAccounts: TAccountList;
FChanged: Boolean;
procedure SetPort(const AValue: Integer);
procedure SetRadarcol(const AValue: string);
procedure SetTiledata(const AValue: string);
public
property Port: Integer read FPort write SetPort;
property Map: TMapInfo read FMap;
property Tiledata: string read FTiledata write SetTiledata;
property Radarcol: string read FRadarcol write SetRadarcol;
property Regions: TRegionList read FRegions;
property Accounts: TAccountList read FAccounts;
procedure Flush;
procedure Invalidate;
end;
var
AppDir: string;
ConfigFile: string;
Config: TConfig;
function TimeStamp: string;
implementation
const
CONFIGVERSION = 3;
function QueryPassword: String;
var
pwChar: char;
begin
Result := '';
InitKeyboard;
try
repeat
pwChar := GetKeyEventChar(TranslateKeyEvent(GetKeyEvent));
case pwChar of
#8: Result := Copy(Result, 1, Length(Result) - 1);
#13: break;
else
Result := Result + pwChar;
end;
until pwChar = #13;
finally
DoneKeyboard;
end;
writeln('');
end;
function TimeStamp: string;
begin
Result := '[' + DateTimeToStr(Now) + '] ';
end;
{ TMapInfo }
constructor TMapInfo.Create(AOwner: IInvalidate);
begin
inherited Create;
FOwner := AOwner;
end;
constructor TMapInfo.Deserialize(AOwner: IInvalidate; AElement: TDOMElement);
begin
Create(AOwner);
FMapFile := TXmlHelper.ReadString(AElement, 'Map', 'map0.mul');
FStaIdxFile := TXmlHelper.ReadString(AElement, 'StaIdx', 'staidx0.mul');
FStaticsFile := TXmlHelper.ReadString(AElement, 'Statics', 'statics0.mul');
FWidth := TXmlHelper.ReadInteger(AElement, 'Width', 768);
FHeight := TXmlHelper.ReadInteger(AElement, 'Height', 512);
end;
procedure TMapInfo.Serialize(AElement: TDOMElement);
begin
TXmlHelper.WriteString(AElement, 'Map', FMapFile);
TXmlHelper.WriteString(AElement, 'StaIdx', FStaIdxFile);
TXmlHelper.WriteString(AElement, 'Statics', FStaticsFile);
TXmlHelper.WriteInteger(AElement, 'Width', FWidth);
TXmlHelper.WriteInteger(AElement, 'Height', FHeight);
end;
procedure TMapInfo.SetHeight(const AValue: Word);
begin
FHeight := AValue;
FOwner.Invalidate;
end;
procedure TMapInfo.SetMapFile(const AValue: string);
begin
FMapFile := AValue;
FOwner.Invalidate;
end;
procedure TMapInfo.SetStaIdxFile(const AValue: string);
begin
FStaIdxFile := AValue;
FOwner.Invalidate;
end;
procedure TMapInfo.SetStaticsFile(const AValue: string);
begin
FStaticsFile := AValue;
FOwner.Invalidate;
end;
procedure TMapInfo.SetWidth(const AValue: Word);
begin
FWidth := AValue;
FOwner.Invalidate;
end;
{ TConfig }
constructor TConfig.Create(AFilename: string);
var
xmlDoc: TXMLDocument;
version: Integer;
xmlElement: TDOMElement;
begin
inherited Create;
FFilename := AFilename;
ReadXMLFile(xmlDoc, AFilename);
version := 0;
if not ((xmlDoc.DocumentElement.NodeName = 'CEDConfig') and
TryStrToInt(xmlDoc.DocumentElement.AttribStrings['Version'], version) and
(version = CONFIGVERSION)) then
raise TInvalidConfigException.Create(Format('Version mismatch: %d <> %d', [version, CONFIGVERSION]));
FPort := TXmlHelper.ReadInteger(xmlDoc.DocumentElement, 'Port', 2597);
xmlElement := TDOMElement(xmlDoc.DocumentElement.FindNode('Map'));
if not assigned(xmlElement) then
raise TInvalidConfigException.Create('Map information not found');
FMap := TMapInfo.Deserialize(Self, xmlElement);
FTiledata := TXmlHelper.ReadString(xmlDoc.DocumentElement, 'Tiledata', 'tiledata.mul');
FRadarcol := TXmlHelper.ReadString(xmlDoc.DocumentElement, 'Radarcol', 'radarcol.mul');
xmlElement := TDOMElement(xmlDoc.DocumentElement.FindNode('Regions'));
if assigned(xmlElement) then
FRegions := TRegionList.Deserialize(Self, xmlElement)
else
Fregions := TRegionList.Create(Self);
xmlElement := TDOMElement(xmlDoc.DocumentElement.FindNode('Accounts'));
if not assigned(xmlElement) then
raise TInvalidConfigException.Create('Account information not found');
FAccounts := TAccountList.Deserialize(Self, xmlElement);
xmlDoc.Free;
FChanged := False;
end;
constructor TConfig.Init(AFilename: string);
var
stringValue, password: string;
intValue: Integer;
begin
inherited Create;
FFilename := AFilename;
FMap := TMapInfo.Create(Self);
FAccounts := TAccountList.Create(Self);
FRegions := TRegionList.Create(Self);
Writeln('Configuring Network');
Writeln('===================');
Write ('Port [2597]: ');
Readln (stringValue);
intValue := 0;
if not TryStrToInt(stringValue, intValue) then intValue := 2597;
FPort := intValue;
Writeln('');
Writeln('Configuring Paths');
Writeln('=================');
Write ('map [map0.mul]: ');
Readln (FMap.FMapFile);
if FMap.MapFile = '' then FMap.MapFile := 'map0.mul';
Write ('statics [statics0.mul]: ');
Readln (FMap.FStaticsFile);
if FMap.StaticsFile = '' then FMap.StaticsFile := 'statics0.mul';
Write ('staidx [staidx0.mul]: ');
Readln (FMap.FStaIdxFile);
if FMap.StaIdxFile = '' then FMap.StaIdxFile := 'staidx0.mul';
Write ('tiledata [tiledata.mul]: ');
Readln (FTiledata);
if FTiledata = '' then FTiledata := 'tiledata.mul';
Write ('radarcol [radarcol.mul]: ');
Readln (FRadarcol);
if FRadarcol = '' then FRadarcol := 'radarcol.mul';
Writeln('');
Writeln('Parameters');
Writeln('==========');
Write ('Map width [768]: ');
Readln (stringValue);
if not TryStrToInt(stringValue, intValue) then intValue := 768;
FMap.Width := intValue;
Write ('Map height [512]: ');
Readln (stringValue);
if not TryStrToInt(stringValue, intValue) then intValue := 512;
FMap.Height := intValue;
Writeln('');
Writeln('Admin account');
Writeln('=============');
repeat
Write('Account name: ');
Readln(stringValue);
until stringValue <> '';
Write ('Password [hidden]: ');
password := QueryPassword;
FAccounts.Add(TAccount.Create(FAccounts, stringValue, password,
alAdministrator, nil));
FChanged := True;
end;
destructor TConfig.Destroy;
begin
if Assigned(FMap) then FreeAndNil(FMap);
if Assigned(FAccounts) then FreeAndNil(FAccounts);
if Assigned(FRegions) then FreeAndNil(FRegions);
inherited Destroy;
end;
procedure TConfig.Serialize(AElement: TDOMElement);
begin
TXmlHelper.WriteInteger(AElement, 'Port', FPort);
FMap.Serialize(TXmlHelper.AssureElement(AElement, 'Map'));
TXmlHelper.WriteString(AElement, 'Tiledata', FTiledata);
TXmlHelper.WriteString(AElement, 'Radarcol', FRadarcol);
FAccounts.Serialize(TXmlHelper.AssureElement(AElement, 'Accounts'));
FRegions.Serialize(TXmlHelper.AssureElement(AElement, 'Regions'));
end;
procedure TConfig.SetPort(const AValue: Integer);
begin
FPort := AValue;
Invalidate;
end;
procedure TConfig.SetRadarcol(const AValue: string);
begin
FRadarcol := AValue;
Invalidate;
end;
procedure TConfig.SetTiledata(const AValue: string);
begin
FTiledata := AValue;
Invalidate;
end;
procedure TConfig.Flush;
var
xmlDoc: TXMLDocument;
begin
if FChanged then
begin
xmlDoc := TXMLDocument.Create;
xmlDoc.AppendChild(xmlDoc.CreateElement('CEDConfig'));
xmlDoc.DocumentElement.AttribStrings['Version'] := IntToStr(CONFIGVERSION);
Serialize(xmlDoc.DocumentElement);
WriteXMLFile(xmlDoc, FFilename);
xmlDoc.Free;
FChanged := False;
end;
end;
procedure TConfig.Invalidate;
begin
FChanged := True;
end;
initialization
begin
AppDir := ExtractFilePath(ParamStr(0));
if AppDir[Length(AppDir)] <> PathDelim then
AppDir := AppDir + PathDelim;
{TODO : add command line parameter to specify the config}
Config := nil;
ConfigFile := ChangeFileExt(ParamStr(0), '.xml');
end;
end.