2019-06-18 22:55:32 -04:00
/ *
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Copyright ( C ) 2015 - 2019 Project Meteor Dev Team
This file is part of Project Meteor Server .
Project Meteor Server is free software : you can redistribute it and / or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
Project Meteor Server is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU Affero General Public License for more details .
You should have received a copy of the GNU Affero General Public License
along with Project Meteor Server . If not , see < https : www . gnu . org / licenses / > .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* /
using FFXIVClassic.Common ;
2016-08-22 14:18:37 -04:00
using FFXIVClassic_World_Server.DataObjects ;
2016-12-17 09:37:18 -05:00
using FFXIVClassic_World_Server.DataObjects.Group ;
2016-12-18 09:50:23 -05:00
using FFXIVClassic_World_Server.Packets.Send.Subpackets ;
2016-12-17 09:37:18 -05:00
using FFXIVClassic_World_Server.Packets.Send.Subpackets.Groups ;
2016-12-03 14:00:24 -05:00
using FFXIVClassic_World_Server.Packets.WorldPackets.Send ;
2016-12-21 09:27:51 -05:00
using FFXIVClassic_World_Server.Packets.WorldPackets.Send.Group ;
2016-08-22 14:18:37 -04:00
using MySql.Data.MySqlClient ;
using System ;
using System.Collections.Generic ;
namespace FFXIVClassic_World_Server
{
class WorldManager
{
private Server mServer ;
2016-08-29 08:17:14 -04:00
public Dictionary < string , ZoneServer > mZoneServerList ;
2016-09-26 16:20:01 -04:00
private Dictionary < uint , ZoneEntrance > zoneEntranceList ;
2016-08-22 14:18:37 -04:00
2016-12-17 09:37:18 -05:00
//World Scope Group Management
private Object mGroupLock = new object ( ) ;
private ulong mRunningGroupIndex = 1 ;
private Dictionary < ulong , Group > mCurrentWorldGroups = new Dictionary < ulong , Group > ( ) ;
private PartyManager mPartyManager ;
private RetainerGroupManager mRetainerGroupManager ;
private LinkshellManager mLinkshellManager ;
private RelationGroupManager mRelationGroupManager ;
2016-08-22 14:18:37 -04:00
public WorldManager ( Server server )
{
mServer = server ;
2016-12-17 09:37:18 -05:00
mPartyManager = new PartyManager ( this , mGroupLock , mCurrentWorldGroups ) ;
mLinkshellManager = new LinkshellManager ( this , mGroupLock , mCurrentWorldGroups ) ;
mRetainerGroupManager = new RetainerGroupManager ( this , mGroupLock , mCurrentWorldGroups ) ;
mRelationGroupManager = new RelationGroupManager ( this , mGroupLock , mCurrentWorldGroups ) ;
2016-08-22 14:18:37 -04:00
}
public void LoadZoneServerList ( )
{
mZoneServerList = new Dictionary < string , ZoneServer > ( ) ;
using ( MySqlConnection conn = new MySqlConnection ( String . Format ( "Server={0}; Port={1}; Database={2}; UID={3}; Password={4}" , ConfigConstants . DATABASE_HOST , ConfigConstants . DATABASE_PORT , ConfigConstants . DATABASE_NAME , ConfigConstants . DATABASE_USERNAME , ConfigConstants . DATABASE_PASSWORD ) ) )
{
try
{
conn . Open ( ) ;
string query = @ "
SELECT
2016-12-03 12:19:59 -05:00
id ,
2016-08-22 14:18:37 -04:00
serverIp ,
serverPort
FROM server_zones
WHERE serverIp IS NOT NULL ";
MySqlCommand cmd = new MySqlCommand ( query , conn ) ;
using ( MySqlDataReader reader = cmd . ExecuteReader ( ) )
{
while ( reader . Read ( ) )
{
2016-12-03 12:19:59 -05:00
uint id = reader . GetUInt32 ( 0 ) ;
string ip = reader . GetString ( 1 ) ;
int port = reader . GetInt32 ( 2 ) ;
2016-08-22 14:18:37 -04:00
string address = ip + ":" + port ;
if ( ! mZoneServerList . ContainsKey ( address ) )
{
2016-12-03 12:19:59 -05:00
ZoneServer zone = new ZoneServer ( ip , port , id ) ;
2016-08-22 14:18:37 -04:00
mZoneServerList . Add ( address , zone ) ;
}
2016-12-03 12:19:59 -05:00
else
mZoneServerList [ address ] . AddLoadedZone ( id ) ;
2016-08-22 14:18:37 -04:00
}
}
}
catch ( MySqlException e )
{ Console . WriteLine ( e ) ; }
finally
{
conn . Dispose ( ) ;
}
}
}
2016-09-26 16:20:01 -04:00
public void LoadZoneEntranceList ( )
{
zoneEntranceList = new Dictionary < uint , ZoneEntrance > ( ) ;
int count = 0 ;
using ( MySqlConnection conn = new MySqlConnection ( String . Format ( "Server={0}; Port={1}; Database={2}; UID={3}; Password={4}" , ConfigConstants . DATABASE_HOST , ConfigConstants . DATABASE_PORT , ConfigConstants . DATABASE_NAME , ConfigConstants . DATABASE_USERNAME , ConfigConstants . DATABASE_PASSWORD ) ) )
{
try
{
conn . Open ( ) ;
string query = @ "
SELECT
id ,
zoneId ,
spawnType ,
spawnX ,
spawnY ,
spawnZ ,
spawnRotation ,
privateAreaName
FROM server_zones_spawnlocations ";
MySqlCommand cmd = new MySqlCommand ( query , conn ) ;
using ( MySqlDataReader reader = cmd . ExecuteReader ( ) )
{
while ( reader . Read ( ) )
{
uint id = reader . GetUInt32 ( 0 ) ;
string privArea = null ;
if ( ! reader . IsDBNull ( 7 ) )
privArea = reader . GetString ( 7 ) ;
ZoneEntrance entance = new ZoneEntrance ( reader . GetUInt32 ( 1 ) , privArea , reader . GetByte ( 2 ) , reader . GetFloat ( 3 ) , reader . GetFloat ( 4 ) , reader . GetFloat ( 5 ) , reader . GetFloat ( 6 ) ) ;
zoneEntranceList [ id ] = entance ;
count + + ;
}
}
}
catch ( MySqlException e )
{ Console . WriteLine ( e ) ; }
finally
{
conn . Dispose ( ) ;
}
}
Program . Log . Info ( String . Format ( "Loaded {0} zone spawn locations." , count ) ) ;
}
2016-08-22 14:18:37 -04:00
public void ConnectToZoneServers ( )
{
Program . Log . Info ( "--------------------------" ) ;
Program . Log . Info ( "Connecting to zone servers" ) ;
Program . Log . Info ( "--------------------------" ) ;
foreach ( ZoneServer zs in mZoneServerList . Values )
{
zs . Connect ( ) ;
}
}
2016-12-03 12:19:59 -05:00
public ZoneServer GetZoneServer ( uint zoneId )
{
foreach ( ZoneServer zs in mZoneServerList . Values )
{
if ( zs . ownedZoneIds . Contains ( zoneId ) )
return zs ;
}
return null ;
}
2016-08-22 14:18:37 -04:00
//Moves the actor to the new zone if exists. No packets are sent nor position changed.
public void DoSeamlessZoneServerChange ( Session session , uint destinationZoneId )
{
}
//Moves actor to new zone, and sends packets to spawn at the given zone entrance
public void DoZoneServerChange ( Session session , uint zoneEntrance )
{
2016-09-26 16:20:01 -04:00
if ( ! zoneEntranceList . ContainsKey ( zoneEntrance ) )
{
Program . Log . Error ( "Given zone entrance was not found: " + zoneEntrance ) ;
return ;
}
ZoneEntrance ze = zoneEntranceList [ zoneEntrance ] ;
DoZoneServerChange ( session , ze . zoneId , ze . privateAreaName , ze . spawnType , ze . spawnX , ze . spawnY , ze . spawnZ , ze . spawnRotation ) ;
2016-08-22 14:18:37 -04:00
}
//Moves actor to new zone, and sends packets to spawn at the given coords.
public void DoZoneServerChange ( Session session , uint destinationZoneId , string destinationPrivateArea , byte spawnType , float spawnX , float spawnY , float spawnZ , float spawnRotation )
{
2016-12-03 14:00:24 -05:00
ZoneServer zs = GetZoneServer ( destinationZoneId ) ;
2016-12-11 23:31:13 -05:00
if ( zs = = null )
return ;
2016-12-13 15:02:28 -05:00
session . currentZoneId = destinationZoneId ;
//Intrazone change, just update the id
if ( zs . Equals ( session . routing1 ) )
return ;
2016-12-03 14:00:24 -05:00
if ( zs . isConnected )
session . routing1 . SendSessionEnd ( session , destinationZoneId , destinationPrivateArea , spawnType , spawnX , spawnY , spawnZ , spawnRotation ) ;
else if ( zs . Connect ( ) )
session . routing1 . SendSessionEnd ( session , destinationZoneId , destinationPrivateArea , spawnType , spawnX , spawnY , spawnZ , spawnRotation ) ;
else
session . routing1 . SendPacket ( ErrorPacket . BuildPacket ( session , 1 ) ) ;
2016-08-22 14:18:37 -04:00
}
//Login Zone In
public void DoLogin ( Session session )
2016-12-18 09:50:23 -05:00
{
SendMotD ( session ) ;
//Send party, retainer, ls groups
2016-12-21 08:27:23 -05:00
Party pt = mPartyManager . GetParty ( session . sessionId ) ;
2016-12-21 18:02:50 -05:00
2016-12-21 08:27:23 -05:00
pt . SendGroupPackets ( session ) ;
2016-12-22 14:47:24 -05:00
SendPartySync ( pt ) ;
2016-12-18 09:50:23 -05:00
mRetainerGroupManager . GetRetainerGroup ( session . sessionId ) . SendGroupPackets ( session ) ;
2017-09-05 12:37:23 -04:00
2016-12-18 09:50:23 -05:00
List < Linkshell > linkshells = mLinkshellManager . GetPlayerLinkshellMembership ( session . sessionId ) ;
foreach ( Linkshell ls in linkshells )
2017-01-09 23:12:56 -05:00
ls . SendGroupPackets ( session ) ;
//Reset to blank if in unknown state
ulong activeGroupIndex = 0 ;
if ( ! session . activeLinkshellName . Equals ( "" ) )
{
Linkshell activeLs = mLinkshellManager . GetLinkshell ( session . activeLinkshellName ) ;
if ( activeLs ! = null & & activeLs . HasMember ( session . sessionId ) )
{
activeGroupIndex = activeLs . groupIndex ;
}
else
{
session . activeLinkshellName = "" ;
Database . SetActiveLS ( session , "" ) ;
}
}
SubPacket activeLsPacket = SetActiveLinkshellPacket . BuildPacket ( session . sessionId , activeGroupIndex ) ;
2017-06-27 17:31:17 -04:00
session . clientConnection . QueuePacket ( activeLsPacket ) ;
2016-12-18 09:50:23 -05:00
}
private void SendMotD ( Session session )
{
2017-06-27 17:31:17 -04:00
session . clientConnection . QueuePacket ( SendMessagePacket . BuildPacket ( session . sessionId , session . sessionId , SendMessagePacket . MESSAGE_TYPE_GENERAL_INFO , "" , "-------- Login Message --------" ) ) ;
session . clientConnection . QueuePacket ( SendMessagePacket . BuildPacket ( session . sessionId , session . sessionId , SendMessagePacket . MESSAGE_TYPE_GENERAL_INFO , "" , String . Format ( "Welcome to {0}!" , ConfigConstants . PREF_SERVERNAME ) ) ) ;
session . clientConnection . QueuePacket ( SendMessagePacket . BuildPacket ( session . sessionId , session . sessionId , SendMessagePacket . MESSAGE_TYPE_GENERAL_INFO , "" , "Welcome to Eorzea!" ) ) ;
session . clientConnection . QueuePacket ( SendMessagePacket . BuildPacket ( session . sessionId , session . sessionId , SendMessagePacket . MESSAGE_TYPE_GENERAL_INFO , "" , "Here is a test Message of the Day from the World Server!" ) ) ;
2016-08-22 14:18:37 -04:00
}
2016-12-21 09:27:51 -05:00
public void SendPartySync ( Party party )
2016-12-21 18:02:50 -05:00
{
List < ZoneServer > alreadySent = new List < ZoneServer > ( ) ;
2016-12-21 09:27:51 -05:00
foreach ( uint member in party . members )
{
Session session = Server . GetServer ( ) . GetSession ( member ) ;
if ( session = = null )
continue ;
2016-12-21 18:02:50 -05:00
if ( alreadySent . Contains ( session . routing1 ) )
continue ;
alreadySent . Add ( session . routing1 ) ;
2016-12-21 09:27:51 -05:00
SubPacket syncPacket = PartySyncPacket . BuildPacket ( session , party ) ;
session . routing1 . SendPacket ( syncPacket ) ;
}
}
2016-08-22 14:18:37 -04:00
public class ZoneEntrance
{
public uint zoneId ;
public string privateAreaName ;
public byte spawnType ;
public float spawnX ;
public float spawnY ;
public float spawnZ ;
public float spawnRotation ;
public ZoneEntrance ( uint zoneId , string privateAreaName , byte spawnType , float x , float y , float z , float rot )
{
this . zoneId = zoneId ;
this . privateAreaName = privateAreaName ;
this . spawnType = spawnType ;
this . spawnX = x ;
this . spawnY = y ;
this . spawnZ = z ;
this . spawnRotation = rot ;
}
2016-12-17 09:37:18 -05:00
}
public void SendGroupData ( Session session , ulong groupId )
{
if ( mCurrentWorldGroups . ContainsKey ( groupId ) )
{
Group group = mCurrentWorldGroups [ groupId ] ;
group . SendGroupPackets ( session ) ;
}
}
public void SendGroupDataToAllMembers ( ulong groupId )
{
if ( mCurrentWorldGroups . ContainsKey ( groupId ) )
{
Group group = mCurrentWorldGroups [ groupId ] ;
2016-12-21 21:49:50 -05:00
foreach ( GroupMember member in group . BuildMemberList ( 0 ) )
2016-12-17 09:37:18 -05:00
group . SendGroupPackets ( mServer . GetSession ( member . actorId ) ) ;
}
2017-01-02 11:47:14 -05:00
}
2017-01-02 14:35:11 -05:00
public void ProcessPartyInvite ( Session requestSession , uint invitee )
{
if ( mServer . GetSession ( invitee ) = = null )
{
requestSession . SendGameMessage ( 30544 , 0x20 ) ;
}
else
{
Session inviteeSession = mServer . GetSession ( invitee ) ;
2017-01-08 21:42:43 -05:00
Relation inviteRelation = mRelationGroupManager . CreatePartyRelationGroup ( mPartyManager . GetParty ( requestSession . sessionId ) . groupIndex , requestSession . sessionId , invitee ) ;
2017-01-02 14:35:11 -05:00
inviteRelation . SendGroupPacketsAll ( requestSession . sessionId , invitee ) ;
inviteeSession . SendGameMessage ( 30430 , 0x20 , ( object ) mServer . GetNameForId ( requestSession . sessionId ) ) ; //X Invited you
requestSession . SendGameMessage ( 30433 , 0x20 , ( object ) mServer . GetNameForId ( inviteeSession . sessionId ) ) ; //You invite X
}
}
public void ProcessPartyInviteResult ( Session inviteeSession , uint resultCode )
2017-01-02 11:47:14 -05:00
{
2017-01-02 14:35:11 -05:00
Relation relation = mRelationGroupManager . GetPartyRelationGroup ( inviteeSession . sessionId ) ;
Session inviterSession = mServer . GetSession ( relation . GetHost ( ) ) ;
//Accept
if ( resultCode = = 1 )
{
Party oldParty = mPartyManager . GetParty ( inviteeSession . sessionId ) ;
if ( oldParty . members . Count = = 1 )
{
mPartyManager . DeleteParty ( oldParty . groupIndex ) ;
Party newParty = mPartyManager . GetParty ( inviterSession . sessionId ) ;
mPartyManager . AddToParty ( newParty . groupIndex , inviteeSession . sessionId ) ;
newParty . SendGroupPacketsAll ( newParty . members ) ;
SendPartySync ( newParty ) ;
newParty . OnPlayerJoin ( inviteeSession ) ;
}
}
else //Refuse
{
inviterSession . SendGameMessage ( 30573 , 0x20 , ( object ) mServer . GetNameForId ( inviteeSession . sessionId ) ) ; //X rejects your invite
}
//Delete the relation
mRelationGroupManager . DeleteRelationGroup ( relation . groupIndex ) ;
relation . SendDeletePackets ( inviterSession . sessionId , inviteeSession . sessionId ) ;
2017-01-02 11:47:14 -05:00
}
2016-12-17 09:37:18 -05:00
2017-01-08 21:42:43 -05:00
public void ProcessLinkshellInvite ( Session inviterSession , string lsName , uint invitee )
{
2019-06-08 17:06:10 -04:00
Session inviteeSession = mServer . GetSession ( invitee ) ;
Linkshell ls = mLinkshellManager . GetLinkshell ( lsName ) ;
//Something really fucked up
2017-01-08 21:42:43 -05:00
if ( mServer . GetSession ( invitee ) = = null )
{
inviterSession . SendGameMessage ( 30544 , 0x20 ) ;
}
2019-06-08 17:06:10 -04:00
//Check if they are already in your LS
else if ( ls . HasMember ( invitee ) )
2017-01-08 21:42:43 -05:00
{
2019-06-08 17:06:10 -04:00
inviterSession . SendGameMessage ( 25282 , 0x20 , ( object ) inviteeSession . characterName , 1 ) ; //X already belongs to
2017-01-08 21:42:43 -05:00
}
2019-06-08 17:06:10 -04:00
//Check if you can invite more members
else if ( ls . GetMemberCount ( ) > = LinkshellManager . LS_MAX_MEMBERS )
2017-01-08 21:42:43 -05:00
{
2019-06-08 17:06:10 -04:00
inviterSession . SendGameMessage ( 25158 , 0x20 , ( object ) inviteeSession ) ; //This linkshell cannot take on any more members.
}
//Check if they currently have an invite
else if ( mRelationGroupManager . GetLinkshellRelationGroup ( invitee ) ! = null )
{
inviterSession . SendGameMessage ( 25196 , 0x20 , ( object ) inviteeSession ) ; //Unable to invite X another pending
2017-01-08 21:42:43 -05:00
}
else
2019-06-08 17:06:10 -04:00
{
2017-01-08 21:42:43 -05:00
Relation inviteRelation = mRelationGroupManager . CreateLinkshellRelationGroup ( mLinkshellManager . GetLinkshell ( lsName ) . groupIndex , inviterSession . sessionId , invitee ) ;
inviteRelation . SendGroupPacketsAll ( inviterSession . sessionId , invitee ) ;
inviteeSession . SendGameMessage ( 25150 , 0x20 , ( object ) 1 , ( object ) lsName , ( object ) inviterSession ) ; //X Offers you
inviterSession . SendGameMessage ( 25151 , 0x20 , ( object ) 1 , null , ( object ) inviteeSession ) ; //You offer X
}
}
public void ProcessLinkshellInviteResult ( Session inviteeSession , uint resultCode )
{
Relation relation = mRelationGroupManager . GetLinkshellRelationGroup ( inviteeSession . sessionId ) ;
Session inviterSession = mServer . GetSession ( relation . GetHost ( ) ) ;
2019-06-08 17:06:10 -04:00
Linkshell newLS = null ;
if ( mCurrentWorldGroups . ContainsKey ( relation . groupIndex ) )
newLS = ( Linkshell ) mCurrentWorldGroups [ relation . GetTopicGroupIndex ( ) ] ;
else
2017-01-08 21:42:43 -05:00
{
2019-06-08 17:06:10 -04:00
//??? errored
2017-01-08 21:42:43 -05:00
}
2019-06-08 17:06:10 -04:00
if ( newLS ! = null )
2017-01-08 21:42:43 -05:00
{
2019-06-08 17:06:10 -04:00
//Accept
if ( resultCode = = 1 )
{
//Check if the invitee has room for more linkshells
if ( mLinkshellManager . GetPlayerLinkshellMembership ( inviteeSession . sessionId ) . Count > = LinkshellManager . LS_MAX_ALLOWED )
{
inviteeSession . SendGameMessage ( 25153 , 0x20 , ( object ) inviteeSession ) ; //You are unable to join any more linkshells.
}
//Did someone invite in the meantime?
else if ( newLS . GetMemberCount ( ) > = LinkshellManager . LS_MAX_MEMBERS )
{
inviterSession . SendGameMessage ( 25158 , 0x20 , ( object ) inviteeSession ) ; //This linkshell cannot take on any more members.
}
//All good, add new member
else
{
mLinkshellManager . AddMemberToLinkshell ( inviteeSession . sessionId , newLS . name ) ;
newLS . SendGroupPacketsAll ( newLS . GetMemberIds ( ) ) ;
newLS . OnPlayerJoin ( inviteeSession ) ;
}
}
else //Refuse
{
inviteeSession . SendGameMessage ( 25189 , 0x20 ) ; //You decline the linkpearl offer.
inviterSession . SendGameMessage ( 25190 , 0x20 ) ; //Your linkpearl offer is declined.
}
}
2017-01-08 21:42:43 -05:00
//Delete the relation
2019-06-08 17:06:10 -04:00
//mRelationGroupManager.DeleteRelationGroup(relation.groupIndex);
2017-01-08 21:42:43 -05:00
relation . SendDeletePackets ( inviterSession . sessionId , inviteeSession . sessionId ) ;
}
public void ProcessLinkshellInviteCancel ( Session inviterSession )
{
Relation relation = mRelationGroupManager . GetLinkshellRelationGroup ( inviterSession . sessionId ) ;
Session inviteeSession = mServer . GetSession ( relation . GetOther ( ) ) ;
inviterSession . SendGameMessage ( 25191 , 0x20 ) ; //You cancel the linkpearl offer.
inviteeSession . SendGameMessage ( 25192 , 0x20 ) ; //The linkpearl offer has been canceled.
//Delete the relation
mRelationGroupManager . DeleteRelationGroup ( relation . groupIndex ) ;
relation . SendDeletePackets ( inviterSession . sessionId , inviteeSession . sessionId ) ;
}
2017-01-09 23:12:56 -05:00
public void ProcessLinkshellSetActive ( Session requestSession , string lsName )
{
//Deactivate all
if ( lsName . Equals ( "" ) )
{
requestSession . SetActiveLS ( lsName ) ;
SubPacket activeLsPacket = SetActiveLinkshellPacket . BuildPacket ( requestSession . sessionId , 0 ) ;
2017-06-27 17:31:17 -04:00
requestSession . clientConnection . QueuePacket ( activeLsPacket ) ;
2017-01-09 23:12:56 -05:00
requestSession . SendGameMessage ( 25132 , 0x20 , ( object ) 1 ) ;
}
else
{
Linkshell ls = mLinkshellManager . GetLinkshell ( lsName ) ;
if ( ls = = null | | ! ls . HasMember ( requestSession . sessionId ) )
{
requestSession . SendGameMessage ( 25167 , 0x20 , ( object ) 1 , ( object ) lsName ) ;
}
else
{
requestSession . SetActiveLS ( lsName ) ;
SubPacket activeLsPacket = SetActiveLinkshellPacket . BuildPacket ( requestSession . sessionId , ls . groupIndex ) ;
2017-06-27 17:31:17 -04:00
requestSession . clientConnection . QueuePacket ( activeLsPacket ) ;
2017-01-09 23:12:56 -05:00
requestSession . SendGameMessage ( 25131 , 0x20 , ( object ) 1 , ( object ) lsName ) ;
}
}
}
2016-12-17 09:37:18 -05:00
public void IncrementGroupIndex ( )
{
mRunningGroupIndex + + ;
}
public ulong GetGroupIndex ( )
{
2016-12-18 09:50:23 -05:00
return mRunningGroupIndex | 0x8000000000000000 ;
2016-12-17 09:37:18 -05:00
}
public bool SendGroupInit ( Session session , ulong groupId )
{
if ( mCurrentWorldGroups . ContainsKey ( groupId ) )
{
mCurrentWorldGroups [ groupId ] . SendInitWorkValues ( session ) ;
return true ;
}
return false ;
}
2016-08-22 14:18:37 -04:00
2016-12-17 09:37:18 -05:00
public PartyManager GetPartyManager ( )
{
return mPartyManager ;
}
public RetainerGroupManager GetRetainerManager ( )
{
return mRetainerGroupManager ;
}
public LinkshellManager GetLinkshellManager ( )
{
return mLinkshellManager ;
}
2017-01-02 11:47:14 -05:00
2016-08-22 14:18:37 -04:00
}
}