* DataPaths now has two new helper methods. GetFilePath for returning the path to a supplied filename for a specified object type. GetExtension which returns a file extension for the specified object type.

* XMLData now contains a GetData() method for returning data from the stored data collection.
* XMLData now contains a Load() method for loading a previously saved XML data file.
* StandardCharacter now automatically generates a filename.
* StandardCharacter.Connected added.  Use Connected to check if they are connected to the server regardless of the values for Enabled and LoggedIn.  LoggedIn is now true once the Login command is completed.
* Default Character Role is now Player.
* Server.ServerOwner property added.  When a character is logged in matching the ServerOwner name, it will automatically be assigned the Admin role.
* StandardCharacter.ExecuteSilentCommand() method added for executing a command and not having the "Command: " line printed to the screen when the command is completed.  Useful for daisy chained commands.
* StandardCharacter login code is now 100% completed.  Including save/load code and new character creation.
* StandardCharacter.SetRole() method added.  Admins can set the role of any other character in the game if they want to.
* BaseScript & StandardCharacter now have their Load() code fully implemented.  They can save and load their files now.
* Player creation command added.  Can only be executed from within the login command.  If it is executed from any other object it will bail.
* Stop command now only works when a Character with Role = Admin issues the command.  During development of a MUD Game, this would typically be the Server.ServerOwner character who will have Admin rights.
* ConnectionManager had some bugs fixed such as not removing Threads from the Thread collection when a character disconnected.  Also re-organized the character connection code some.
This commit is contained in:
Scionwest_cp 2012-03-03 23:29:58 -08:00
parent 4b6c394f43
commit f2c5b594c5
13 changed files with 307 additions and 34 deletions

View file

@ -25,6 +25,6 @@ namespace MudEngine.Core.Interfaces
/// <summary>
/// Method for connecting a object to the server.
/// </summary>
void Connect(Socket connection);
void Connect();
}
}

View file

@ -13,7 +13,7 @@ namespace MudEngine.Core.Interfaces
/// <summary>
/// Objects filename.
/// </summary>
String Filename { get; set; }
String Filename { get; }
/// <summary>
/// Save method for dumping the object to physical file.

View file

@ -54,6 +54,34 @@ namespace MudEngine.DAL
return String.Empty;
}
public String GetFilePath(DataTypes objectType, String filename)
{
String result = String.Empty;
switch (objectType)
{
case DataTypes.Players:
result = Path.Combine(this._Players, filename + this.GetExtension(DataTypes.Players));
break;
}
return result;
}
public String GetExtension(DataTypes objectType)
{
String result = String.Empty;
switch (objectType)
{
case DataTypes.Players:
result = ".player";
break;
}
return result;
}
private String _InstallRoot;
private String _Players;
private String _Environments;

View file

@ -6,6 +6,7 @@ using System.Xml.Linq;
using System.Reflection;
using MudEngine.GameScripts;
using MudEngine.Core;
namespace MudEngine.DAL
{
@ -19,6 +20,7 @@ namespace MudEngine.DAL
public XMLData(String objectType)
{
SaveData = new XElement(objectType);
this._RootNode = objectType;
}
public void AddSaveData(String property, String value)
@ -26,6 +28,17 @@ namespace MudEngine.DAL
this.SaveData.Add(new XElement(property, value));
}
public String GetData(String property)
{
foreach (XElement element in SaveData.Elements())
{
if (element.Name.LocalName == property)
return element.Value;
}
return String.Empty;
}
public Boolean Save(String filename)
{
try
@ -38,5 +51,22 @@ namespace MudEngine.DAL
return false;
}
}
public Boolean Load(String filename)
{
try
{
this.SaveData = XElement.Load(filename);
return true;
}
catch (Exception ex)
{
Logger.WriteLine(ex.Message);
return false;
}
}
private String _RootNode;
}
}

View file

