/*
* Copyright (c) 2006-2008, openmetaverse.org
* All rights reserved.
*
* - Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* - Neither the name of the openmetaverse.org nor the names
* of its contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using OpenMetaverse.Packets;
namespace OpenMetaverse
{
#region Structs
///
/// Avatar group management
///
public struct GroupMember
{
/// Key of Group Member
public UUID ID;
/// Total land contribution
public int Contribution;
/// Online status information
public string OnlineStatus;
/// Abilities that the Group Member has
public GroupPowers Powers;
/// Current group title
public string Title;
/// Is a group owner
public bool IsOwner;
}
///
/// Role manager for a group
///
public struct GroupRole
{
/// Key of the group
public UUID GroupID;
/// Key of Role
public UUID ID;
/// Name of Role
public string Name;
/// Group Title associated with Role
public string Title;
/// Description of Role
public string Description;
/// Abilities Associated with Role
public GroupPowers Powers;
/// Returns the role's title
/// The role's title
public override string ToString()
{
return Name;
}
}
///
/// Class to represent Group Title
///
public struct GroupTitle
{
/// Key of the group
public UUID GroupID;
/// Group Title
public string Title;
/// Whether title is Active
public bool Selected;
}
///
/// Represents a group on the grid
///
public struct Group
{
/// Key of Group
public UUID ID;
/// Key of Group Insignia
public UUID InsigniaID;
/// Key of Group Founder
public UUID FounderID;
/// Key of Group Role for Owners
public UUID OwnerRole;
/// Name of Group
public string Name;
/// Text of Group Charter
public string Charter;
/// Title of "everyone" role
public string MemberTitle;
/// Is the group open for enrolement to everyone
public bool OpenEnrollment;
/// Will group show up in search
public bool ShowInList;
///
public GroupPowers Powers;
///
public bool AcceptNotices;
///
public bool AllowPublish;
/// Is the group Mature
public bool MaturePublish;
/// Cost of group membership
public int MembershipFee;
///
public int Money;
///
public int Contribution;
/// The total number of current members this group has
public int GroupMembershipCount;
/// The number of roles this group has configured
public int GroupRolesCount;
/// Returns the name of the group
/// A string containing the name of the group
public override string ToString()
{
return Name;
}
}
///
/// A group Vote
///
public struct Vote
{
/// Key of Avatar who created Vote
public UUID Candidate;
/// Text of the Vote proposal
public string VoteString;
/// Total number of votes
public int NumVotes;
}
///
/// A group proposal
///
public struct GroupProposal
{
/// The Text of the proposal
public string VoteText;
/// The minimum number of members that must vote before proposal passes or failes
public int Quorum;
/// The required ration of yes/no votes required for vote to pass
/// The three options are Simple Majority, 2/3 Majority, and Unanimous
/// TODO: this should be an enum
public float Majority;
/// The duration in days votes are accepted
public int Duration;
}
///
///
///
public struct GroupAccountSummary
{
///
public int IntervalDays;
///
public int CurrentInterval;
///
public string StartDate;
///
public int Balance;
///
public int TotalCredits;
///
public int TotalDebits;
///
public int ObjectTaxCurrent;
///
public int LightTaxCurrent;
///
public int LandTaxCurrent;
///
public int GroupTaxCurrent;
///
public int ParcelDirFeeCurrent;
///
public int ObjectTaxEstimate;
///
public int LightTaxEstimate;
///
public int LandTaxEstimate;
///
public int GroupTaxEstimate;
///
public int ParcelDirFeeEstimate;
///
public int NonExemptMembers;
///
public string LastTaxDate;
///
public string TaxDate;
}
///
/// Struct representing a group notice
///
public struct GroupNotice
{
///
public string Subject;
///
public string Message;
///
public UUID AttachmentID;
///
public UUID OwnerID;
///
///
///
///
public byte[] SerializeAttachment()
{
if (OwnerID == UUID.Zero || AttachmentID == UUID.Zero)
return Utils.EmptyBytes;
OpenMetaverse.StructuredData.OSDMap att = new OpenMetaverse.StructuredData.OSDMap();
att.Add("item_id", OpenMetaverse.StructuredData.OSD.FromUUID(AttachmentID));
att.Add("owner_id", OpenMetaverse.StructuredData.OSD.FromUUID(OwnerID));
return OpenMetaverse.StructuredData.OSDParser.SerializeLLSDXmlBytes(att);
/*
//I guess this is how this works, no gaurentees
string lsd = "" + AttachmentID.ToString() + ""
+ OwnerID.ToString() + "";
return Utils.StringToBytes(lsd);
*/
}
}
///
/// Struct representing a group notice list entry
///
public struct GroupNoticeList
{
/// Notice ID
public UUID NoticeID;
/// Creation timestamp of notice
public uint Timestamp;
/// Agent name who created notice
public string FromName;
/// Notice subject
public string Subject;
/// Is there an attachment?
public bool HasAttachment;
/// Attachment Type
public AssetType AssetType;
}
///
/// Struct representing a member of a group chat session and their settings
///
public struct ChatSessionMember
{
/// The of the Avatar
public UUID AvatarKey;
/// True if user has voice chat enabled
public bool CanVoiceChat;
/// True of Avatar has moderator abilities
public bool IsModerator;
/// True if a moderator has muted this avatars chat
public bool MuteText;
/// True if a moderator has muted this avatars voice
public bool MuteVoice;
}
#endregion Structs
#region Enums
///
/// Role update flags
///
public enum GroupRoleUpdate : uint
{
///
NoUpdate,
///
UpdateData,
///
UpdatePowers,
///
UpdateAll,
///
Create,
///
Delete
}
///
/// Group role powers flags
///
[Flags]
public enum GroupPowers : long
{
///
None = 0,
/// Can send invitations to groups default role
Invite = 1 << 1,
/// Can eject members from group
Eject = 1 << 2,
/// Can toggle 'Open Enrollment' and change 'Signup fee'
ChangeOptions = 1 << 3,
/// Can create new roles
CreateRole = 1 << 4,
/// Can delete existing roles
DeleteRole = 1 << 5,
/// Can change Role names, titles and descriptions
RoleProperties = 1 << 6,
/// Can assign other members to assigners role
AssignMemberLimited = 1 << 7,
/// Can assign other members to any role
AssignMember = 1 << 8,
/// Can remove members from roles
RemoveMember = 1 << 9,
/// Can assign and remove abilities in roles
ChangeActions = 1 << 10,
/// Can change group Charter, Insignia, 'Publish on the web' and which
/// members are publicly visible in group member listings
ChangeIdentity = 1 << 11,
/// Can buy land or deed land to group
LandDeed = 1 << 12,
/// Can abandon group owned land to Governor Linden on mainland, or Estate owner for
/// private estates
LandRelease = 1 << 13,
/// Can set land for-sale information on group owned parcels
LandSetSale = 1 << 14,
/// Can subdivide and join parcels
LandDivideJoin = 1 << 15,
/// Can join group chat sessions
JoinChat = 1 << 16,
/// Can toggle "Show in Find Places" and set search category
FindPlaces = 1 << 17,
/// Can change parcel name, description, and 'Publish on web' settings
LandChangeIdentity = 1 << 18,
/// Can set the landing point and teleport routing on group land
SetLandingPoint = 1 << 19,
/// Can change music and media settings
ChangeMedia = 1 << 20,
/// Can toggle 'Edit Terrain' option in Land settings
LandEdit = 1 << 21,
/// Can toggle various About Land > Options settings
LandOptions = 1 << 22,
/// Can always terraform land, even if parcel settings have it turned off
AllowEditLand = 1 << 23,
/// Can always fly while over group owned land
AllowFly = 1 << 24,
/// Can always rez objects on group owned land
AllowRez = 1 << 25,
/// Can always create landmarks for group owned parcels
AllowLandmark = 1 << 26,
/// Can use voice chat in Group Chat sessions
AllowVoiceChat = 1 << 27,
/// Can set home location on any group owned parcel
AllowSetHome = 1 << 28,
/// Can modify public access settings for group owned parcels
LandManageAllowed = 1 << 29,
/// Can manager parcel ban lists on group owned land
LandManageBanned = 1 << 30,
/// Can manage pass list sales information
LandManagePasses = 1 << 31,
/// Can eject and freeze other avatars on group owned land
LandEjectAndFreeze = 1 << 32,
/// Can return objects set to group
ReturnGroupSet = 1 << 33,
/// Can return non-group owned/set objects
ReturnNonGroup = 1 << 34,
/// Can landscape using Linden plants
LandGardening = 1 << 35,
/// Can deed objects to group
DeedObject = 1 << 36,
/// Can moderate group chat sessions
ModerateChat = 1 << 37,
/// Can move group owned objects
ObjectManipulate = 1 << 38,
/// Can set group owned objects for-sale
ObjectSetForSale = 1 << 39,
/// Pay group liabilities and receive group dividends
Accountable = 1 << 40,
/// Can send group notices
SendNotices = 1 << 42,
/// Can receive group notices
ReceiveNotices = 1 << 43,
/// Can create group proposals
StartProposal = 1 << 44,
/// Can vote on group proposals
VoteOnProposal = 1 << 45,
/// Can return group owned objects
ReturnGroupOwned = 1 << 48
}
#endregion Enums
///
/// Handles all network traffic related to reading and writing group
/// information
///
public class GroupManager
{
#region Delegates
///
/// Callback for the list of groups the avatar is currently a member of
///
/// A dictionary containing the groups an avatar is a member of,
/// where the Key is the group , and the values are the groups
public delegate void CurrentGroupsCallback(Dictionary groups);
///
/// Callback for a list of group names
///
/// A dictionary containing the the group names requested
/// where the Key is the group , and the values are the names
public delegate void GroupNamesCallback(Dictionary groupNames);
///
/// Callback for the profile of a group
///
/// The group profile
public delegate void GroupProfileCallback(Group group);
///
/// Callback for the member list of a group
///
/// A dictionary containing the members of a group
/// where the Key is the group , and the values are the members
public delegate void GroupMembersCallback(Dictionary members);
///
/// Callback for the role list of a group
///
/// A dictionary containing the roles of a group
/// where the Key is the group , and the values are the roles
public delegate void GroupRolesCallback(Dictionary roles);
///
/// Callback for a pairing of roles to members
///
/// A List of Keyvalue pairs containing the role ID and the members assigned to
/// that role
public delegate void GroupRolesMembersCallback(List> rolesMembers);
///
/// Callback for the title list of a group
///
/// A dictionary containing the titles of a group
/// where the Key is the group , and the values are the title details
public delegate void GroupTitlesCallback(Dictionary titles);
///
/// Callback fired when group account summary information is received
///
/// The group account summary information
public delegate void GroupAccountSummaryCallback(GroupAccountSummary summary);
///
/// Callback fired after an attempt to create a group
///
/// The new groups
/// True of creation was successful
/// A string, containing a message from the simulator
public delegate void GroupCreatedCallback(UUID groupID, bool success, string message);
///
/// Callback fired when the avatar has joined a group
///
/// The of the group joined
/// True if the join was successful
public delegate void GroupJoinedCallback(UUID groupID, bool success);
///
/// Callback fired when the avatar leaves a group
///
/// The of the group joined
/// True if the part was successful
public delegate void GroupLeftCallback(UUID groupID, bool success);
///
/// Fired when a group is dropped, likely because it did not keep the required (2) avatar
/// minimum
///
/// The of the group which was dropped
public delegate void GroupDroppedCallback(UUID groupID);
///
/// Fired when a member of a group is ejected,
/// Does not provide member information, only
/// group ID and whether it was successful or not
///
/// The Group UUID the member was ejected from
/// true of member was successfully ejected
public delegate void GroupMemberEjectedCallback(UUID groupID, bool success);
///
/// Fired when the list of group notices is recievied
///
/// The of the group for which the notice list entry was recievied
/// The Notice list entry
public delegate void GroupNoticesListCallback(UUID groupID, GroupNoticeList notice);
#endregion Delegates
#region Events
/// Fired when a is received, contains a list of
/// groups avatar is currently a member of
public event CurrentGroupsCallback OnCurrentGroups;
/// Fired when a UUIDGroupNameReply packet is receiived,
/// contains name of group requested
public event GroupNamesCallback OnGroupNames;
/// Fired when a GroupProfileReply packet is received,
/// contains group profile information for requested group.
public event GroupProfileCallback OnGroupProfile;
/// Fired when a GroupMembersReply packet is received,
/// contains a list of group members for requested group
public event GroupMembersCallback OnGroupMembers;
/// Fired when a GroupRoleDataReply packet is received,
/// contains details on roles for requested group
public event GroupRolesCallback OnGroupRoles;
/// Fired when a is received,
/// Contains group member to group role mappings
public event GroupRolesMembersCallback OnGroupRolesMembers;
/// Fired when a GroupTitlesReply packet is received,
/// sets the active role title for the current Agent
public event GroupTitlesCallback OnGroupTitles;
/// Fired when a GroupAccountSummaryReply packet is received,
/// Contains a summary of group financial information
public event GroupAccountSummaryCallback OnGroupAccountSummary;
/// Fired when a CreateGroupReply packet is received, indicates
/// the successful creation of a new group
public event GroupCreatedCallback OnGroupCreated;
/// Fired when a JoinGroupReply packet is received, indicates
/// the Avatar has successfully joined a new group either by
/// or by accepting a group join invitation with
public event GroupJoinedCallback OnGroupJoined;
/// Fired when a LeaveGroupReply packet is received, indicates
/// the Avatar has successfully left a group
///
public event GroupLeftCallback OnGroupLeft;
/// Fired when a AgentDropGroup packet is received, contains
/// the of the group dropped
public event GroupDroppedCallback OnGroupDropped;
/// Fired when a GroupMemberEjected packet is received,
/// indicates a member of a group has been ejected
public event GroupMemberEjectedCallback OnGroupMemberEjected;
/// Fired when the list of group notices is recievied
public event GroupNoticesListCallback OnGroupNoticesList;
#endregion Events
/// A reference to the current instance
private GridClient Client;
/// Currently-active group members requests
private List GroupMembersRequests;
/// Currently-active group roles requests
private List GroupRolesRequests;
/// Currently-active group role-member requests
private List GroupRolesMembersRequests;
/// A list of all the lists of group members, indexed by the group ID
public InternalDictionary> GroupMembersCaches;
/// A list of all the lists of group roles, indexed by the group ID
public InternalDictionary> GroupRolesCaches;
/// A list of all the role to member mappings, indexed by the group ID
public InternalDictionary>> GroupRolesMembersCaches;
/// Caches group name lookups
public InternalDictionary GroupName2KeyCache;
///
/// Group Management Routines, Methods and Packet Handlers
///
/// A reference to the current instance
public GroupManager(GridClient client)
{
Client = client;
GroupMembersCaches = new InternalDictionary>();
GroupMembersRequests = new List();
GroupRolesCaches = new InternalDictionary>();
GroupRolesRequests = new List();
GroupRolesMembersCaches = new InternalDictionary>>();
GroupRolesMembersRequests = new List();
GroupName2KeyCache = new InternalDictionary();
Client.Network.RegisterCallback(PacketType.AgentGroupDataUpdate, new NetworkManager.PacketCallback(GroupDataHandler));
Client.Network.RegisterCallback(PacketType.AgentDropGroup, new NetworkManager.PacketCallback(AgentDropGroupHandler));
Client.Network.RegisterCallback(PacketType.GroupTitlesReply, new NetworkManager.PacketCallback(GroupTitlesHandler));
Client.Network.RegisterCallback(PacketType.GroupProfileReply, new NetworkManager.PacketCallback(GroupProfileHandler));
Client.Network.RegisterCallback(PacketType.GroupMembersReply, new NetworkManager.PacketCallback(GroupMembersHandler));
Client.Network.RegisterCallback(PacketType.GroupRoleDataReply, new NetworkManager.PacketCallback(GroupRoleDataHandler));
Client.Network.RegisterCallback(PacketType.GroupRoleMembersReply, new NetworkManager.PacketCallback(GroupRoleMembersHandler));
Client.Network.RegisterCallback(PacketType.GroupActiveProposalItemReply, new NetworkManager.PacketCallback(GroupActiveProposalItemHandler));
Client.Network.RegisterCallback(PacketType.GroupVoteHistoryItemReply, new NetworkManager.PacketCallback(GroupVoteHistoryItemHandler));
Client.Network.RegisterCallback(PacketType.GroupAccountSummaryReply, new NetworkManager.PacketCallback(GroupAccountSummaryHandler));
Client.Network.RegisterCallback(PacketType.CreateGroupReply, new NetworkManager.PacketCallback(CreateGroupReplyHandler));
Client.Network.RegisterCallback(PacketType.JoinGroupReply, new NetworkManager.PacketCallback(JoinGroupReplyHandler));
Client.Network.RegisterCallback(PacketType.LeaveGroupReply, new NetworkManager.PacketCallback(LeaveGroupReplyHandler));
Client.Network.RegisterCallback(PacketType.UUIDGroupNameReply, new NetworkManager.PacketCallback(UUIDGroupNameReplyHandler));
Client.Network.RegisterCallback(PacketType.EjectGroupMemberReply, new NetworkManager.PacketCallback(EjectGroupMemberReplyHandler));
Client.Network.RegisterCallback(PacketType.GroupNoticesListReply, new NetworkManager.PacketCallback(GroupNoticesListReplyHandler));
}
///
/// Request a current list of groups the avatar is a member of.
///
/// CAPS Event Queue must be running for this to work since the results
/// come across CAPS.
public void RequestCurrentGroups()
{
AgentDataUpdateRequestPacket request = new AgentDataUpdateRequestPacket();
request.AgentData.AgentID = Client.Self.AgentID;
request.AgentData.SessionID = Client.Self.SessionID;
Client.Network.SendPacket(request);
}
///
/// Lookup name of group based on groupID
///
/// groupID of group to lookup name for.
public void RequestGroupName(UUID groupID)
{
// if we already have this in the cache, return from cache instead of making a request
if (GroupName2KeyCache.ContainsKey(groupID))
{
Dictionary groupNames = new Dictionary();
lock(GroupName2KeyCache.Dictionary)
groupNames.Add(groupID, GroupName2KeyCache.Dictionary[groupID]);
if (OnGroupNames != null)
{
try { OnGroupNames(groupNames); }
catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
}
}
else
{
UUIDGroupNameRequestPacket req = new UUIDGroupNameRequestPacket();
UUIDGroupNameRequestPacket.UUIDNameBlockBlock[] block = new UUIDGroupNameRequestPacket.UUIDNameBlockBlock[1];
block[0] = new UUIDGroupNameRequestPacket.UUIDNameBlockBlock();
block[0].ID = groupID;
req.UUIDNameBlock = block;
Client.Network.SendPacket(req);
}
}
///
/// Request lookup of multiple group names
///
/// List of group IDs to request.
public void RequestGroupNames(List groupIDs)
{
Dictionary groupNames = new Dictionary();
lock (GroupName2KeyCache.Dictionary)
{
foreach (UUID groupID in groupIDs)
{
if (GroupName2KeyCache.ContainsKey(groupID))
groupNames[groupID] = GroupName2KeyCache.Dictionary[groupID];
}
}
if (groupIDs.Count > 0)
{
UUIDGroupNameRequestPacket req = new UUIDGroupNameRequestPacket();
UUIDGroupNameRequestPacket.UUIDNameBlockBlock[] block = new UUIDGroupNameRequestPacket.UUIDNameBlockBlock[groupIDs.Count];
for (int i = 0; i < groupIDs.Count; i++)
{
block[i] = new UUIDGroupNameRequestPacket.UUIDNameBlockBlock();
block[i].ID = groupIDs[i];
}
req.UUIDNameBlock = block;
Client.Network.SendPacket(req);
}
// fire handler from cache
if(groupNames.Count > 0 && OnGroupNames != null)
try { OnGroupNames(groupNames); }
catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
}
/// Lookup group profile data such as name, enrollment, founder, logo, etc
/// Subscribe to OnGroupProfile event to receive the results.
/// group ID (UUID)
public void RequestGroupProfile(UUID group)
{
GroupProfileRequestPacket request = new GroupProfileRequestPacket();
request.AgentData.AgentID = Client.Self.AgentID;
request.AgentData.SessionID = Client.Self.SessionID;
request.GroupData.GroupID = group;
Client.Network.SendPacket(request);
}
/// Request a list of group members.
/// Subscribe to OnGroupMembers event to receive the results.
/// group ID (UUID)
/// UUID of the request, use to index into cache
public UUID RequestGroupMembers(UUID group)
{
UUID requestID = UUID.Random();
lock (GroupMembersRequests) GroupMembersRequests.Add(requestID);
GroupMembersRequestPacket request = new GroupMembersRequestPacket();
request.AgentData.AgentID = Client.Self.AgentID;
request.AgentData.SessionID = Client.Self.SessionID;
request.GroupData.GroupID = group;
request.GroupData.RequestID = requestID;
Client.Network.SendPacket(request);
return requestID;
}
/// Request group roles
/// Subscribe to OnGroupRoles event to receive the results.
/// group ID (UUID)
/// UUID of the request, use to index into cache
public UUID RequestGroupRoles(UUID group)
{
UUID requestID = UUID.Random();
lock (GroupRolesRequests) GroupRolesRequests.Add(requestID);
GroupRoleDataRequestPacket request = new GroupRoleDataRequestPacket();
request.AgentData.AgentID = Client.Self.AgentID;
request.AgentData.SessionID = Client.Self.SessionID;
request.GroupData.GroupID = group;
request.GroupData.RequestID = requestID;
Client.Network.SendPacket(request);
return requestID;
}
/// Request members (members,role) role mapping for a group.
/// Subscribe to OnGroupRolesMembers event to receive the results.
/// group ID (UUID)
/// UUID of the request, use to index into cache
public UUID RequestGroupRoleMembers(UUID group)
{
UUID requestID = UUID.Random();
lock (GroupRolesRequests) GroupRolesMembersRequests.Add(requestID);
GroupRoleMembersRequestPacket request = new GroupRoleMembersRequestPacket();
request.AgentData.AgentID = Client.Self.AgentID;
request.AgentData.SessionID = Client.Self.SessionID;
request.GroupData.GroupID = group;
request.GroupData.RequestID = requestID;
Client.Network.SendPacket(request);
return requestID;
}
/// Request a groups Titles
/// Subscribe to OnGroupTitles event to receive the results.
/// group ID (UUID)
/// UUID of the request, use to index into cache
public UUID RequestGroupTitles(UUID group)
{
UUID requestID = UUID.Random();
GroupTitlesRequestPacket request = new GroupTitlesRequestPacket();
request.AgentData.AgentID = Client.Self.AgentID;
request.AgentData.SessionID = Client.Self.SessionID;
request.AgentData.GroupID = group;
request.AgentData.RequestID = requestID;
Client.Network.SendPacket(request);
return requestID;
}
/// Begin to get the group account summary
/// Subscribe to the OnGroupAccountSummary event to receive the results.
/// group ID (UUID)
/// How long of an interval
/// Which interval (0 for current, 1 for last)
public void RequestGroupAccountSummary(UUID group, int intervalDays, int currentInterval)
{
GroupAccountSummaryRequestPacket p = new GroupAccountSummaryRequestPacket();
p.AgentData.AgentID = Client.Self.AgentID;
p.AgentData.SessionID = Client.Self.SessionID;
p.AgentData.GroupID = group;
p.MoneyData.RequestID = UUID.Random();
p.MoneyData.CurrentInterval = currentInterval;
p.MoneyData.IntervalDays = intervalDays;
Client.Network.SendPacket(p);
}
/// Invites a user to a group
/// The group to invite to
/// A list of roles to invite a person to
/// Key of person to invite
public void Invite(UUID group, List roles, UUID personkey)
{
InviteGroupRequestPacket igp = new InviteGroupRequestPacket();
igp.AgentData = new InviteGroupRequestPacket.AgentDataBlock();
igp.AgentData.AgentID = Client.Self.AgentID;
igp.AgentData.SessionID = Client.Self.SessionID;
igp.GroupData = new InviteGroupRequestPacket.GroupDataBlock();
igp.GroupData.GroupID = group;
igp.InviteData = new InviteGroupRequestPacket.InviteDataBlock[roles.Count];
for (int i = 0; i < roles.Count; i++)
{
igp.InviteData[i] = new InviteGroupRequestPacket.InviteDataBlock();
igp.InviteData[i].InviteeID = personkey;
igp.InviteData[i].RoleID = roles[i];
}
Client.Network.SendPacket(igp);
}
/// Set a group as the current active group
/// group ID (UUID)
public void ActivateGroup(UUID id)
{
ActivateGroupPacket activate = new ActivateGroupPacket();
activate.AgentData.AgentID = Client.Self.AgentID;
activate.AgentData.SessionID = Client.Self.SessionID;
activate.AgentData.GroupID = id;
Client.Network.SendPacket(activate);
}
/// Change the role that determines your active title
/// Group ID to use
/// Role ID to change to
public void ActivateTitle(UUID group, UUID role)
{
GroupTitleUpdatePacket gtu = new GroupTitleUpdatePacket();
gtu.AgentData.AgentID = Client.Self.AgentID;
gtu.AgentData.SessionID = Client.Self.SessionID;
gtu.AgentData.TitleRoleID = role;
gtu.AgentData.GroupID = group;
Client.Network.SendPacket(gtu);
}
/// Set this avatar's tier contribution
/// Group ID to change tier in
/// amount of tier to donate
public void SetGroupContribution(UUID group, int contribution)
{
SetGroupContributionPacket sgp = new SetGroupContributionPacket();
sgp.AgentData.AgentID = Client.Self.AgentID;
sgp.AgentData.SessionID = Client.Self.SessionID;
sgp.Data.GroupID = group;
sgp.Data.Contribution = contribution;
Client.Network.SendPacket(sgp);
}
/// Request to join a group
/// Subscribe to OnGroupJoined event for confirmation.
/// group ID (UUID) to join.
public void RequestJoinGroup(UUID id)
{
JoinGroupRequestPacket join = new JoinGroupRequestPacket();
join.AgentData.AgentID = Client.Self.AgentID;
join.AgentData.SessionID = Client.Self.SessionID;
join.GroupData.GroupID = id;
Client.Network.SendPacket(join);
}
///
/// Request to create a new group. If the group is successfully
/// created, L$100 will automatically be deducted
///
/// Subscribe to OnGroupCreated event to receive confirmation.
/// Group struct containing the new group info
public void RequestCreateGroup(Group group)
{
OpenMetaverse.Packets.CreateGroupRequestPacket cgrp = new CreateGroupRequestPacket();
cgrp.AgentData = new CreateGroupRequestPacket.AgentDataBlock();
cgrp.AgentData.AgentID = Client.Self.AgentID;
cgrp.AgentData.SessionID = Client.Self.SessionID;
cgrp.GroupData = new CreateGroupRequestPacket.GroupDataBlock();
cgrp.GroupData.AllowPublish = group.AllowPublish;
cgrp.GroupData.Charter = Utils.StringToBytes(group.Charter);
cgrp.GroupData.InsigniaID = group.InsigniaID;
cgrp.GroupData.MaturePublish = group.MaturePublish;
cgrp.GroupData.MembershipFee = group.MembershipFee;
cgrp.GroupData.Name = Utils.StringToBytes(group.Name);
cgrp.GroupData.OpenEnrollment = group.OpenEnrollment;
cgrp.GroupData.ShowInList = group.ShowInList;
Client.Network.SendPacket(cgrp);
}
/// Update a group's profile and other information
/// Groups ID (UUID) to update.
/// Group struct to update.
public void UpdateGroup(UUID id, Group group)
{
OpenMetaverse.Packets.UpdateGroupInfoPacket cgrp = new UpdateGroupInfoPacket();
cgrp.AgentData = new UpdateGroupInfoPacket.AgentDataBlock();
cgrp.AgentData.AgentID = Client.Self.AgentID;
cgrp.AgentData.SessionID = Client.Self.SessionID;
cgrp.GroupData = new UpdateGroupInfoPacket.GroupDataBlock();
cgrp.GroupData.GroupID = id;
cgrp.GroupData.AllowPublish = group.AllowPublish;
cgrp.GroupData.Charter = Utils.StringToBytes(group.Charter);
cgrp.GroupData.InsigniaID = group.InsigniaID;
cgrp.GroupData.MaturePublish = group.MaturePublish;
cgrp.GroupData.MembershipFee = group.MembershipFee;
cgrp.GroupData.OpenEnrollment = group.OpenEnrollment;
cgrp.GroupData.ShowInList = group.ShowInList;
Client.Network.SendPacket(cgrp);
}
/// Eject a user from a group
/// Group ID to eject the user from
/// Avatar's key to eject
public void EjectUser(UUID group, UUID member)
{
OpenMetaverse.Packets.EjectGroupMemberRequestPacket eject = new EjectGroupMemberRequestPacket();
eject.AgentData = new EjectGroupMemberRequestPacket.AgentDataBlock();
eject.AgentData.AgentID = Client.Self.AgentID;
eject.AgentData.SessionID = Client.Self.SessionID;
eject.GroupData = new EjectGroupMemberRequestPacket.GroupDataBlock();
eject.GroupData.GroupID = group;
eject.EjectData = new EjectGroupMemberRequestPacket.EjectDataBlock[1];
eject.EjectData[0] = new EjectGroupMemberRequestPacket.EjectDataBlock();
eject.EjectData[0].EjecteeID = member;
Client.Network.SendPacket(eject);
}
/// Update role information
/// Modified role to be updated
public void UpdateRole(GroupRole role)
{
OpenMetaverse.Packets.GroupRoleUpdatePacket gru = new GroupRoleUpdatePacket();
gru.AgentData.AgentID = Client.Self.AgentID;
gru.AgentData.SessionID = Client.Self.SessionID;
gru.AgentData.GroupID = role.GroupID;
gru.RoleData = new GroupRoleUpdatePacket.RoleDataBlock[1];
gru.RoleData[0] = new GroupRoleUpdatePacket.RoleDataBlock();
gru.RoleData[0].Name = Utils.StringToBytes(role.Name);
gru.RoleData[0].Description = Utils.StringToBytes(role.Description);
gru.RoleData[0].Powers = (ulong)role.Powers;
gru.RoleData[0].RoleID = role.ID;
gru.RoleData[0].Title = Utils.StringToBytes(role.Title);
gru.RoleData[0].UpdateType = (byte)GroupRoleUpdate.UpdateAll;
Client.Network.SendPacket(gru);
}
/// Create a new group role
/// Group ID to update
/// Role to create
public void CreateRole(UUID group, GroupRole role)
{
OpenMetaverse.Packets.GroupRoleUpdatePacket gru = new GroupRoleUpdatePacket();
gru.AgentData.AgentID = Client.Self.AgentID;
gru.AgentData.SessionID = Client.Self.SessionID;
gru.AgentData.GroupID = group;
gru.RoleData = new GroupRoleUpdatePacket.RoleDataBlock[1];
gru.RoleData[0].Name = Utils.StringToBytes(role.Name);
gru.RoleData[0].Description = Utils.StringToBytes(role.Description);
gru.RoleData[0].Powers = (ulong)role.Powers;
gru.RoleData[0].Title = Utils.StringToBytes(role.Title);
gru.RoleData[0].UpdateType = (byte)GroupRoleUpdate.Create;
Client.Network.SendPacket(gru);
}
/// Remove an avatar from a role
/// Group ID to update
/// Role ID to be removed from
/// Avatar's Key to remove
public void RemoveFromRole(UUID group, UUID role, UUID member)
{
OpenMetaverse.Packets.GroupRoleChangesPacket grc = new GroupRoleChangesPacket();
grc.AgentData.AgentID = Client.Self.AgentID;
grc.AgentData.SessionID = Client.Self.SessionID;
grc.AgentData.GroupID = group;
grc.RoleChange = new GroupRoleChangesPacket.RoleChangeBlock[1];
grc.RoleChange[0] = new GroupRoleChangesPacket.RoleChangeBlock();
//Add to members and role
grc.RoleChange[0].MemberID = member;
grc.RoleChange[0].RoleID = role;
//1 = Remove From Role TODO: this should be in an enum
grc.RoleChange[0].Change = 1;
Client.Network.SendPacket(grc);
}
/// Assign an avatar to a role
/// Group ID to update
/// Role ID to assign to
/// Avatar's ID to assign to role
public void AddToRole(UUID group, UUID role, UUID member)
{
OpenMetaverse.Packets.GroupRoleChangesPacket grc = new GroupRoleChangesPacket();
grc.AgentData.AgentID = Client.Self.AgentID;
grc.AgentData.SessionID = Client.Self.SessionID;
grc.AgentData.GroupID = group;
grc.RoleChange = new GroupRoleChangesPacket.RoleChangeBlock[1];
grc.RoleChange[0] = new GroupRoleChangesPacket.RoleChangeBlock();
//Add to members and role
grc.RoleChange[0].MemberID = member;
grc.RoleChange[0].RoleID = role;
//0 = Add to Role TODO: this should be in an enum
grc.RoleChange[0].Change = 0;
Client.Network.SendPacket(grc);
}
/// Request the group notices list
/// Group ID to fetch notices for
public void RequestGroupNoticeList(UUID group)
{
OpenMetaverse.Packets.GroupNoticesListRequestPacket gnl = new GroupNoticesListRequestPacket();
gnl.AgentData.AgentID = Client.Self.AgentID;
gnl.AgentData.SessionID = Client.Self.SessionID;
gnl.Data.GroupID = group;
Client.Network.SendPacket(gnl);
}
/// Request a group notice by key
/// ID of group notice
public void RequestGroupNotice(UUID noticeID)
{
OpenMetaverse.Packets.GroupNoticeRequestPacket gnr = new GroupNoticeRequestPacket();
gnr.AgentData.AgentID = Client.Self.AgentID;
gnr.AgentData.SessionID = Client.Self.SessionID;
gnr.Data.GroupNoticeID = noticeID;
Client.Network.SendPacket(gnr);
}
private void GroupNoticesListReplyHandler(Packet packet, Simulator simulator)
{
GroupNoticesListReplyPacket reply = (GroupNoticesListReplyPacket)packet;
foreach (GroupNoticesListReplyPacket.DataBlock entry in reply.Data)
{
GroupNoticeList notice = new GroupNoticeList();
notice.FromName = Utils.BytesToString(entry.FromName);
notice.Subject = Utils.BytesToString(entry.Subject);
notice.NoticeID = entry.NoticeID;
notice.Timestamp = entry.Timestamp;
notice.HasAttachment = entry.HasAttachment;
notice.AssetType = (AssetType)entry.AssetType;
if (OnGroupNoticesList != null)
{
try { OnGroupNoticesList(reply.AgentData.GroupID, notice); }
catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
}
}
}
/// Send out a group notice
/// Group ID to update
/// GroupNotice structure containing notice data
public void SendGroupNotice(UUID group, GroupNotice notice)
{
Client.Self.InstantMessage(Client.Self.Name, group, notice.Subject + "|" + notice.Message,
UUID.Zero, InstantMessageDialog.GroupNotice, InstantMessageOnline.Online,
Vector3.Zero, UUID.Zero, notice.SerializeAttachment());
}
/// Start a group proposal (vote)
/// The Group ID to send proposal to
/// GroupProposal structure containing the proposal
public void StartProposal(UUID group, GroupProposal prop)
{
StartGroupProposalPacket p = new StartGroupProposalPacket();
p.AgentData.AgentID = Client.Self.AgentID;
p.AgentData.SessionID = Client.Self.SessionID;
p.ProposalData.GroupID = group;
p.ProposalData.ProposalText = Utils.StringToBytes(prop.VoteText);
p.ProposalData.Quorum = prop.Quorum;
p.ProposalData.Majority = prop.Majority;
p.ProposalData.Duration = prop.Duration;
Client.Network.SendPacket(p);
}
/// Request to leave a group
/// Subscribe to OnGroupLeft event to receive confirmation
/// The group to leave
public void LeaveGroup(UUID groupID)
{
LeaveGroupRequestPacket p = new LeaveGroupRequestPacket();
p.AgentData.AgentID = Client.Self.AgentID;
p.AgentData.SessionID = Client.Self.SessionID;
p.GroupData.GroupID = groupID;
Client.Network.SendPacket(p);
}
#region Packet Handlers
private void GroupDataHandler(Packet packet, Simulator simulator)
{
if (OnCurrentGroups != null)
{
AgentGroupDataUpdatePacket update = (AgentGroupDataUpdatePacket)packet;
Dictionary currentGroups = new Dictionary();
foreach (AgentGroupDataUpdatePacket.GroupDataBlock block in update.GroupData)
{
Group group = new Group();
group.ID = block.GroupID;
group.InsigniaID = block.GroupInsigniaID;
group.Name = Utils.BytesToString(block.GroupName);
group.Powers = (GroupPowers)block.GroupPowers;
group.Contribution = block.Contribution;
group.AcceptNotices = block.AcceptNotices;
currentGroups[block.GroupID] = group;
lock (GroupName2KeyCache.Dictionary)
{
if (!GroupName2KeyCache.Dictionary.ContainsKey(block.GroupID))
GroupName2KeyCache.Dictionary.Add(block.GroupID, Utils.BytesToString(block.GroupName));
}
}
try { OnCurrentGroups(currentGroups); }
catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
}
}
private void AgentDropGroupHandler(Packet packet, Simulator simulator)
{
if (OnGroupDropped != null)
{
try { OnGroupDropped(((AgentDropGroupPacket)packet).AgentData.GroupID); }
catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
}
}
private void GroupProfileHandler(Packet packet, Simulator simulator)
{
if (OnGroupProfile != null)
{
GroupProfileReplyPacket profile = (GroupProfileReplyPacket)packet;
Group group = new Group();
group.ID = profile.GroupData.GroupID;
group.AllowPublish = profile.GroupData.AllowPublish;
group.Charter = Utils.BytesToString(profile.GroupData.Charter);
group.FounderID = profile.GroupData.FounderID;
group.GroupMembershipCount = profile.GroupData.GroupMembershipCount;
group.GroupRolesCount = profile.GroupData.GroupRolesCount;
group.InsigniaID = profile.GroupData.InsigniaID;
group.MaturePublish = profile.GroupData.MaturePublish;
group.MembershipFee = profile.GroupData.MembershipFee;
group.MemberTitle = Utils.BytesToString(profile.GroupData.MemberTitle);
group.Money = profile.GroupData.Money;
group.Name = Utils.BytesToString(profile.GroupData.Name);
group.OpenEnrollment = profile.GroupData.OpenEnrollment;
group.OwnerRole = profile.GroupData.OwnerRole;
group.Powers = (GroupPowers)profile.GroupData.PowersMask;
group.ShowInList = profile.GroupData.ShowInList;
try { OnGroupProfile(group); }
catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
}
}
private void GroupTitlesHandler(Packet packet, Simulator simulator)
{
if (OnGroupTitles != null)
{
GroupTitlesReplyPacket titles = (GroupTitlesReplyPacket)packet;
Dictionary groupTitleCache = new Dictionary();
foreach (GroupTitlesReplyPacket.GroupDataBlock block in titles.GroupData)
{
GroupTitle groupTitle = new GroupTitle();
groupTitle.GroupID = titles.AgentData.GroupID;
groupTitle.Title = Utils.BytesToString(block.Title);
groupTitle.Selected = block.Selected;
groupTitleCache[block.RoleID] = groupTitle;
}
try { OnGroupTitles(groupTitleCache); }
catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
}
}
private void GroupMembersHandler(Packet packet, Simulator simulator)
{
GroupMembersReplyPacket members = (GroupMembersReplyPacket)packet;
Dictionary groupMemberCache = null;
lock (GroupMembersRequests)
{
// If nothing is registered to receive this RequestID drop the data
if (GroupMembersRequests.Contains(members.GroupData.RequestID))
{
lock (GroupMembersCaches)
{
if (!GroupMembersCaches.TryGetValue(members.GroupData.RequestID, out groupMemberCache))
{
groupMemberCache = new Dictionary();
GroupMembersCaches[members.GroupData.RequestID] = groupMemberCache;
}
foreach (GroupMembersReplyPacket.MemberDataBlock block in members.MemberData)
{
GroupMember groupMember = new GroupMember();
groupMember.ID = block.AgentID;
groupMember.Contribution = block.Contribution;
groupMember.IsOwner = block.IsOwner;
groupMember.OnlineStatus = Utils.BytesToString(block.OnlineStatus);
groupMember.Powers = (GroupPowers)block.AgentPowers;
groupMember.Title = Utils.BytesToString(block.Title);
groupMemberCache[block.AgentID] = groupMember;
}
if(groupMemberCache.Count >= members.GroupData.MemberCount)
GroupMembersRequests.Remove(members.GroupData.RequestID);
}
}
}
// Check if we've received all the group members that are showing up
if (OnGroupMembers != null && groupMemberCache != null && groupMemberCache.Count >= members.GroupData.MemberCount)
{
try { OnGroupMembers(groupMemberCache); }
catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
}
}
private void GroupRoleDataHandler(Packet packet, Simulator simulator)
{
GroupRoleDataReplyPacket roles = (GroupRoleDataReplyPacket)packet;
Dictionary groupRoleCache = null;
lock (GroupRolesRequests)
{
// If nothing is registered to receive this RequestID drop the data
if (GroupRolesRequests.Contains(roles.GroupData.RequestID))
{
GroupRolesRequests.Remove(roles.GroupData.RequestID);
lock (GroupRolesCaches)
{
if (!GroupRolesCaches.TryGetValue(roles.GroupData.GroupID, out groupRoleCache))
{
groupRoleCache = new Dictionary();
GroupRolesCaches[roles.GroupData.GroupID] = groupRoleCache;
}
foreach (GroupRoleDataReplyPacket.RoleDataBlock block in roles.RoleData)
{
GroupRole groupRole = new GroupRole();
groupRole.GroupID = roles.GroupData.GroupID;
groupRole.ID = block.RoleID;
groupRole.Description = Utils.BytesToString(block.Description);
groupRole.Name = Utils.BytesToString(block.Name);
groupRole.Powers = (GroupPowers)block.Powers;
groupRole.Title = Utils.BytesToString(block.Title);
groupRoleCache[block.RoleID] = groupRole;
}
}
}
}
// Check if we've received all the group members that are showing up
if (OnGroupRoles != null && groupRoleCache != null && groupRoleCache.Count >= roles.GroupData.RoleCount)
{
try { OnGroupRoles(groupRoleCache); }
catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
}
}
private void GroupRoleMembersHandler(Packet packet, Simulator simulator)
{
GroupRoleMembersReplyPacket members = (GroupRoleMembersReplyPacket)packet;
List> groupRoleMemberCache = null;
try
{
lock (GroupRolesMembersRequests)
{
// If nothing is registered to receive this RequestID drop the data
if (GroupRolesMembersRequests.Contains(members.AgentData.RequestID))
{
GroupRolesMembersRequests.Remove(members.AgentData.RequestID);
if (!GroupRolesMembersRequests.Contains(members.AgentData.RequestID))
{
GroupRolesMembersRequests.Remove(members.AgentData.RequestID);
if (!GroupRolesMembersCaches.TryGetValue(members.AgentData.GroupID, out groupRoleMemberCache))
{
groupRoleMemberCache = new List>();
GroupRolesMembersCaches[members.AgentData.GroupID] = groupRoleMemberCache;
}
}
foreach (GroupRoleMembersReplyPacket.MemberDataBlock block in members.MemberData)
{
KeyValuePair rolemember =
new KeyValuePair(block.RoleID, block.MemberID);
groupRoleMemberCache.Add(rolemember);
}
}
}
}
catch (Exception e)
{
Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e);
}
//Client.DebugLog("Pairs Ratio: " + groupRoleMemberCache.Count + "/" + members.AgentData.TotalPairs);
// Check if we've received all the pairs that are showing up
if (OnGroupRolesMembers != null && groupRoleMemberCache != null && groupRoleMemberCache.Count >= members.AgentData.TotalPairs)
{
try { OnGroupRolesMembers(groupRoleMemberCache); }
catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
}
}
private void GroupActiveProposalItemHandler(Packet packet, Simulator simulator)
{
//GroupActiveProposalItemReplyPacket proposal = (GroupActiveProposalItemReplyPacket)packet;
// TODO: Create a proposal struct to represent the fields in a proposal item
}
private void GroupVoteHistoryItemHandler(Packet packet, Simulator simulator)
{
//GroupVoteHistoryItemReplyPacket history = (GroupVoteHistoryItemReplyPacket)packet;
// TODO: This was broken in the official viewer when I was last trying to work on it
}
private void GroupAccountSummaryHandler(Packet packet, Simulator simulator)
{
if (OnGroupAccountSummary != null)
{
GroupAccountSummaryReplyPacket summary = (GroupAccountSummaryReplyPacket)packet;
GroupAccountSummary account = new GroupAccountSummary();
account.Balance = summary.MoneyData.Balance;
account.CurrentInterval = summary.MoneyData.CurrentInterval;
account.GroupTaxCurrent = summary.MoneyData.GroupTaxCurrent;
account.GroupTaxEstimate = summary.MoneyData.GroupTaxEstimate;
account.IntervalDays = summary.MoneyData.IntervalDays;
account.LandTaxCurrent = summary.MoneyData.LandTaxCurrent;
account.LandTaxEstimate = summary.MoneyData.LandTaxEstimate;
account.LastTaxDate = Utils.BytesToString(summary.MoneyData.LastTaxDate);
account.LightTaxCurrent = summary.MoneyData.LightTaxCurrent;
account.LightTaxEstimate = summary.MoneyData.LightTaxEstimate;
account.NonExemptMembers = summary.MoneyData.NonExemptMembers;
account.ObjectTaxCurrent = summary.MoneyData.ObjectTaxCurrent;
account.ObjectTaxEstimate = summary.MoneyData.ObjectTaxEstimate;
account.ParcelDirFeeCurrent = summary.MoneyData.ParcelDirFeeCurrent;
account.ParcelDirFeeEstimate = summary.MoneyData.ParcelDirFeeEstimate;
account.StartDate = Utils.BytesToString(summary.MoneyData.StartDate);
account.TaxDate = Utils.BytesToString(summary.MoneyData.TaxDate);
account.TotalCredits = summary.MoneyData.TotalCredits;
account.TotalDebits = summary.MoneyData.TotalDebits;
try { OnGroupAccountSummary(account); }
catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
}
}
private void CreateGroupReplyHandler(Packet packet, Simulator simulator)
{
if (OnGroupCreated != null)
{
CreateGroupReplyPacket reply = (CreateGroupReplyPacket)packet;
string message = Utils.BytesToString(reply.ReplyData.Message);
try { OnGroupCreated(reply.ReplyData.GroupID, reply.ReplyData.Success, message); }
catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
}
}
private void JoinGroupReplyHandler(Packet packet, Simulator simulator)
{
if (OnGroupJoined != null)
{
JoinGroupReplyPacket reply = (JoinGroupReplyPacket)packet;
try { OnGroupJoined(reply.GroupData.GroupID, reply.GroupData.Success); }
catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
}
}
private void LeaveGroupReplyHandler(Packet packet, Simulator simulator)
{
if (OnGroupLeft != null)
{
LeaveGroupReplyPacket reply = (LeaveGroupReplyPacket)packet;
try { OnGroupLeft(reply.GroupData.GroupID, reply.GroupData.Success); }
catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
}
}
private void UUIDGroupNameReplyHandler(Packet packet, Simulator simulator)
{
UUIDGroupNameReplyPacket reply = (UUIDGroupNameReplyPacket)packet;
UUIDGroupNameReplyPacket.UUIDNameBlockBlock[] blocks = reply.UUIDNameBlock;
Dictionary groupNames = new Dictionary();
foreach (UUIDGroupNameReplyPacket.UUIDNameBlockBlock block in blocks)
{
groupNames.Add(block.ID, Utils.BytesToString(block.GroupName));
if (!GroupName2KeyCache.ContainsKey(block.ID))
GroupName2KeyCache.SafeAdd(block.ID, Utils.BytesToString(block.GroupName));
}
if (OnGroupNames != null)
{
try { OnGroupNames(groupNames); }
catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
}
}
///
/// Packet Handler for EjectGroupMemberReply, fired when an avatar is ejected from
/// a group.
///
/// The EjectGroupMemberReply packet
/// The simulator where the message originated
/// This is a silly packet, it doesn't provide you with the ejectees UUID
private void EjectGroupMemberReplyHandler(Packet packet, Simulator simulator)
{
EjectGroupMemberReplyPacket reply = (EjectGroupMemberReplyPacket)packet;
// TODO: On Success remove the member from the cache(s)
if(OnGroupMemberEjected != null)
{
try { OnGroupMemberEjected(reply.GroupData.GroupID, reply.EjectData.Success); }
catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
}
}
#endregion Packet Handlers
}
}