public bool CheckFull(GroupMember member, SubGroup group) { if (group.IsFull) { var chr = member.Character; if (chr != null) { GroupHandler.SendResult(chr.Client, GroupResult.GroupIsFull); } return false; } return true; }
public static void SendLeaderChanged(GroupMember leader) { using (var packet = new RealmPacketOut(RealmServerOpCode.SMSG_GROUP_SET_LEADER)) { packet.WriteCString(leader.Name); leader.SubGroup.Group.SendAll(packet); } }
/// <summary> /// Checks whether the given target exists in this group and whether the given requestMember has the given privs /// </summary> public GroupResult CheckAction(GroupMember requestMember, GroupMember target, string targetName, GroupPrivs reqPrivs) { GroupResult err; if (target == null || (target.Group) != requestMember.Group) { // Character is offline or doesn't exist err = GroupResult.NotInYourParty; } else if ((reqPrivs == GroupPrivs.Leader && m_leader != requestMember) || (reqPrivs == GroupPrivs.MainAsisstant && !requestMember.IsAtLeastMainAssistant) || (reqPrivs == GroupPrivs.Assistant && !requestMember.IsAtLeastAssistant)) { err = GroupResult.DontHavePermission; targetName = string.Empty; } else { return GroupResult.NoError; } var requester = requestMember.Character; if (requester != null) { SendResult(requester.Client, err, 0, targetName); } return err; }
public bool CheckPrivs(GroupMember member, GroupPrivs reqPrivs) { //var flags = member.Flags; if ((reqPrivs == GroupPrivs.Leader && m_leader != member) || (reqPrivs == GroupPrivs.MainAsisstant && !member.IsAtLeastMainAssistant) || (reqPrivs == GroupPrivs.Assistant && !member.IsAtLeastAssistant)) { var requester = member.Character; if (requester != null) { GroupHandler.SendResult(requester.Client, GroupResult.DontHavePermission); } return false; } return true; }
/// <summary> /// Sends the response of a member to the original ready check requester. /// </summary> /// <param name="member">the responding member</param> /// <param name="status">their ready status</param> public void SendReadyCheckResponse(GroupMember member, ReadyCheckStatus status) { using (var packet = new RealmPacketOut(RealmServerOpCode.MSG_RAID_READY_CHECK_CONFIRM)) { packet.Write(EntityId.GetPlayerId(member.Id)); packet.WriteByte((byte)status); Character checkRequester = World.GetCharacter(m_readyCheckRequester.Id); if (checkRequester != null) checkRequester.Client.Send(packet); } }
/// <summary> /// Sends ping to the group, except pinger /// </summary> /// <param name="pinger">The group member who pingged the minimap</param> /// <param name="x">x coordinate of ping</param> /// <param name="y">y coordinate of ping</param> public virtual void SendPing(GroupMember pinger, float x, float y) { using (var packet = new RealmPacketOut(RealmServerOpCode.MSG_MINIMAP_PING)) { packet.Write(EntityId.GetPlayerId(pinger.Id)); packet.WriteFloat(x); packet.WriteFloat(y); SendAll(packet, pinger); } }
/// <summary> /// Called when the given member is added /// </summary> protected virtual void OnAddMember(GroupMember member) { m_Count++; var chr = member.Character; if (chr != null) { chr.GroupMember = member; } if (m_firstMember == null) { // first member: m_firstMember = m_lastMember = member; } else { m_lastMember.Next = member; m_lastMember = member; } var handler = MemberAdded; if (handler != null) { handler(member); } }
/// <summary> /// Moves a member of the raid group into another subgroup. /// </summary> /// <param name="member">the member to move</param> /// <param name="group">the target subgroup</param> /// <returns>Whether the move was successful or false if the target group was full</returns> public bool MoveMember(GroupMember member, SubGroup group) { if (group.IsFull) return false; var oldGroup = member.SubGroup; oldGroup.m_members.Remove(member); group.AddMember(member); return true; }
/// <summary> /// Add member to Group /// </summary> /// <param name="update">Indicates if this group needs to be updated after adding the /// new member</param> /// <returns>True if the member was added successfully. False otherwise.</returns> public GroupMember AddMember(Character chr, bool update) { GroupMember newMember = null; m_syncLock.EnterWriteLock(); try { // look for the first SubGroup with space left foreach (var groupUnit in m_subGroups) { if (!groupUnit.IsFull) { newMember = new GroupMember(chr, GroupMemberFlags.Normal); groupUnit.AddMember(newMember); break; } } } catch (Exception e) { LogUtil.ErrorException(e, string.Format("Could not add member {0} to group {1}", chr, this)); } finally { m_syncLock.ExitWriteLock(); } OnAddMember(newMember); if (newMember != null && update) { SendUpdate(); } return newMember; }
/// <summary> /// Remove member from this Group /// </summary> public virtual void RemoveMember(GroupMember member) { if (Count <= MinGroupMemberCount) { Disband(); } else { m_syncLock.EnterWriteLock(); var leaderChanged = false; try { var next = member.Next; OnMemberRemoved(member); // fix the links in the linked list: if (m_firstMember == member) { // set the new FirstMember if we removed the prevous one m_firstMember = next; } else { // set the previous GroupMember's Next member var previous = m_firstMember; while (previous.Next != member) { previous = previous.Next; } // previous should never be null here previous.Next = next; if (member == m_lastMember) { m_lastMember = previous; } } //Set new Leader if we removed the previous one if (m_leader == member) { m_leader = GetFirstOnlineMemberUnlocked(); leaderChanged = true; } //Set new MasterLooter if we removed the previous one if (m_masterLooter == member) { m_masterLooter = m_firstMember; } //Unset MainAssistant if we removed the previous one if (m_mainAssistant == member) { member.Flags &= ~GroupMemberFlags.MainAssistant; m_mainAssistant = null; } //Unset MainTank if we removed the previous one if (m_mainTank == member) { member.Flags &= ~GroupMemberFlags.MainTank; m_mainTank = null; } // Skip the member in RoundRobin if (m_roundRobinMember == member) { m_roundRobinMember = next; } } finally { m_syncLock.ExitWriteLock(); } if (leaderChanged) { // make sure to call this after the lock has been released OnLeaderChanged(member); } } SendUpdate(); }
/// <summary> /// Update the stats of the given <see cref="GroupMember"/> to all /// out of range members of this group. /// </summary> /// <remarks>Method requires Group-synchronization.</remarks> /// <param name="member">The <see cref="GroupMember"/> who needs to send /// the update</param> internal void UpdateOutOfRangeMembers(GroupMember member) { if (member.Character == null) return; if (member.Group != this) return; foreach (var chr in GetCharacters()) { if (chr != member.Character && chr != null && !chr.IsInUpdateRange(member.Character) && member.Character.GroupUpdateFlags != GroupUpdateFlags.None) { GroupHandler.SendPartyMemberStats(chr.Client, member, member.Character.GroupUpdateFlags); } } member.Character.GroupUpdateFlags = GroupUpdateFlags.None; }
/// <summary> /// Sets the given Looting-parameters and updates the Group. /// </summary> public void SetLootMethod(LootMethod method, GroupMember masterLooter, ItemQuality lootThreshold) { m_syncLock.EnterWriteLock(); try { LootMethod = method; m_masterLooter = masterLooter; LootThreshold = lootThreshold; } finally { m_syncLock.ExitWriteLock(); } SendUpdate(); }
/// <summary> /// Selects and returns the next online Member whose turn it is in RoundRobin. /// </summary> /// <returns>null if all members of this Group are offline.</returns> public GroupMember GetNextRoundRobinMember() { m_syncLock.EnterWriteLock(); try { if (m_roundRobinMember == null) { m_roundRobinMember = m_firstMember; } else { m_roundRobinMember = m_roundRobinMember.Next; } while (m_roundRobinMember.Character == null) { m_roundRobinMember = m_roundRobinMember.Next; if (m_roundRobinMember == m_firstMember) { return null; } } } finally { m_syncLock.ExitWriteLock(); } return m_roundRobinMember; }
/// <summary> /// Sends the requested party member stats data to the client /// </summary> /// <param name="client">realm client</param> /// <param name="member">The character whose stats is going to be retrieved</param> /// <param name="flags">The stats to be retrieved from the <paramref name="member"/></param> public static void SendPartyMemberStats(IPacketReceiver client, GroupMember member, GroupUpdateFlags flags) { SendPartyMemberStatsInternal(client, member, flags, RealmServerOpCode.SMSG_PARTY_MEMBER_STATS); }
/// <summary> /// Called before the given member is removed to clean up everything related to the given member /// </summary> protected void OnMemberRemoved(GroupMember member) { var chr = member.Character; if (chr != null && chr.IsInWorld) { if (!chr.IsInContext) { chr.ExecuteInContext(() => OnMemberRemoved(member)); return; } var handler = MemberRemoved; if (handler != null) { handler(member); } m_Count--; //Send an empty party list to the member SendEmptyUpdate(chr); chr.GroupMember = null; // notify user: // SendGroupDestroyed(chr); GroupHandler.SendResult(chr.Client, GroupResult.NoError); //Remove the member from the subgroup member.SubGroup.RemoveMember(member); member.Character = null; // Teleport out of group-owned instances within 1 minute if (chr.Region is BaseInstance) { var instance = (BaseInstance)chr.Region; chr.Region.CallDelayed(GroupInstanceKickDelay, () => { if (chr.IsInWorld && chr.Region == instance && !instance.CanEnter(chr)) { // chr is still inside and not allowed //chr.Region.TeleportOutside(chr); chr.TeleportToNearestGraveyard(); } }); } } else { var handler = MemberRemoved; if (handler != null) { handler(member); } m_Count--; GroupMgr.Instance.OfflineChars.Remove(member.Id); member.m_subGroup = null; } member.m_nextMember = null; }
/// <summary> /// Sends the requested party member stats data to the client /// </summary> /// <param name="client">realm client</param> /// <param name="member">The character whose stats is going to be retrieved</param> /// <param name="flags">The stats to be retrieved from the <paramref name="member"/></param> private static void SendPartyMemberStatsInternal(IPacketReceiver client, GroupMember member, GroupUpdateFlags flags, RealmServerOpCode opcode) { using (var packet = new RealmPacketOut(opcode)) { if (opcode == RealmServerOpCode.SMSG_PARTY_MEMBER_STATS_FULL) { packet.Write((byte)0); //arena something } member.WriteIdPacked(packet); if (!member.IsOnline) { packet.WriteUShort((ushort)CharacterStatus.OFFLINE); client.Send(packet); return; } packet.Write((uint)flags); var chr = member.Character; if (flags.HasFlag(GroupUpdateFlags.Status)) { packet.Write((ushort)chr.Status); } if (flags.HasFlag(GroupUpdateFlags.Health)) { packet.Write(chr.Health); } if (flags.HasFlag(GroupUpdateFlags.MaxHealth)) { packet.Write(chr.MaxHealth); } if (flags.HasFlag(GroupUpdateFlags.PowerType)) { packet.Write((byte)chr.PowerType); } if (flags.HasFlag(GroupUpdateFlags.Power)) { packet.Write((ushort)chr.Power); } if (flags.HasFlag(GroupUpdateFlags.MaxPower)) { packet.Write((ushort)chr.MaxPower); } if (flags.HasFlag(GroupUpdateFlags.Level)) { packet.Write((ushort)chr.Level); } if (flags.HasFlag(GroupUpdateFlags.ZoneId)) { packet.Write((ushort)(chr.Zone != null ? chr.Zone.Id : ZoneId.None)); } if (flags.HasFlag(GroupUpdateFlags.Position)) { packet.Write((ushort)chr.Position.X); packet.Write((ushort)chr.Position.Y); } if (flags.HasFlag(GroupUpdateFlags.Auras)) { ulong auraMask = chr.AuraUpdateMask; packet.Write(auraMask); Aura currAura; for (byte i = 0; i < AuraHandler.MaxAuras; ++i) { if ((auraMask & ((ulong)1 << i)) != 0) { currAura = chr.Auras.GetAt(i); packet.Write(currAura.Spell.Id); packet.Write((byte)currAura.Flags); } } } NPC targetPet = chr.ActivePet; if (targetPet == null) //no pet { packet.Write((byte)0); //name packet.Write(0UL); //auras client.Send(packet); return; } if (flags.HasFlag(GroupUpdateFlags.PetGuid)) { packet.Write(targetPet.EntityId); } if (flags.HasFlag(GroupUpdateFlags.PetName)) { packet.WriteCString(targetPet.Name); } if (flags.HasFlag(GroupUpdateFlags.PetDisplayId)) { packet.Write((ushort)targetPet.DisplayId); } if (flags.HasFlag(GroupUpdateFlags.PetHealth)) { packet.Write(targetPet.Health); } if (flags.HasFlag(GroupUpdateFlags.PetMaxHealth)) { packet.Write(targetPet.MaxHealth); } if (flags.HasFlag(GroupUpdateFlags.PetPowerType)) { packet.Write((byte)targetPet.PowerType); } if (flags.HasFlag(GroupUpdateFlags.PetPower)) { packet.Write((ushort)targetPet.Power); } if (flags.HasFlag(GroupUpdateFlags.PetMaxPower)) { packet.Write((ushort)targetPet.MaxPower); } if (flags.HasFlag(GroupUpdateFlags.PetAuras)) { ulong auraMask = targetPet.AuraUpdateMask; packet.Write(auraMask); Aura currAura; for (byte i = 0; i < AuraHandler.MaxAuras; ++i) { if ((auraMask & ((ulong)1 << i)) != 0) { currAura = targetPet.Auras.GetAt(i);//chr.Auras.GetAt(i); packet.Write(currAura.Spell.Id); packet.Write((byte)currAura.Flags); } } } client.Send(packet); } }
private void OnLeaderChanged(GroupMember oldLeader) { // if everyone is offline, the Group has no leader if (m_leader != null) { GroupHandler.SendLeaderChanged(m_leader); } var evt = LeaderChanged; if (evt != null) { evt(oldLeader, m_leader); } }
/// <summary> /// Sends a ready check request to the members of the raid group. /// </summary> /// <param name="member">the member who requested the check</param> public void SendReadyCheckRequest(GroupMember member) { m_readyCheckRequester = member; using (var packet = new RealmPacketOut(RealmServerOpCode.MSG_RAID_READY_CHECK)) { packet.Write(EntityId.GetPlayerId(member.Id)); SendAll(packet, member); } }
protected Group(Character leader, byte maxGroupUnits) { // m_syncLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); m_syncLock = new ReaderWriterLockSlim(); m_subGroups = new SubGroup[maxGroupUnits]; for (byte i = 0; i < maxGroupUnits; i++) { m_subGroups[i] = new SubGroup(this, i); } m_targetIcons = new EntityId[TargetIconCount]; for (int i = 0; i < m_targetIcons.Length; i++) m_targetIcons[i] = EntityId.Zero; m_lootMethod = LootMethod.GroupLoot; m_lootThreshold = ItemQuality.Uncommon; m_DungeonDifficulty = 0; var member = AddMember(leader, false); Leader = member; m_masterLooter = null; // update will follow when the 2nd guy joins }
/// <summary> /// Creates a raid group with the given character as the leader. /// </summary> /// <param name="leader">the character to be the leader</param> public RaidGroup(Character leader) : base(leader, MaxSubGroupCount) { m_readyCheckRequester = null; }
/// <summary> /// Send a packet to each group member except one specified /// </summary> /// <param name="packet">Realm Packet</param> /// <param name="ignored">Member that won't receive the message</param> protected virtual void SendAll(RealmPacketOut packet, GroupMember ignored) { foreach (var groupUnit in m_subGroups) { groupUnit.Send(packet, ignored); } }