@ -26,7 +26,13 @@ namespace MudEngine.Game.Characters
/// </summary>
public StandardGame Game { get; private set; }
public string Filename { get; set; }
public string Filename
{
get
{
return this.Game.SavePaths.GetFilePath(DAL.DataTypes.Players, this.Name);
}
}
/// <summary>
/// Gets what this Characters role on the server is.
@ -48,11 +54,14 @@ namespace MudEngine.Game.Characters
/// <summary>
/// Gets or Sets if this character is enabled.
/// When disabled, they can not enter commands.
/// Characters can have LoggedIn and Connected TRUE with Enabled false resulting in a player connected to
/// the server but unable to interact.
/// </summary>
public Boolean Enabled { get; set; }
/// <summary>
/// Gets or Sets if this client is fully logged into the account.
/// Gets or Sets if this client is fully logged into the account and located in the World.
/// </summary>
public Boolean LoggedIn
{
@ -68,6 +77,11 @@ namespace MudEngine.Game.Characters
}
}
/// <summary>
/// Gets if the user is currently connected to a server or not.
/// </summary>
public Boolean Connected { get; set; }
//TODO: Add current location to characters
//public IEnvironment CurrentLocation
@ -78,6 +92,8 @@ namespace MudEngine.Game.Characters
{
this.Game = game;
this.Role = CharacterRoles.Player;
//Instance this Characters personal Command System with a copy of the command
//collection already loaded and prepared by the Active Game.
this.Commands = new CommandSystem(CommandSystem.Commands);
@ -114,13 +130,22 @@ namespace MudEngine.Game.Characters
}
public override bool Save(String filename)
{
return this.Save(filename, true);
}
public override bool Save(String filename, Boolean verbose)
{
base.Save(filename, true);
SaveData.AddSaveData("Immovable", Immovable.ToString());
SaveData.AddSaveData("Password", Password);
this.SaveData.Save(filename);
if (this.SaveData.Save(filename))
{
if (!verbose)
this.SendMessage("Save completed.");
}
return true;
}
@ -128,9 +153,17 @@ namespace MudEngine.Game.Characters
public override void Load(string filename)
{
base.Load(filename);
this.Immovable = Convert.ToBoolean(this.SaveData.GetData("Immovable"));
this.Password = this.SaveData.GetData("Password");
}
internal Boolean ExecuteCommand(string command)
/// <summary>
/// Executes the specified command if it exists in the Command library.
/// </summary>
/// <param name="command"></param>
/// <returns></returns>
public Boolean ExecuteCommand(string command)
{
if (this.Enabled)
{
@ -145,12 +178,29 @@ namespace MudEngine.Game.Characters
return false;
}
public void Connect(Socket connection)
/// <summary>
/// Executes the spcified command if it exists in the Command library.
/// This method is verbose. Only messages sent from the Commands will be presented to the player.
/// The standard new line and "Command: " message is skipped with this method.
/// </summary>
/// <param name="command"></param>
/// <returns></returns>
public Boolean ExecuteSilentCommand(string command)
{
this._Connection = connection;
if (this.Enabled)
{
Boolean result = Commands.Execute(command, this);
return result;
}
else
return false;
}
public void Connect()
{
//this.Initialize();
this.Connected = true;
OnConnectEvent();
}
@ -164,9 +214,9 @@ namespace MudEngine.Game.Characters
//Close our currently open socket.
this._Connection.Close();
this.OnDisconnectEvent();
this.LoggedIn = false;
Console.WriteLine("Disconnect Complete.");
this.OnDisconnectEvent();
}
public void SendMessage(String data)
@ -246,13 +296,31 @@ namespace MudEngine.Game.Characters
this.SendMessage(String.Empty);
//Log the user in.
this.LoggedIn = this.ExecuteCommand("Login");
Boolean result = this.ExecuteSilentCommand("Login");
this.SendMessage(String.Empty);
//Flags the character as fully logged in.
//This will automatically invoke the OnLoggedIn method
//which will present the user with the server MOTD
this.LoggedIn = result;
//Provide a blank line between the character loggin info
//and the characters actual first in-game Command prompt.
this.SendMessage(String.Empty);
//Make sure we are logged in.
if (!this.LoggedIn)
{
this.Disconnect();
}
this.ExecuteCommand("Look");
}
public delegate void OnDisconnectHandler();
public event OnDisconnectHandler OnDisconnectEvent;
public void OnDisconnect()
{
Console.WriteLine("Disconnect Complete.");
}
public delegate void OnLoginHandler();
@ -260,6 +328,26 @@ namespace MudEngine.Game.Characters
public void OnLogin()
{
this.SendMessage(this.Game.Server.MOTD);
//Check to see if this user is the servers owner.
if (this.Name == this.Game.Server.ServerOwner)
{
//Set the role accordingly.
this.Role = CharacterRoles.Admin;
}
}
public void SetRole(StandardCharacter adminCharacter, StandardCharacter subordinateCharacter, CharacterRoles role)
{
//Check to make sure the admin character is truly a admin
if (adminCharacter.Role == CharacterRoles.Admin)
{
subordinateCharacter.Role = role;
}
else
{
adminCharacter.SendMessage("You do not have the rights to perform this command.");
}
}
private Socket _Connection;

