// created on 20/11/2005 at 13:36
// Stuff for game types. Note that this is all client-side
// (and interfaces require ClientLobby parameters) because
// the server never needs to know *what* game you're playing.
using System;
using System.Text;
using System.Windows.Forms;
namespace RedCorona.Net.Games {
public interface IGame {
// Game types must support these members to allow
// the server to manage its games correctly
bool ProcessCode(ClientLobbyProxy lobby, MemberInfo mem, uint code, byte[] bytes, int len);
Form GetCustomSetupForm();
void RequestStartGame();
void StartGame();
void CloseGame();
}
public interface IGameType {
string URL { get; }
string Version { get; }
bool CanCreate { get; }
int ValidateMaxPlayers(int value);
IGame CreateClientsideGame(ClientLobbyProxy lobby, GameInfo gi);
}
public abstract class BaseGame: MarshalByRefObject, IGame {
protected ClientLobbyProxy lobby;
protected GameInfo game;
protected Form SetupForm, MainForm;
protected bool amOwner;
public GameInfo Game { get { return game; } }
public ClientLobbyProxy Lobby { get { return lobby; } }
public bool OwnsGame { get { return game.CreatorID == lobby.MyID; } }
protected BaseGame(ClientLobbyProxy lobby, GameInfo gi){
this.lobby = lobby; game = gi;
amOwner = gi.CreatorID == lobby.MyID;
}
public virtual bool ProcessCode(ClientLobbyProxy lobby, MemberInfo mem, uint code, byte[] bytes, int len){
try {
ByteBuilder b = new ByteBuilder(bytes, len);
int pi = 0;
switch(code){
case ReservedCodes.Chat:
int scope = ClientInfo.GetInt(b.GetParameter(ref pi).content, 0, 4);
if(scope == ChatScope.Lobby) break;
int memberid = ClientInfo.GetInt(b.GetParameter(ref pi).content, 0, 4);
String msg = Encoding.UTF8.GetString(b.GetParameter(ref pi).content);
int id = ClientInfo.GetInt(b.GetParameter(ref pi).content, 0, 4);
Console.WriteLine("Chat, scope "+scope+" in game "+id);
if(id == game.ID) ProcessGameChat(memberid, msg, scope);
break;
default:
// If it's been passed to our game, call the 'easy' cover version
id = ClientInfo.GetInt(b.GetParameter(ref pi).content, 0, 4);
if(id == game.ID) return ProcessGameCode(lobby, code, b, ref pi);
break;
}
} catch(ArgumentException) {}
catch(IndexOutOfRangeException) {}
return true; // allow normal processing
}
public virtual void ProcessGameChat(int MemberID, String msg, int scope){
// Override to do nice things with chat within this game
}
public virtual bool ProcessGameCode(ClientLobbyProxy lobby, uint code, ByteBuilder data, ref int datapos){
try {
switch(code){
case ReservedCodes.StartGame:
Console.WriteLine("Starting custom game code");
StartGame();
break;
}
} catch(Exception e){
Console.WriteLine("Error running custom game code: "+e);
}
return true;
}
public virtual void SetData(String key, Parameter p, bool global, uint globalflags){
ByteBuilder bb = new ByteBuilder(9);
bb.AddParameter(ClientInfo.IntToBytes(game.ID), ParameterType.Int);
if(global)
bb.AddParameter(ClientInfo.UintToBytes(globalflags), ParameterType.Uint);
bb.AddParameter(Encoding.UTF8.GetBytes(key), ParameterType.String);
bb.AddParameter(p);
lobby.SendMessage(global ? ReservedCodes.SetGameTypeToken : ReservedCodes.SetGameToken, bb.Read(0, bb.Length), 0);
}
public virtual void SetData(String key, String value, bool global, uint globalflags){
SetData(key, new Parameter(Encoding.UTF8.GetBytes(value), ParameterType.String), global, globalflags);
}
public virtual void SetData(String key, int value, bool global, uint globalflags){
SetData(key, new Parameter(ClientInfo.IntToBytes(value), ParameterType.Int), global, globalflags);
}
public void SendToGameOwner(uint code, byte[] msg, byte ParamType){
ByteBuilder bb = new ByteBuilder();
bb.AddParameter(ClientInfo.UintToBytes(code), ParameterType.Uint);
//bb.AddParameter(ClientInfo.IntToBytes(game.CreatorID), ParameterType.Int);
bb.AddParameter(ClientInfo.IntToBytes(game.ID), ParameterType.Uint);
if(ParamType != 0) bb.AddParameter(msg, ParamType);
else bb.Add(msg);
lobby.SendMessage(ReservedCodes.ToGameOwner, bb.Read(0, bb.Length), 0);
}
public virtual Form GetCustomSetupForm(){
return SetupForm; // default stuff is adequate
}
public virtual void RequestStartGame(){
// If we're the owner, this gets called when the user actually
// asks to start the game. Examples of sensible overrides:
// - Check all compulsory positions are filled
if(!OwnsGame) return;
if(AllAreReady()) {
lobby.SendMessage(ReservedCodes.StartGame, BaseLobby.PrepareTwoIDs(game.ID, 0x4), 0);
} else lobby.SendMessage(ReservedCodes.GameBroadcast, BaseLobby.PrepareTwoIDs((int)ReservedCodes.ReadyToStart, game.ID), 0);
}
public virtual bool AllAreReady(){
// Override if standard ready test is not good enough
for(int i = 0; i < game.PlayerFlags.Length; i++){
if(game.Players[i] == game.CreatorID) continue; // assume creator is always ready
if(0 == (game.PlayerFlags[i] & PlayerGameFlags.Ready))
return false;
}
return true;
}
public virtual void StartGame(){
// Set the game flag to 'In Progress'
}
public virtual void CloseGame(){
if(MainForm != null){
MainForm.Close();
MainForm = null;
}
if(SetupForm != null){
SetupForm.Close();
SetupForm = null;
}
}
}
public abstract class BaseGameType : MarshalByRefObject, IGameType {
public abstract String URL { get; }
public abstract string Version { get; }
public virtual bool CanCreate { get { return true; } }
public int ValidateMaxPlayers(int value){ return value; }
public abstract IGame CreateClientsideGame(ClientLobbyProxy lobby, GameInfo gi);
public static Version GetVersion(string Version){
string[] sa = Version.Split(' ')[0].Split('.');
try { return new Version(Int32.Parse(sa[0]), Int32.Parse(sa[1]), Int32.Parse(sa[2]));
} catch { return new Version(); }
}
}
public interface IServersideGame {
GameInfo Game { get; set; }
ServerLobbyProxy Lobby { get; set; }
void Initialise();
void Close();
bool CanJoin(int memberID, int requestID, string password, out string msg);
void Joined(int memberID);
void Left(int memberID);
bool GameMessage(int memberID, uint code, ByteBuilder bb, int startPos);
//HttpResponse HandleWebMessage(HttpRequest r);
}
public interface IServersideGameType {
string URL { get; }
string Version { get; }
IServersideGame CreateGame(ServerLobbyProxy lobby, GameInfo gi);
}
}