/// <summary> /// Sends a textual informational message to a player /// </summary> /// <param name="msg">the message</param> /// <param name="includeObservers">if observers should be included</param> /// <param name="targetPlayers">explicit list of message targets, or null for everyone</param> public void SendGameInfoMessageToPlayer(ServerCharacterInfo toon, string msg) { PacketGameInfoNotification note = new PacketGameInfoNotification(); note.Message = msg; SendPacketToPlayer(toon, note); }
public void SendMatchChangeNotificationToPlayers(MatchNotificationType kind, ServerCharacterInfo targetPlayer, string text, bool synchClientGameObject) { PacketMatchNotification p = new PacketMatchNotification(); p.PacketTypeID = (int)LobbyPacketType.MatchNotification; p.Kind = kind; p.TheGame = synchClientGameObject? Game : null; p.TheGameID = Game.GameID; if (targetPlayer != null) { p.TargetPlayer = targetPlayer.CharacterInfo; } p.ReplyCode = ReplyType.OK; p.ReplyMessage = text; /* * if (p.Kind == MatchNotificationType.MatchEnded) * { * // add this particular message to the PFX queue, to make sure that the EndMessage/Disconnect&Transfer happen in the property order * Task t = new Task((state) => * { * BroadcastToPlayersInGame(p, true); * }, "BroadcastToPlayersInGame: Match Ended", TaskCreationOptions.LongRunning); * m_NetQ.AddTask(t); * } * else */ { BroadcastToPlayersInGame(p, true); } }
private void Test() { Game g = new Game(); PropertyBag p = new PropertyBag(); g.Properties = p; g.Owner = -1; TurnedGameServerGame tg = new TurnedGameServerGame(g); string msg =""; CharacterInfo ci1 = new CharacterInfo(); ci1.ID = 1; ci1.CharacterName = "Alpha"; ServerCharacterInfo t1 = new ServerCharacterInfo(ci1); tg.AddPlayer(t1, ref msg); CharacterInfo ci2 = new CharacterInfo(); ci2.ID = 2; ci2.CharacterName = "Bravo"; ServerCharacterInfo t2 = new ServerCharacterInfo(ci2); tg.AddPlayer(t2, ref msg); CharacterInfo ci3 = new CharacterInfo(); ci3.ID = 3; ci3.CharacterName = "Charly"; ServerCharacterInfo t3 = new ServerCharacterInfo(ci3); tg.AddPlayer(t3, ref msg); string msg2 =""; tg.StartGame(ref msg2, true); }
private void OnCharacterCreateRequest(INetworkConnection con, Packet gmsg) { PacketGenericMessage msg = gmsg as PacketGenericMessage; string rsltMsg = ""; ServerCharacterInfo ci = null; if (MyServer.UseCharacters) { ci = CharacterUtil.Instance.CreateNewCharacter(msg.Parms, ServerUser); } ReplyType rslt = ReplyType.Failure; if (ci != null && OnValidateCharacterCreateRequest(ci, ref rsltMsg)) { if (CharacterUtil.Instance.PersistNewCharacter(ci, ServerUser, ref rsltMsg, !MyServer.RequireAuthentication)) { rslt = ReplyType.OK; } } PacketReply rep = CreateStandardReply(msg, rslt, rsltMsg); msg.ReplyPacket = rep; }
protected virtual void OnPlayerChat(ServerUser fromPlayer, PacketGameMessage msg) { // Game messages are already queued... should not need to queue them manually //Task t = new Task((state) => { int targetPlayer = msg.Parms.GetIntProperty("target").GetValueOrDefault(-1); string text = msg.Parms.GetStringProperty("text"); if (text == null || text.Length < 1) { return; } msg.Parms.SetProperty("sender", fromPlayer.CurrentCharacter.CharacterInfo as ISerializableWispObject); if (targetPlayer < 0) { // Public chat BroadcastToPlayersInGame(msg, true, fromPlayer.CurrentCharacter); return; } if (IsPlayerPartOfGame(targetPlayer)) { ServerCharacterInfo sci = GetCharacter(targetPlayer) as ServerCharacterInfo; SendPacketToPlayer(sci, msg); } }//, "Chat from player " + fromPlayer.CurrentCharacter.CharacterName, TaskCreationOptions.PreferFairness); //m_NetQ.AddTask(t); }
/// <summary> /// Removes a player from the active Players list /// </summary> /// <param name="character">the character to add</param> public virtual void RemovePlayer(ServerCharacterInfo character, string reason, bool playerInitiated) { //Task t = new Task((state) => { lock (m_Game.AllPlayersSyncRoot) { if (Players.Remove(character.ID)) { Log1.Logger("SERVER").Info("Removed player [#" + character.CharacterName + "] from game [" + Name + "] [" + GameID.ToString() + "]."); AllPlayers = (List <ICharacterInfo>)Players.Values.ToList <ICharacterInfo>(); if (CurrentGameState == GameState.Started && !Solved) { // player quit after we started the game, but before we finished the match AddToQuittersRoster(character); } OnPlayerRemoved(character, reason, playerInitiated); // What's the state of the game after player left? if (CurrentGameState == GameState.Lobby) { GameStartStrategy.NotifyPlayerLeftLobby(character.ID); } else if (CurrentGameState == GameState.Started) { GameAbortStrategy.NotifyPlayerLeftGame(character.ID); } } } } //, "Remove Player from game" + character.ToString(), TaskCreationOptions.LongRunning); //m_NetQ.AddTask(t); }
/// <summary> /// For clusters that don't use explicit characters, default characters are used for database tracking purposes. /// Call this method to get a reference to that default character. Method will return null if App.Config's UseCharacters /// setting is TRUE /// </summary> /// <param name="owner"></param> /// <returns></returns> public ServerCharacterInfo GetOrCreateDefaultCharacter(bool isTempCharacter, ServerUser owner) { SqlConnection con = null; SqlTransaction tran = null; try { // This cluster doesn't use characters. Create a default one for system purposes if we don't have one already ServerCharacterInfo ci = new ServerCharacterInfo(); if (!DB.Instance.Character_LoadAny(owner.ID, ci)) // see if we can fetch the current default character from the DB. { // Nope, couldn't find it. Try creating one. ci = new ServerCharacterInfo(CreateNewCharacterShell(), owner); ci.Properties.SetProperty((int)PropertyID.Name, "Mc_" + CryptoManager.GetSHA256Hash(owner.AccountName)); string msgCreate = ""; int newCharId = NextCharId; if (DB.Instance.Character_Create(owner.ID, ci.Stats, ci.Properties, (int)PropertyID.Name, ci.CharacterName, true, 1, isTempCharacter, out msgCreate, out tran, out con, out newCharId)) { ci.CharacterInfo.ID = newCharId; if (tran != null) { tran.Commit(); } return(ci); } else { if (tran != null) { tran.Rollback(); } } } else // got the default character { return(ci); } } catch (Exception e) { } finally { if (con != null) { con.Close(); con.Dispose(); con = null; } if (tran != null) { tran.Dispose(); tran = null; } } return(null); }
protected bool OnCharacterSaving(SqlConnection con, SqlTransaction tran, ServerCharacterInfo ci, ref string msg) { if (CharacterSaving != null) { return(CharacterSaving(con, tran, ci)); } return(true); }
protected override void OnCharacterHandoffComplete(INetworkConnection con, ServerCharacterInfo character, Guid owner) { base.OnCharacterHandoffComplete(con, character, owner); OutboundServerConnection ocon = con as OutboundServerConnection; // we uncache a character when they disconnect (even as part of a transfer, just in case they never reconnect). // now that they have reconnected, recache them. CharacterCache.CacheCharacter(character, ocon.ServerUserID, TimeSpan.MaxValue); }
private void OnCharacterHandoffComplete(INetworkConnection con, Packet msg) { PacketGenericMessage pck = msg as PacketGenericMessage; ServerCharacterInfo ci = pck.Parms.GetComponentProperty((int)PropertyID.CharacterInfo) as ServerCharacterInfo; Guid owner = pck.Parms.GetGuidProperty((int)PropertyID.Owner); Log1.Logger("Server.Outbound.Network").Info("Character [" + ci.CharacterName + "|#" + ci.ID.ToString() + "] completed transfer to " + ((OutboundServerConnection)con).Name); OnCharacterHandoffComplete(con, ci, owner); }
/// <summary> /// Sends a generic PacketGameMessage of a specific sub type to a player /// </summary> /// <param name="msg">the message</param> /// <param name="includeObservers">if observers should be included</param> /// <param name="targetPlayers">explicit list of message targets, or null for everyone</param> public void SendGameMessageToPlayer(ServerCharacterInfo toon, int subType, PropertyBag props) { PacketGameMessage note = new PacketGameMessage(); note.PacketSubTypeID = subType; note.Parms = props; SendPacketToPlayer(toon, note); }
public void SendPacketToPlayer(ServerCharacterInfo toon, Packet p, bool compress, bool encrypt) { p.IsCompressed = compress; p.IsEncrypted = encrypt; if (toon != null && toon.OwningAccount != null && toon.OwningAccount.MyConnection != null && toon.OwningAccount.MyConnection.IsAlive) { toon.OwningAccount.MyConnection.Send(p); } }
/// <summary> /// When a player quits they are added to this games' quitters roster /// </summary> /// <param name="ci"></param> public void AddToQuittersRoster(ServerCharacterInfo ci) { // Add them to the games' "Quitters" roster. int[] playersQuit = Properties.GetIntArrayProperty("Quitters"); if (Array.IndexOf(playersQuit, ci.ID) < 0) { Array.Resize(ref playersQuit, playersQuit.Length + 1); playersQuit[playersQuit.Length - 1] = ci.ID; Properties.SetProperty("Quitters", playersQuit); } }
protected override bool OnCharacterSaving(SqlConnection con, SqlTransaction tran, ServerCharacterInfo ci) { bool rslt = CharacterUtil.Instance.SaveCharacter_TSRating(ci, con, tran); if (rslt) { return base.OnCharacterSaving(con, tran, ci); } return false; }
protected override void OnPlayerRemoved(ServerCharacterInfo character, string reason, bool playerInitiated) { //Player got removed from game, if it was currently their turn, they are done. base.OnPlayerRemoved(character, reason, playerInitiated); try { if (CurrentPlayer != null && CurrentPlayer.ID == character.ID) { EndPlayersTurn(); } } catch { } }
/// <summary> /// Tries to end the current phase. /// </summary> /// <param name="serverCharacterInfo"></param> protected virtual void PlayerDone(ServerCharacterInfo serverCharacterInfo) { if (serverCharacterInfo != null && CurrentPlayer.ID != serverCharacterInfo.ID) { Log.LogMsg("Player [" + serverCharacterInfo.CharacterName + "] [" + serverCharacterInfo.ID.ToString() + "] tried to say PlayerDone, but it's currently someone else's turn."); return; } if (GamePhaseSequencer.CurrentItem != null) { ((Phase)GamePhaseSequencer.CurrentItem).PlayerDone(serverCharacterInfo); } }
public void SendGamePropertiesUpdateToPlayer(ServerCharacterInfo toon, Guid bagId, Property[] ps, bool removeProperties, bool compress, bool encrypt) { PacketGamePropertiesUpdateNotification note = new PacketGamePropertiesUpdateNotification(); note.Properties = ps; note.PropertyBagId = bagId; note.TheGame = GameID; note.IsCompressed = compress; note.IsEncrypted = encrypt; note.Remove = removeProperties; SendPacketToPlayer(toon, note); }
/// <summary> /// Saves/updates the character to the DB /// </summary> /// <param name="owner">owning account</param> /// <param name="id">the id for the character to get</param> /// <param name="enforceUniqueName">You can change a toon's name in the DB. To ensure unique names, set to true. IMPORTANT!!!: If you are saving /// , i.e. updating an EXISTING toon without changing his name, set enforceUniqueName to FALSE - otherwise the update will fail since that /// toon's name already exists in the DB, the update will fail.</param> /// <returns></returns> public bool SaveCharacter(ServerUser owner, ServerCharacterInfo toon, bool enforceUniqueName, ref string rsultMsg) { SqlConnection con = null; SqlTransaction tran = null; try { Guid cown = Guid.Empty; if (DB.Instance.Character_Save(owner.ID, toon, (int)PropertyID.Name, toon.CharacterName, enforceUniqueName, out rsultMsg, out tran, out con)) { if (!OnCharacterSaving(con, tran, toon, ref rsultMsg)) { tran.Rollback(); } else { tran.Commit(); } } else { if (con.State != System.Data.ConnectionState.Closed && con.State != System.Data.ConnectionState.Connecting) { if (tran != null) { tran.Rollback(); } } rsultMsg = "Can't save character. " + rsultMsg; return(false); } } catch (Exception e) { } finally { if (con != null) { con.Close(); con.Dispose(); con = null; } if (tran != null) { tran.Dispose(); tran = null; } } return(true); }
/// <summary> /// Gets called when a player is about to be added. Return false to prevent player from being added. /// </summary> /// <param name="toon">the character to add</param> /// <returns></returns> protected virtual bool CanAddPlayer(ServerCharacterInfo toon, ref string msg) { msg = ""; if (Players.ContainsKey(toon.ID)) { msg = "Player is already part of this game."; return(false); } if (PlayerCountSafe + 1 > MaxPlayers) { msg = "Game is full. Sorry."; return(false); } return(true); }
/// <summary> /// Removes a player from the passive Observers list /// </summary> /// <param name="character">the character to add</param> public virtual void RemoveObserver(ServerCharacterInfo character) { //Task t = new Task((state) => { lock (m_Game.AllObserversSyncRoot) { if (Observers.Remove(character.ID)) { Log.LogMsg("Removed observer [#" + character.ToString() + "] from game [" + Name + "] [" + GameID.ToString() + "]."); AllObservers = (List <ICharacterInfo>)Observers.Values.ToList <ICharacterInfo>(); OnObserverRemoved(character); } } }//, "Remove Observer " + character.ToString(), TaskCreationOptions.LongRunning); //m_NetQ.AddTask(t); }
/// <summary> /// Gets called when an observers is about to be added. Return false to prevent player from being added. /// </summary> /// <param name="character">the player to observe</param> /// <returns></returns> protected virtual bool CanAddObserver(ServerCharacterInfo character, ref string msg) { msg = ""; if (Observers.ContainsKey(character.ID)) { msg = character.CharacterName + " is already observing the match."; return(false); } if (ObserverCountSafe + 1 > MaxObservers) { msg = "Game has no more seats available for observers. Sorry."; return(false); } return(true); }
public void SendMatchChangeNotificationToPlayer(ServerCharacterInfo toon, MatchNotificationType kind, ServerCharacterInfo targetPlayer, string text, bool synchClientGameObject) { PacketMatchNotification p = new PacketMatchNotification(); p.PacketTypeID = (int)LobbyPacketType.MatchNotification; p.Kind = kind; p.TheGame = synchClientGameObject ? Game : null; p.TheGameID = Game.GameID; if (targetPlayer != null) { p.TargetPlayer = targetPlayer.CharacterInfo; } p.ReplyCode = ReplyType.OK; p.ReplyMessage = text; SendPacketToPlayer(toon, p); }
/// <summary> /// Requests that a player be connected to the cluster server /// </summary> /// <param name="userId">the id of the account to be transferred</param> /// <param name="accountName">the name of the account to be transferred</param> /// <param name="remotePlayerEndpoint">the remote endpoint of the transferee</param> /// <param name="targetResource">the target content resource the player wants, or Guid.Empy if none</param> /// <param name="accountProperties">the account properties of the account to transfer</param> /// <param name="owningServer">the server in the cluster that owns the server. See ServerUser.Owner</param> public void RequestPlayerHandoff(Guid userId, string accountName, Guid targetResource, AccountProfile profile, ServerCharacterInfo characterToTransfer, string owningServer) { // request auth ticket from game server PacketRelayPlayerHandoffRequest p = (PacketRelayPlayerHandoffRequest)CreatePacket((int)ServerPacketType.RequestPlayerHandoff, 0, false, false); p.NeedsReply = true; p.Player = userId; p.SharedSecret = MyServer.SharedClusterServerSecret; p.AccountName = accountName; p.TargetResource = targetResource; p.Profile = profile; p.OwningServer = owningServer; p.Character = characterToTransfer; characterToTransfer.TargetResource = targetResource; Log1.Logger("Server.Inbound.Network").Info("Requesting authenticated client *" + p.AccountName + "* to be handed off to game server " + ServerUser.AccountName + "."); Send(p); }
protected override bool OnCharacterPersisting(SqlConnection con, SqlTransaction tran, ServerCharacterInfo ci) { // TrueSkill component if (ci.GetComponent<TSCharacterComponent>() == null) { TSCharacterComponent trueSkill = new TSCharacterComponent(); ci.AddComponent(trueSkill); } bool rslt = CharacterUtil.Instance.PersistNewCharacter_TSRating(ci, con, tran); if (rslt) { return base.OnCharacterPersisting(con, tran, ci); } return false; }
/// <summary> /// Gets called when a player was added to the game /// </summary> /// <param name="toon">the character that was added to the game</param> protected virtual void OnPlayerAdded(ServerCharacterInfo toon) { DB.Instance.Lobby_UpdateGameForServer(this); SendMatchChangeNotificationToPlayers(MatchNotificationType.PlayerAdded, toon, "", false); lock (m_Game.CurrentGameStateSyncRoot) { if (CurrentGameState == GameState.Lobby) { GameStartStrategy.NotifyPlayerAddedToLobby(toon); } else if (CurrentGameState == GameState.Started) { GameAbortStrategy.NotifyPlayerAddedToGame(toon); } } }
/// <summary> /// Gets the character from the DB /// </summary> /// <param name="owner">owning account</param> /// <param name="id">the id for the character to get</param> /// <returns></returns> public ServerCharacterInfo LoadCharacter(ServerUser owner, int id, ref string rsultMsg) { SqlConnection con = null; SqlTransaction tran = null; ServerCharacterInfo ci = OnCharacterObjectCreate(CreateNewCharacterShell(), owner); try { Guid cown = Guid.Empty; if (DB.Instance.Character_Load(owner.ID, ci, id, ref cown, out tran, out con)) { if (!OnCharacterLoading(con, tran, ci, ref rsultMsg)) { tran.Rollback(); } else { tran.Commit(); } } else { rsultMsg = "Character doesn't exist."; return(null); } } catch (Exception e) { return(null); } finally { if (con != null) { con.Close(); con.Dispose(); con = null; } if (tran != null) { tran.Dispose(); tran = null; } } return(ci); }
/// <summary> /// Adds a player to the passive Observers list /// </summary> /// <param name="character">the character to add</param> /// <returns></returns> public virtual bool AddObserver(ServerCharacterInfo character, ref string msg) { lock (m_Game.AllObserversSyncRoot) { if (!CanAddObserver(character, ref msg)) { return(false); } Observers.Add(character.ID, character); character.SetCurrentGame(this); AllObservers = (List <ICharacterInfo>)Observers.Values.ToList <ICharacterInfo>(); OnObserverAdded(character); } return(true); }
/// <summary> /// creates a character object, but does not persist it. /// </summary> /// <param name="properties">character properties to add</param> /// <param name="owner">the owning user</param> /// <returns></returns> public ServerCharacterInfo CreateNewCharacter(PropertyBag properties, ServerUser owner) { CharacterInfo shell = CreateNewCharacterShell(); if (properties != null) { shell.Properties.UpdateWithValues(properties); } ServerCharacterInfo ci = new ServerCharacterInfo(shell); ci.ID = NextCharId; ci.Properties = shell.Properties; ci.Stats = shell.Stats; ci.OwningAccount = owner; return(ci); }
private void OnPlayerJoinGame(INetworkConnection con, Packet gmsg) { PacketGenericMessage genMsg = gmsg as PacketGenericMessage; if (!ValidateHasCurrentCharacter()) { return; } Guid gameId = genMsg.Parms.GetGuidProperty((int)PropertyID.GameId); ServerCharacterInfo ci = ServerUser.CurrentCharacter; string address = ""; int port = 0; string name = ""; Log1.Logger(MyServer.ServerUserID).Info(string.Format("Player {0} requesting join content '{1}'...", ServerUser.AccountName, gameId.ToString())); if (DB.Instance.Lobby_GetGameServer(gameId, out address, out port, out name) && address.Length > 0 && port > 0) { Log.LogMsg(string.Format("Transferring Player {0} to join content '{1}' on server @ {2} ...", ServerUser.AccountName, gameId.ToString(), address)); PacketMatchNotification note = (PacketMatchNotification)CreatePacket((int)LobbyPacketType.MatchNotification, 0, false, false); note.Kind = MatchNotificationType.PlayerAdded; note.TargetPlayer = ci.CharacterInfo; note.Parms = genMsg.Parms; note.ReplyCode = ReplyType.OK; Send(note); ServerUser.TransferToServerUnassisted(address, port, gameId, name, name); } else { Log.LogMsg(string.Format("Player {0} failed to join content '{1}' : {2} ...", ServerUser.AccountName, gameId.ToString(), "Couldn't find game. Join canceled.")); PacketMatchNotification note = (PacketMatchNotification)CreatePacket((int)LobbyPacketType.MatchNotification, 0, false, false); note.ReplyMessage = "Game couldn't be found. Strange..."; note.Kind = MatchNotificationType.PlayerAdded; note.TargetPlayer = ci.CharacterInfo; note.Parms = genMsg.Parms; note.ReplyCode = ReplyType.Failure; genMsg.ReplyPacket = note; return; } }
/// <summary> /// Gets called when a player is removed from the game /// </summary> /// <param name="character"></param> protected virtual void OnPlayerRemoved(ServerCharacterInfo toon, string reason, bool playerInitiated) { toon.SetCurrentGame(null); // Update game stats in game listing DB DB.Instance.Lobby_UpdateGameForServer(this); // Send notification to player that player left, including game state update. Player is no longer part of "AllPlayers" list at this point, so we // have to manually send this notification to them. SendGamePropertiesUpdateToPlayer(toon, this.Properties.ID, this.Properties.AllProperties); SendMatchChangeNotificationToPlayer(toon, MatchNotificationType.PlayerRemoved, toon, reason, false); // Broadcast to all remaining players SendMatchChangeNotificationToPlayers(MatchNotificationType.PlayerRemoved, toon, reason, false); SendGamePropertiesUpdateToPlayers(this.Properties.ID, this.Properties.AllProperties); // Set new game owner if necessary if (Owner == toon.ID) { if (AllPlayers.Count > 0) { Owner = AllPlayers[0].ID; BroadcastGameInfoMessage(AllPlayers[0].CharacterName + " is now the owner of this game.", true); PropertyBag props = new PropertyBag(); props.SetProperty("NewOwner", Owner); BroadcastGameMessage((int)LobbyGameMessageSubType.NewOwner, props, true, false, false); } } // when a player leaves the game, they go back to Central if (CurrentGameState == GameState.Lobby || CurrentGameState == GameState.Started) { string address = ""; int port = 0; string serverId = ""; if (!GSLobbyInboundPlayerConnection.GetCentralHandoffAddress(ref address, ref port, ref serverId)) { toon.OwningAccount.MyConnection.KillConnection("Unable to host player on this server. No lobby server found to hand off too after leaving game."); return; } toon.OwningAccount.TransferToServerUnassisted(address, port, Guid.Empty, "Lobby Server", serverId); } }
/// <summary> /// Gracefully transfers all players to Central /// </summary> public void TransferAllPlayersToCentral(bool includeObservers, string reason) { lock (AllPlayersSyncRoot) // don't want collection being modified as we're looping over it { List <ICharacterInfo> players = AllPlayers; for (int i = 0; i < players.Count; i++) { TransferPlayerToCentral(players[i] as ServerCharacterInfo, reason); } } if (includeObservers) { for (int i = 0; i < Observers.Count; i++) { ServerCharacterInfo sci = Observers[i] as ServerCharacterInfo; TransferPlayerToCentral(sci, reason); } } }
private void OnCharacterDetailRequest(INetworkConnection con, Packet r) { Log1.Logger("Zeus.Inbound.Client").Debug("Character detail request from " + ServerUser.AccountName + "."); PacketGenericMessage msg = r as PacketGenericMessage; int id = msg.Parms.GetIntProperty(2).GetValueOrDefault(-1); WispCharacterDetail ci = new WispCharacterDetail(id); string rmsg = ""; ServerUser su = new Shared.ServerUser(); su.ID = Guid.Empty; ServerCharacterInfo sci = null; if (MyServer.RequireAuthentication) { sci = CharacterUtil.Instance.LoadCharacter(su, id, ref rmsg); } r.ReplyPacket = CreateStandardReply(r, ReplyType.OK, ""); r.ReplyPacket.ReplyMessage = rmsg; if (sci == null) { r.ReplyPacket.ReplyCode = ReplyType.Failure; r.ReplyPacket.ReplyMessage = "Character not found. " + rmsg; } else { ci.CharacterName = sci.CharacterInfo.CharacterName; ci.ID = sci.ID; ci.LastLogin = sci.LastLogin; ci.Properties = sci.Properties; ci.Stats = sci.Stats; r.ReplyPacket.Parms.SetProperty(2, ci as ISerializableWispObject); } r.ReplyPacket.Parms.SetProperty(1, MyServer.ServerUserID); }
private void OnCharacterSelectRequest(INetworkConnection con, Packet mesg) { PacketGenericMessage genMsg = mesg as PacketGenericMessage; string msg = ""; ReplyType rslt = ReplyType.OK; int id = genMsg.Parms.GetIntProperty((int)PropertyID.CharacterId).GetValueOrDefault(-1); ServerCharacterInfo ci = null; // if we don't use characters, there wont be one in the DB if (MyServer.UseCharacters) { ci = CharacterUtil.Instance.LoadCharacter(ServerUser, id, ref msg); } if (ci == null && ServerUser.CurrentCharacter != null && ServerUser.CurrentCharacter.ID == id) { ci = ServerUser.CurrentCharacter; } PacketReply rep = CreateStandardReply(genMsg, rslt, msg); //genMsg.ReplyPacket = rep; if (ci == null) { genMsg.ReplyPacket = rep; rep.ReplyCode = ReplyType.Failure; rep.ReplyMessage = "Unable to load character."; return; } ServerUser.CurrentCharacter = ci; CharacterCache.CacheCharacter(ci, MyServer.ServerUserID, TimeSpan.MaxValue); rep.Parms.SetProperty((int)PropertyID.CharacterInfo, ci.CharacterInfo as IComponent); Send(rep); // reply needs to arrive before the OnSelected event is fired, in case OnSelected results in a server transfer OnCharacterSelected(ci); }
protected override void OnConnectionReady() { base.OnConnectionReady(); // Assign default character if necessary if (!MyServer.UseCharacters) { ServerCharacterInfo ci = CharacterUtil.Instance.GetOrCreateDefaultCharacter(!MyServer.RequireAuthentication, ServerUser); if (ci == null) { // disconnect user. couldn't get or create character. Log1.Logger("Server.Character").Error("Internal server error. Couldn't get or create default character for user " + ServerUser.AccountName); KillConnection("Internal Server Error. Failed to get or create default character for user " + ServerUser.AccountName); return; } ServerUser.CurrentCharacter = ci; CharacterCache.CacheCharacter(ci, MyServer.ServerUserID, TimeSpan.MaxValue); } ServerUser.OwningServer = MyServer.ServerUserID; }
/// <summary> /// Saves/updates a character on a different thread /// </summary> /// <param name="completionCallback"></param> /// <param name="toon"></param> /// <param name="enforceUniqueName">You can change a toon's name in the DB. To ensure unique names, set to true. IMPORTANT!!!: If you are saving /// , i.e. updating an EXISTING toon without changing his name, set enforceUniqueName to FALSE - otherwise the update will fail since that /// toon's name already exists in the DB, the update will fail.</param> public void BeginSaveCharacter(Action<Task> completionCallback, ServerCharacterInfo toon, bool enforceUniqueName) { // Save character, out of band Task t = new Task((state) => { ServerCharacterInfo sci = toon as ServerCharacterInfo; if (toon != null) { string msg = ""; if (!CharacterUtil.Instance.SaveCharacter(sci.OwningAccount, sci, enforceUniqueName, ref msg)) { Log.LogMsg("Failed to save character [" + toon.CharacterName + " | " + toon.ID + "]. " + msg); } } }, "Save Player " + toon.CharacterName, TaskCreationOptions.LongRunning); if (completionCallback != null) { t.ContinueWith(completionCallback, TaskContinuationOptions.AttachedToParent); } GlobalTaskQueue.AddTask(t); }
bool CharacterUtil_CharacterSaving(SqlConnection con, SqlTransaction tran, ServerCharacterInfo ci) { return OnCharacterSaving(con, tran, ci); }
protected virtual bool OnCharacterSaving(SqlConnection con, SqlTransaction tran, ServerCharacterInfo ci) { return true; }
/// <summary> /// Gets called when the central server is requested, by an authorized source, to create a character. Add any number of Int32, Int64, String or Float Properties /// to the property bag to have them persisted as part of the new character. Return false (and probably populate @msg with a reason) to prevent character creation. /// After this method is called, all @character parts are checked against the server's Character template XML file. If any of the properties /// or stats on the character do not appear in the Character template file, character creation will fail. /// </summary> /// <param name="character">The character that will be created. Modify these properties to your liking</param> /// <param name="msg">anything you want the player to know</param> /// <returns></returns> protected virtual bool OnValidateCharacterCreateRequest(ServerCharacterInfo character, ref string msg) { return true; }
private bool CharacterUtil_CharacterPersisting(SqlConnection con, SqlTransaction tran, ServerCharacterInfo ci) { return OnCharacterPersisting(con, tran, ci); }
/// <summary> /// For clusters that don't use explicit characters, default characters are used for database tracking purposes. /// Call this method to get a reference to that default character. Method will return null if App.Config's UseCharacters /// setting is TRUE /// </summary> /// <param name="owner"></param> /// <returns></returns> public ServerCharacterInfo GetOrCreateDefaultCharacter(bool isTempCharacter, ServerUser owner) { SqlConnection con = null; SqlTransaction tran = null; try { // This cluster doesn't use characters. Create a default one for system purposes if we don't have one already ServerCharacterInfo ci = new ServerCharacterInfo(); if (!DB.Instance.Character_LoadAny(owner.ID, ci)) // see if we can fetch the current default character from the DB. { // Nope, couldn't find it. Try creating one. ci = new ServerCharacterInfo(CreateNewCharacterShell(), owner); ci.Properties.SetProperty((int)PropertyID.Name, "Mc_" + CryptoManager.GetSHA256Hash(owner.AccountName)); string msgCreate = ""; int newCharId = NextCharId; if (DB.Instance.Character_Create(owner.ID, ci.Stats, ci.Properties, (int)PropertyID.Name, ci.CharacterName, true, 1, isTempCharacter, out msgCreate, out tran, out con, out newCharId)) { ci.CharacterInfo.ID = newCharId; if (tran != null) { tran.Commit(); } return ci; } else { if (tran != null) { tran.Rollback(); } } } else // got the default character { return ci; } } catch (Exception e) { } finally { if (con != null) { con.Close(); con.Dispose(); con = null; } if (tran != null) { tran.Dispose(); tran = null; } } return null; }
public WispPlayer(ServerCharacterInfo ci) : base() { Initialize(ci); Version = 0; // Update the version of the serialize or deserialize methods have been updated. that way the correct datastream is read from the database. }
/// <summary> /// Add a character to the cache, or renew that character's expiration timer if it's already in the cache /// </summary> /// <param name="character">the character to cache</param> /// <param name="hostServer">the server hosting the character</param> public static void CacheCharacter(ServerCharacterInfo character, string hostServer) { CacheCharacter(character, hostServer, ExpirationInterval); }
public void Initialize(ServerCharacterInfo ci) { CharacterData = new ServerCharacterInfo(ci.CharacterInfo, ci.OwningAccount); }
/// <summary> /// Gets called as the character is being created in the Database. If you have additional DB tasks /// to add, now is the time. Use the supplied connection and transaction objects. The connection should already /// be open. /// Do NOT close the connection and do NOT commit /rollback the transaction. Simply return true or false if /// you want the creation to be committed or not. /// </summary> /// <param name="con">the connection object to use for additional database work in relation to character creation</param> /// <param name="tran">the transaction object to use for additional database work in relation to character creation</param> /// <returns>return false if you do not want the transaction to be committed, which will also cause character creation to fail</returns> protected virtual bool OnCharacterPersiting(SqlConnection con, SqlTransaction tran, ServerCharacterInfo ci) { if (CharacterPersisting != null) { return CharacterPersisting(con, tran, ci); } return true; }
/// <summary> /// Add a character to the cache, or renew that character's expiration timer if it's already in the cache /// </summary> /// <param name="character">the character to cache</param> /// <param name="hostServer">the server hosting the character</param> /// <param name="cacheDuration">The amount of time before the character expires from the cache</param> public static void CacheCharacter(ServerCharacterInfo character, string hostServer, TimeSpan cacheDuration) { if (character == null) { return; } CacheItem item = null; lock (m_CharacterMap) { Log1.Logger("Server.Character").Debug("Caching character [" + character.CharacterName + "|#" + character.ID + "]"); if (!m_CharacterMap.TryGetValue(character.CharacterInfo.ID, out item)) { item = new CacheItem(); m_CharacterMap.Add(character.CharacterInfo.ID, item); } item.Host = hostServer; item.Character = character; if (cacheDuration == TimeSpan.MaxValue) { item.ExpirationTime = DateTime.MaxValue; } else { try { item.ExpirationTime = DateTime.UtcNow + cacheDuration; } catch (ArgumentOutOfRangeException exc) { item.ExpirationTime = DateTime.MaxValue; } } } }
/// <summary> /// Saves/updates the character to the DB /// </summary> /// <param name="owner">owning account</param> /// <param name="id">the id for the character to get</param> /// <param name="enforceUniqueName">You can change a toon's name in the DB. To ensure unique names, set to true. IMPORTANT!!!: If you are saving /// , i.e. updating an EXISTING toon without changing his name, set enforceUniqueName to FALSE - otherwise the update will fail since that /// toon's name already exists in the DB, the update will fail.</param> /// <returns></returns> public bool SaveCharacter(ServerUser owner, ServerCharacterInfo toon, bool enforceUniqueName, ref string rsultMsg) { SqlConnection con = null; SqlTransaction tran = null; try { Guid cown = Guid.Empty; if (DB.Instance.Character_Save(owner.ID, toon, (int)PropertyID.Name, toon.CharacterName, enforceUniqueName, out rsultMsg, out tran, out con)) { if (!OnCharacterSaving(con, tran, toon, ref rsultMsg)) { tran.Rollback(); } else { tran.Commit(); } } else { if (con.State != System.Data.ConnectionState.Closed && con.State != System.Data.ConnectionState.Connecting) { if (tran != null) { tran.Rollback(); } } rsultMsg = "Can't save character. " + rsultMsg; return false; } } catch (Exception e) { } finally { if (con != null) { con.Close(); con.Dispose(); con = null; } if (tran != null) { tran.Dispose(); tran = null; } } return true; }
public void SendMatchChangeNotificationToPlayers(MatchNotificationType kind, GameServerGame theGame, ServerCharacterInfo targetPlayer) { string text = ""; switch (kind) { case MatchNotificationType.PlayerRemoved: text = "Goodbye, " + targetPlayer.CharacterName; break; case MatchNotificationType.PlayerAdded: text = "Welcome, " + targetPlayer.CharacterName; break; case MatchNotificationType.MatchEnded: text = "Game '" + theGame.Name + "' ended."; break; } theGame.SendMatchChangeNotificationToPlayers(kind, targetPlayer, text, false); }
protected virtual void OnCharacterSelected(ServerCharacterInfo toon) { }
/// <summary> /// Gets called when a character/user has successfully arrived at a remote server /// </summary> /// <param name="con">the remote server connection sending the notification</param> /// <param name="character">the character that was transferred</param> /// <param name="owner">The owner's account ID</param> protected virtual void OnCharacterHandoffComplete(INetworkConnection con, ServerCharacterInfo character, Guid owner) { }
/// <summary> /// Saves/updates a character /// </summary> /// <param name="toon"></param> /// <param name="enforceUniqueName">You can change a toon's name in the DB. To ensure unique names, set to true. IMPORTANT!!!: If you are saving /// , i.e. updating an EXISTING toon without changing his name, set enforceUniqueName to FALSE - otherwise the update will fail since that /// toon's name already exists in the DB, the update will fail.</param> public bool SaveCharacter(ServerCharacterInfo toon, ref string msg, bool enforceUniqueName) { return CharacterUtil.Instance.SaveCharacter(toon.OwningAccount, toon, enforceUniqueName, ref msg); }
protected bool OnCharacterSaving(SqlConnection con, SqlTransaction tran, ServerCharacterInfo ci, ref string msg) { if (CharacterSaving != null) { return CharacterSaving(con, tran, ci); } return true; }
protected override void OnPlayerAdded(ServerCharacterInfo toon) { base.OnPlayerAdded(toon); PlayerTurnOrder.Remove(toon.ID); PlayerTurnOrder.Add(toon.ID); }
/// <summary> /// Creates a new character in the DB using the character template XML file as a basis for stats and properties. If you want to override any of the default /// properties, pass in the appropriate characterProperties property bag. /// </summary> /// <param name="msg">an error message, if any</param> /// <returns></returns> public bool PersistNewCharacter(ServerCharacterInfo ci, ServerUser owner, ref string msg, bool isTempCharacter) { SqlConnection con = null; SqlTransaction tran = null; try { if (ValidateCharacterCreateRequest(ci, ref msg)) { int maxCharacters = (int)owner.Profile.MaxCharacters; if (maxCharacters < 1) maxCharacters = 1; int newCharId = 0; if (DB.Instance.Character_Create(owner.ID, ci.Stats, ci.Properties, (int)PropertyID.Name, ci.CharacterName, true, maxCharacters, isTempCharacter, out msg, out tran, out con, out newCharId)) { ci.CharacterInfo.ID = newCharId; if (OnCharacterPersiting(con, tran, ci)) { tran.Commit(); } else { tran.Rollback(); } return true; } else { if (con.State != System.Data.ConnectionState.Closed && con.State != System.Data.ConnectionState.Connecting) { if (tran != null) { tran.Rollback(); } } } } } catch (Exception exc) { if (con.State != System.Data.ConnectionState.Closed && con.State != System.Data.ConnectionState.Connecting) { if (tran != null) { tran.Rollback(); } } return false; } finally { if (con != null) { con.Close(); con.Dispose(); con = null; } if (tran != null) { tran.Dispose(); tran = null; } } return false; }
/// <summary> /// creates a character object, but does not persist it. /// </summary> /// <param name="properties">character properties to add</param> /// <param name="owner">the owning user</param> /// <returns></returns> public ServerCharacterInfo CreateNewCharacter(PropertyBag properties, ServerUser owner) { CharacterInfo shell = CreateNewCharacterShell(); if (properties != null) { shell.Properties.UpdateWithValues(properties); } ServerCharacterInfo ci = new ServerCharacterInfo(shell); ci.ID = NextCharId; ci.Properties = shell.Properties; ci.Stats = shell.Stats; ci.OwningAccount = owner; return ci; }