View file

@ -8,6 +8,7 @@ using System.IO;
using MudEngine.Game;
using MudEngine.DAL;
using MudEngine.Core;
namespace MudEngine.GameScripts
{
@ -44,6 +45,7 @@ namespace MudEngine.GameScripts
try
{
this.SaveData = new XMLData(this.GetType().Name);
this.SaveData.AddSaveData("Name", Name);
this.SaveData.AddSaveData("ID", ID);
this.SaveData.AddSaveData("Description", Description);
@ -65,11 +67,15 @@ namespace MudEngine.GameScripts
{
if (!File.Exists(filename))
return;
this.SaveData.Load(filename);
//XElement data = XElement.Load(filename);
this.Name = this.SaveData.GetData("Name");
this.ID = this.SaveData.GetData("ID");
this.Description = this.SaveData.GetData("Description");
}
catch
catch (Exception ex)
{
Logger.WriteLine(ex.Message);
return;
}
return;

View file

@ -0,0 +1,89 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;
using System.Diagnostics;
using MudEngine.Core.Interface;
using MudEngine.Game;
using MudEngine.Game.Characters;
using MudEngine.Game.Environment;
using MudEngine.GameScripts;
namespace MudEngine.GameScripts.Commands
{
public class CommandCreatePlayer : ICommand
{
public string Name { get; set; }
public string Description { get; set; }
public List<string> Help { get; set; }
public CommandCreatePlayer()
{
Help = new List<string>();
Name = "CreatePlayer";
Description = "Account login command.";
}
public Boolean Execute(string command, Game.Characters.StandardCharacter character)
{
//reference to the Characters Game.
StandardGame game = character.Game;
Boolean buildingPassword = true;
//We need to check if the 3rd Frame on the stack is the CommandLogin Type.
//If it isn't, then another Type executed this command and we don't allow it.
StackTrace trace = new StackTrace();
String callingType = trace.GetFrame(3).GetMethod().ReflectedType.Name;
//Don't allow anything other than the Login command to start the
//character creation process.
if (callingType != "CommandLogin")
{
character.SendMessage("Invalid Command Used.");
return false;
}
//Make sure we build a proper password.
while (buildingPassword)
{
character.SendMessage("Please enter a password for this character: ", false);
String password1, password2;
password1 = character.GetInput();
//We do not perform any IsLetterOrDigit() checks on passwords. The more
//special characters the better.
//We do however want to make sure the length of the password is sufficient
if (password1.Length < character.Game.MinimumPasswordSize)
{
character.SendMessage("Passwords must have a minimum of " + character.Game.MinimumPasswordSize.ToString() + " characters!");
continue;
}
character.SendMessage("Please re-enter your password for confirmation: ", false);
password2 = character.GetInput();
if (password1 == password2)
{
buildingPassword = false;
character.Password = password1;
}
else
{
character.SendMessage("Passwords did not match!");
continue;
}
}
//TODO: Create a class and setup Stats.
character.Save(character.Filename, false);
return true;
}
}
}

View file

@ -47,7 +47,7 @@ namespace MudEngine.GameScripts.Commands
String name = String.Empty;
//Repeat the login process until we get a valid name.
while (String.IsNullOrEmpty(name))
while (String.IsNullOrEmpty(name) && character.Connected)
{
character.SendMessage("Enter your character name: ", false);
@ -92,9 +92,9 @@ namespace MudEngine.GameScripts.Commands
continue;
//Look if the file exists.
String filename = game.SavePaths.GetPath(DAL.DataTypes.Players) + name;
String filename = game.SavePaths.GetFilePath(DAL.DataTypes.Players, name);
if (File.Exists(game.SavePaths.GetPath(DAL.DataTypes.Players) + name))
if (File.Exists(filename))
isFound = true;
//if the character name supplied exists, load it.
@ -112,10 +112,10 @@ namespace MudEngine.GameScripts.Commands
}
//Load the character from file.
character.Load(game.SavePaths.GetPath(DAL.DataTypes.Players) + name);
character.Load(filename);
//Check if the characters password matches that of the saved player password
if ("1234" != password)
if (character.Password != password)
{
//No match, bail.
character.SendMessage("Invalid password provided.");
@ -127,7 +127,6 @@ namespace MudEngine.GameScripts.Commands
character.SendMessage("Welcome back " + character.Name + "!");
return true;
}
}
else
{
@ -135,10 +134,25 @@ namespace MudEngine.GameScripts.Commands
String result = character.GetInput();
if (result.ToLower() == "yes")
{
return CreateCharacter(name);
//Store the character name.
character.Name = name;
if (!character.ExecuteSilentCommand("CreatePlayer"))
{
name = String.Empty;
continue;
}
else
{
//We complete the login process..
character.SendMessage(character.Name + " created!");
return true;
}
}
else
{
name = String.Empty;
continue;
}
}
@ -146,11 +160,6 @@ namespace MudEngine.GameScripts.Commands
return false;
}
private Boolean CreateCharacter(String name)
{
return false;
}
private StandardCharacter _Character;
}
}

