public override void SuggestInvitation(Google.ProtocolBuffers.IRpcController controller, bnet.protocol.channel_invitation.SuggestInvitationRequest request, Action <bnet.protocol.NoData> done) { var suggester = GameAccountManager.GetAccountByPersistentID(request.TargetId.Low); //wants invite var suggestee = GameAccountManager.GetAccountByPersistentID(request.ApprovalId.Low); //approves invite if (suggestee == null) { return; } Logger.Debug("{0} suggested {1} to invite him.", suggester, suggestee); var respone = bnet.protocol.NoData.CreateBuilder(); done(respone.Build()); // Even though it makes no sense, the suggester is used for all fields in the caps and is what works with the client. /dustinconrad var suggestion = bnet.protocol.invitation.Suggestion.CreateBuilder() .SetChannelId(request.ChannelId) .SetSuggesterId(suggester.BnetEntityId) .SetSuggesterName(suggester.Owner.BattleTag) .SetSuggesteeId(suggester.BnetEntityId) .SetSuggesteeName(suggester.Owner.BattleTag) .Build(); var notification = bnet.protocol.channel_invitation.SuggestionAddedNotification.CreateBuilder().SetSuggestion(suggestion); suggestee.LoggedInClient.MakeTargetedRPC(this._invitationManager, () => bnet.protocol.channel_invitation.ChannelInvitationNotify.CreateStub(suggestee.LoggedInClient).NotifyReceivedSuggestionAdded(null, notification.Build(), callback => { })); }
public override void SendReport(IRpcController controller, bnet.protocol.report.SendReportRequest request, Action <bnet.protocol.NoData> done) { Logger.Trace("SendReport()"); var report = request.Report; //TODO: Store reports against accounts foreach (var attribute in report.AttributeList) { switch (attribute.Name) { case "target_toon_id": //uint GameAccount.Low var reportee = GameAccountManager.GetAccountByPersistentID(attribute.Value.UintValue); Logger.Trace("{0} reported {1} for \"{2}\".", this.Client.Account.CurrentGameAccount.CurrentToon, reportee, report.ReportType); break; //case "target_account_id": //uint Account.Low //case "target_toon_name": //string //case "target_toon_program": //fourcc //case "target_toon_region": //string //case "note": //string - not currently used in client } } var builder = bnet.protocol.NoData.CreateBuilder(); done(builder.Build()); }
public override void Subscribe(Google.ProtocolBuffers.IRpcController controller, bnet.protocol.presence.SubscribeRequest request, System.Action <bnet.protocol.NoData> done) { switch (request.EntityId.GetHighIdType()) { case EntityIdHelper.HighIdType.AccountId: var account = AccountManager.GetAccountByPersistentID(request.EntityId.Low); if (account != null) { Logger.Trace("Subscribe() {0} {1}", this.Client, account); account.AddSubscriber(this.Client, request.ObjectId); } break; case EntityIdHelper.HighIdType.GameAccountId: var gameaccount = GameAccountManager.GetAccountByPersistentID(request.EntityId.Low); if (gameaccount != null) { Logger.Trace("Subscribe() {0} {1}", this.Client, gameaccount); gameaccount.AddSubscriber(this.Client, request.ObjectId); } break; default: Logger.Warn("Recieved an unhandled Presence.Subscribe request with type {0} (0x{1})", request.EntityId.GetHighIdType(), request.EntityId.High.ToString("X16")); break; } var builder = bnet.protocol.NoData.CreateBuilder(); done(builder.Build()); }
public void Revoke(MooNetClient client, bnet.protocol.channel_invitation.RevokeInvitationRequest request) { if (!this._onGoingInvitations.ContainsKey(request.InvitationId)) { return; } var invitation = this._onGoingInvitations[request.InvitationId]; var channel = ChannelManager.GetChannelByEntityId(request.ChannelId); //notify inviter about revoke var updateChannelNotification = bnet.protocol.channel.UpdateChannelStateNotification.CreateBuilder() .SetAgentId(bnet.protocol.EntityId.CreateBuilder().SetHigh(0).SetLow(0)) // caps have this set to high: 0 low: 0 /dustin .SetStateChange(bnet.protocol.channel.ChannelState.CreateBuilder() .AddInvitation(invitation) .SetReason((uint)InvitationRemoveReason.Revoked)); this._onGoingInvitations.Remove(request.InvitationId); client.MakeTargetedRPC(channel, () => bnet.protocol.channel.ChannelSubscriber.CreateStub(client).NotifyUpdateChannelState(null, updateChannelNotification.Build(), callback => { })); //notify invitee about revoke var invitationRemoved = bnet.protocol.channel_invitation.InvitationRemovedNotification.CreateBuilder() .SetInvitation(invitation) .SetReason((uint)InvitationRemoveReason.Revoked); var invitee = GameAccountManager.GetAccountByPersistentID(invitation.InviteeIdentity.AccountId.Low); invitee.LoggedInClient.MakeTargetedRPC(this, () => bnet.protocol.channel_invitation.ChannelInvitationNotify.CreateStub(invitee.LoggedInClient).NotifyReceivedInvitationRemoved(null, invitationRemoved.Build(), callback => { })); }
public Channel HandleAccept(MooNetClient client, bnet.protocol.channel_invitation.AcceptInvitationRequest request) { if (!this._onGoingInvitations.ContainsKey(request.InvitationId)) { return(null); } var invitation = this._onGoingInvitations[request.InvitationId]; var channel = ChannelManager.GetChannelByEntityId(invitation.GetExtension(bnet.protocol.channel_invitation.ChannelInvitation.ChannelInvitationProp).ChannelDescription.ChannelId); var notification = bnet.protocol.channel_invitation.InvitationRemovedNotification.CreateBuilder().SetInvitation(invitation.ToBuilder()).SetReason((uint)InvitationRemoveReason.Accepted); this._onGoingInvitations.Remove(invitation.Id); // notify invitee and let him remove the handled invitation. client.MakeTargetedRPC(this, () => bnet.protocol.channel_invitation.ChannelInvitationNotify.CreateStub(client).NotifyReceivedInvitationRemoved(null, notification.Build(), callback => { })); channel.Join(client, request.ObjectId); // add invitee to channel -- so inviter and other members will also be notified too. var inviter = GameAccountManager.GetAccountByPersistentID(invitation.InviterIdentity.AccountId.Low); var stateNotification = bnet.protocol.channel.UpdateChannelStateNotification.CreateBuilder() .SetAgentId(bnet.protocol.EntityId.CreateBuilder().SetHigh(0).SetLow(0).Build()) .SetStateChange(bnet.protocol.channel.ChannelState.CreateBuilder().AddRangeInvitation(channel.Invitations.Values).SetReason(0).Build()) .Build(); foreach (var member in channel.Members.Keys) { member.MakeTargetedRPC(channel, () => bnet.protocol.channel.ChannelSubscriber.CreateStub(member).NotifyUpdateChannelState(null, stateNotification, callback => { })); } return(channel); }
public void HandleDecline(MooNetClient client, bnet.protocol.invitation.GenericRequest request) { if (!this._onGoingInvitations.ContainsKey(request.InvitationId)) { return; } var invitation = this._onGoingInvitations[request.InvitationId]; var inviter = GameAccountManager.GetAccountByPersistentID(invitation.InviterIdentity.AccountId.Low); if (inviter == null || inviter.LoggedInClient == null) { return; } var notification = bnet.protocol.channel.UpdateChannelStateNotification.CreateBuilder() .SetAgentId(bnet.protocol.EntityId.CreateBuilder().SetHigh(0).SetLow(0)) // caps have this set to high: 0 low: 0 /raist. .SetStateChange(bnet.protocol.channel.ChannelState.CreateBuilder().AddInvitation(invitation) .SetReason((uint)InvitationRemoveReason.Declined)); this._onGoingInvitations.Remove(invitation.Id); // notify invoker about the decline. inviter.LoggedInClient.MakeTargetedRPC(inviter.LoggedInClient.PartyChannel, () => bnet.protocol.channel.ChannelSubscriber.CreateStub(inviter.LoggedInClient).NotifyUpdateChannelState(null, notification.Build(), callback => { })); //inviter.LoggedInClient.MakeTargetedRPC(inviter.LoggedInClient.CurrentChannel, () => // bnet.protocol.channel.ChannelSubscriber.CreateStub(inviter.LoggedInClient).NotifyUpdateChannelState(null, notification.Build(), callback => { })); }
public override void Unsubscribe(Google.ProtocolBuffers.IRpcController controller, bnet.protocol.presence.UnsubscribeRequest request, System.Action <bnet.protocol.NoData> done) { switch (request.EntityId.GetHighIdType()) { case EntityIdHelper.HighIdType.AccountId: var account = AccountManager.GetAccountByPersistentID(request.EntityId.Low); // The client will probably make sure it doesn't unsubscribe to a null ID, but just to make sure.. if (account != null) { account.RemoveSubscriber(this.Client); Logger.Trace("Unsubscribe() {0} {1}", this.Client, account); } break; case EntityIdHelper.HighIdType.GameAccountId: var gameaccount = GameAccountManager.GetAccountByPersistentID(request.EntityId.Low); if (gameaccount != null) { gameaccount.RemoveSubscriber(this.Client); Logger.Trace("Unsubscribe() {0} {1}", this.Client, gameaccount); } break; default: Logger.Warn("Recieved an unhandled Presence.Unsubscribe request with type {0} (0x{1})", request.EntityId.GetHighIdType(), request.EntityId.High.ToString("X16")); break; } var builder = bnet.protocol.NoData.CreateBuilder(); done(builder.Build()); }
public override void Update(Google.ProtocolBuffers.IRpcController controller, bnet.protocol.presence.UpdateRequest request, System.Action <bnet.protocol.NoData> done) { //Logger.Warn("request:\n{0}", request.ToString()); // This "UpdateRequest" is not, as it may seem, a request to update the client on the state of an object, // but instead the *client* requesting to change fields on an object that it has subscribed to. // Check docs/rpc/presence.txt in branch wip-docs (or master) switch (request.EntityId.GetHighIdType()) { case EntityIdHelper.HighIdType.AccountId: var account = AccountManager.GetAccountByPersistentID(request.EntityId.Low); Logger.Trace("Update() {0} {1} - {2} Operations", this.Client, account, request.FieldOperationCount); Logger.Warn("No AccountManager updater."); break; case EntityIdHelper.HighIdType.GameAccountId: var gameaccount = GameAccountManager.GetAccountByPersistentID(request.EntityId.Low); var trace = string.Format("Update() {0} {1} - {2} Operations", this.Client, gameaccount, request.FieldOperationCount); foreach (var fieldOp in request.FieldOperationList) { trace += string.Format("\t{0}, {1}, {2}", (FieldKeyHelper.Program)fieldOp.Field.Key.Program, (FieldKeyHelper.OriginatingClass)fieldOp.Field.Key.Group, fieldOp.Field.Key.Field); gameaccount.Update(fieldOp); } Logger.Trace(trace); break; default: Logger.Warn("Recieved an unhandled Presence.Update request with type {0} (0x{1})", request.EntityId.GetHighIdType(), request.EntityId.High.ToString("X16")); break; } var builder = bnet.protocol.NoData.CreateBuilder(); done(builder.Build()); }
private ByteString GetHeroProfiles(D3.GameMessage.GetHeroProfiles profiles) { Logger.Trace("GetHeroProfiles()"); var profileList = D3.Profile.HeroProfileList.CreateBuilder(); if (profiles.HeroIdsCount > 0) { foreach (var hero in profiles.HeroIdsList) { var toon = ToonManager.GetToonByLowID(hero.IdLow); profileList.AddHeros(toon.Profile); } } else { var heroList = GameAccountManager.GetAccountByPersistentID(profiles.AccountId.IdLow).Toons; foreach (var hero in heroList) { profileList.AddHeros(hero.Profile); } } return(profileList.Build().ToByteString()); }
private ByteString GetAccountProfile(D3.GameMessage.GetAccountProfile profile) { Logger.Trace("GetAccountProfile()"); var account = GameAccountManager.GetAccountByPersistentID(profile.AccountId.IdLow); return(account.Profile.ToByteString()); }
public override void SelectGameAccount(Google.ProtocolBuffers.IRpcController controller, bnet.protocol.EntityId request, Action <bnet.protocol.NoData> done) { this.Client.Account.CurrentGameAccount = GameAccountManager.GetAccountByPersistentID(request.Low); this.Client.Account.CurrentGameAccount.LoggedInClient = this.Client; Logger.Trace("SelectGameAccount(): {0}", this.Client.Account.CurrentGameAccount); done(bnet.protocol.NoData.CreateBuilder().Build()); }
private ByteString GetGameAccountSettings(D3.GameMessage.GetGameAccountSettings settings) { Logger.Trace("GetGameAccountSettings()"); var gameAccount = GameAccountManager.GetAccountByPersistentID(settings.AccountId.IdLow); return(gameAccount.Settings.ToByteString()); //var pref = D3.Client.Preferences.CreateBuilder().SetVersion(105).Build(); //hack since client is expecting this atm -Egris //return pref.ToByteString(); }
public override void RemoveMember(Google.ProtocolBuffers.IRpcController controller, bnet.protocol.channel.RemoveMemberRequest request, System.Action <bnet.protocol.NoData> done) { Logger.Trace("RemoveMember()"); var channel = ChannelManager.GetChannelByDynamicId(LastCallHeader.ObjectId); var gameAccount = GameAccountManager.GetAccountByPersistentID(request.MemberId.Low); var builder = bnet.protocol.NoData.CreateBuilder(); done(builder.Build()); channel.RemoveMember(gameAccount.LoggedInClient, Channel.GetRemoveReasonForRequest((Channel.RemoveRequestReason)request.Reason)); }
private ByteString GetHeroList(D3.GameMessage.GetHeroIds heroIds) { Logger.Trace("GetHeroList()"); var HeroList = D3.Hero.HeroList.CreateBuilder(); var gameAccount = GameAccountManager.GetAccountByPersistentID(heroIds.AccountId.IdLow); foreach (var toon in gameAccount.Toons.Values) { HeroList.AddHeroIds(toon.D3EntityID); } return(HeroList.Build().ToByteString()); }
public override void SendNotification(Google.ProtocolBuffers.IRpcController controller, bnet.protocol.notification.Notification request, Action <bnet.protocol.NoData> done) { switch (request.GetNotificationType()) { case NotificationTypeHelper.NotificationType.Whisper: // NOTE: Real implementation doesn't even handle the situation where neither client knows about the other. // Client requires prior knowledge of sender and target (and even then it cannot whisper by using the /whisper command). var targetAccount = GameAccountManager.GetAccountByPersistentID(request.TargetId.Low); Logger.Trace(string.Format("NotificationRequest.Whisper by {0} to {1}", this.Client.Account.CurrentGameAccount, targetAccount)); if (targetAccount.LoggedInClient == null) { return; } if (targetAccount == this.Client.Account.CurrentGameAccount) // check if whisper targets the account itself. { CommandManager.TryParse(request.AttributeList[0].Value.StringValue, this.Client); // try parsing it as a command and respond it if so. } else { var notification = bnet.protocol.notification.Notification.CreateBuilder(request) .SetSenderId(this.Client.Account.CurrentGameAccount.BnetEntityId) .SetSenderAccountId(this.Client.Account.BnetEntityId) .Build(); targetAccount.LoggedInClient.MakeRPC(() => bnet.protocol.notification.NotificationListener.CreateStub(targetAccount.LoggedInClient).OnNotificationReceived(controller, notification, callback => { })); } break; default: Logger.Warn("Unhandled notification type: {0}", request.Type); break; } var builder = bnet.protocol.NoData.CreateBuilder(); done(builder.Build()); }
public override void Query(Google.ProtocolBuffers.IRpcController controller, bnet.protocol.presence.QueryRequest request, Action <bnet.protocol.presence.QueryResponse> done) { var builder = bnet.protocol.presence.QueryResponse.CreateBuilder(); switch (request.EntityId.GetHighIdType()) { case EntityIdHelper.HighIdType.AccountId: var account = AccountManager.GetAccountByPersistentID(request.EntityId.Low); foreach (var key in request.KeyList) { Logger.Trace("Query() {0} {1} - {2}, {3}, {4}", this.Client, account, (FieldKeyHelper.Program)key.Program, (FieldKeyHelper.OriginatingClass)key.Group, key.Field); var field = account.QueryField(key); if (field != null) { builder.AddField(field); } } break; case EntityIdHelper.HighIdType.GameAccountId: var gameaccount = GameAccountManager.GetAccountByPersistentID(request.EntityId.Low); foreach (var key in request.KeyList) { Logger.Trace("Query() {0} {1} - {2}, {3}, {4}", this.Client, gameaccount, (FieldKeyHelper.Program)key.Program, (FieldKeyHelper.OriginatingClass)key.Group, key.Field); var field = gameaccount.QueryField(key); if (field != null) { builder.AddField(field); } } break; default: Logger.Warn("Recieved an unhandled Presence.Query request with type {0} (0x{1})", request.EntityId.GetHighIdType(), request.EntityId.High.ToString("X16")); break; } done(builder.Build()); }
public Toon(ulong persistentId, string name, int hashCode, byte @class, byte gender, byte level, long accountId, uint timePlayed, int goldAmount, Dictionary <uint, Item> items) // Toon with given persistent ID : base(persistentId) { this.HeroClassField.transformDelegate += HeroClassFieldTransform; this.SetFields(name, hashCode, (int)@class, (ToonFlags)gender, level, GameAccountManager.GetAccountByPersistentID((ulong)accountId), timePlayed, goldAmount, items); }
public Toon(ulong persistentId, string name, int hashCode, byte @class, byte gender, byte level, long accountId, uint timePlayed) // Toon with given persistent ID : base(persistentId) { this.SetFields(name, hashCode, (ToonClass)@class, (ToonFlags)gender, level, GameAccountManager.GetAccountByPersistentID((ulong)accountId), timePlayed); }
public override void SendInvitation(Google.ProtocolBuffers.IRpcController controller, bnet.protocol.invitation.SendInvitationRequest request, Action <bnet.protocol.invitation.SendInvitationResponse> done) { var invitee = GameAccountManager.GetAccountByPersistentID(request.TargetId.Low); //if (this.Client.CurrentChannel.HasMember(invitee)) return; // don't allow a second invitation if invitee is already a member of client's current channel. Logger.Debug("{0} invited {1} to his channel.", Client.Account.CurrentGameAccount.CurrentToon, invitee); // somehow protobuf lib doesnt handle this extension, so we're using a workaround to get that channelinfo. var extensionBytes = request.Params.UnknownFields.FieldDictionary[105].LengthDelimitedList[0].ToByteArray(); var channelInvitationInfo = bnet.protocol.channel_invitation.ChannelInvitationParams.ParseFrom(extensionBytes); var channel = ChannelManager.GetChannelByEntityId(channelInvitationInfo.ChannelId); var channelDescription = bnet.protocol.channel.ChannelDescription.CreateBuilder() .SetChannelId(channelInvitationInfo.ChannelId) .SetCurrentMembers((uint)channel.Members.Count) .SetState(channel.State); var channelInvitation = bnet.protocol.channel_invitation.ChannelInvitation.CreateBuilder() .SetChannelDescription(channelDescription) .SetReserved(channelInvitationInfo.Reserved) .SetServiceType(channelInvitationInfo.ServiceType) .SetRejoin(false).Build(); var invitation = bnet.protocol.invitation.Invitation.CreateBuilder(); invitation.SetId(ChannelInvitationManager.InvitationIdCounter++) .SetInviterIdentity(bnet.protocol.Identity.CreateBuilder().SetGameAccountId(Client.Account.CurrentGameAccount.BnetEntityId).Build()) .SetInviterName(Client.Account.CurrentGameAccount.Owner.BattleTag) .SetInviteeIdentity(bnet.protocol.Identity.CreateBuilder().SetGameAccountId(request.TargetId).Build()) .SetInviteeName(invitee.Owner.BattleTag) .SetInvitationMessage(request.Params.InvitationMessage) .SetCreationTime(DateTime.Now.ToExtendedEpoch()) .SetExpirationTime(DateTime.Now.ToUnixTime() + request.Params.ExpirationTime) .SetExtension(bnet.protocol.channel_invitation.ChannelInvitation.ChannelInvitationProp, channelInvitation); // oh blizz, cmon. your buggy client even doesn't care this message at all but waits the UpdateChannelStateNotification with embedded invitation proto to show "invitation sent message". // ADVICE TO POTENTIAL BLIZZ-WORKER READING THIS; // change rpc SendInvitation(.bnet.protocol.invitation.SendInvitationRequest) returns (.bnet.protocol.invitation.SendInvitationResponse); to rpc SendInvitation(.bnet.protocol.invitation.SendInvitationRequest) returns (.bnet.protocol.NoData); var builder = bnet.protocol.invitation.SendInvitationResponse.CreateBuilder(); channel.AddInvitation(invitation.Build()); if (!channel.HasMember(invitee)) { builder.SetInvitation(invitation.Clone()); // clone it because we need that invitation as un-builded below. } done(builder.Build()); // send bnet.protocol.channel.UpdateChannelStateNotification to inviter - update him on invitation is sent. var notification = bnet.protocol.channel.UpdateChannelStateNotification.CreateBuilder() .SetAgentId(Client.Account.CurrentGameAccount.BnetEntityId) .SetStateChange(bnet.protocol.channel.ChannelState.CreateBuilder().AddInvitation(invitation.Clone())); this.Client.MakeTargetedRPC(channel, () => bnet.protocol.channel.ChannelSubscriber.CreateStub(Client).NotifyUpdateChannelState(controller, notification.Build(), callback => { })); // notify the invitee on invitation. this._invitationManager.HandleInvitation(this.Client, invitation.Build()); }