View file

@ -31,8 +31,18 @@ namespace MudEngine.GameScripts.Commands
StandardGame game = character.Game;
//Stop the game.
new Thread(game.Stop).Start();
return true;
if (character.Role == CharacterRoles.Admin)
{
new Thread(game.Stop).Start();
return true;
}
else
{
//Since a non-admin character attempted this command,
//tell them they used a invalid command
character.SendMessage("Invalid command used.");
return false;
}
}
}
}

View file

@ -35,8 +35,6 @@ namespace MudEngine.Networking
StandardCharacter character = new StandardCharacter(game, "New Player", "New networked client.", connection);
//Invoke the Characters Server connection method
character.Initialize();
character.Connect(connection);
this._ConnectedCharacters.Add(character);
this._ConnectedThreads.Add(new Thread(ReceiveDataThread));
@ -53,8 +51,11 @@ namespace MudEngine.Networking
{
StandardCharacter character = this._ConnectedCharacters[(Int32)index];
character.Initialize();
character.Connect();
while (character.Game.Server.Status == ServerStatus.Running &&
character.Enabled)
character.Connected)
{
try
{
@ -83,7 +84,9 @@ namespace MudEngine.Networking
{
Int32 index = _ConnectedCharacters.IndexOf(c);
this._ConnectedCharacters.Remove(character);
this._ConnectedThreads[index].Abort();
Thread t = this._ConnectedThreads[index];
this._ConnectedThreads.Remove(this._ConnectedThreads[index]);
t.Abort();
}
}
}

View file

@ -38,6 +38,14 @@ namespace MudEngine.Networking
public String MOTD { get; set; }
/// <summary>
/// Gets or Sets the owning Character that has access to all Admin commands.
/// Only the ServerOwner can change the Roles of other Characters. If there
/// is no ServerOwner specified then other Characters can not have their Roles
/// elevated from that of Player.
/// </summary>
public String ServerOwner { get; set; }
public Server(StandardGame game, Int32 port)
{
this.Port = port;

View file

@ -58,6 +58,7 @@
<Compile Include="GameScripts\Commands\CommandLogin.cs" />
<Compile Include="GameScripts\Commands\CommandSay.cs" />
<Compile Include="GameScripts\Commands\CommandStop.cs" />
<Compile Include="GameScripts\Commands\CommandCreatePlayer.cs" />
<Compile Include="Game\Characters\CharacterRoles.cs" />
<Compile Include="Game\Characters\CharacterStats.cs" />
<Compile Include="Game\Characters\MyCharacter.cs" />

View file

@ -33,6 +33,7 @@ namespace WinPC_Server
game.Server.MOTD = "Welcome to the Sample Game demonstration server! This is the Servers MOTD!";
game.Version = "1.0";
game.Website = "http://muddesigner.codeplex.com";
game.Server.ServerOwner = "Akiyuki";
//Start the game and server.
game.Start(100, 20);