Cleaned up namespaces (still have to do Map Project) and removed references to FFXIV Classic from the code. Removed the Launcher Editor project as it is no longer needed (host file editing is cleaner).

This commit is contained in:
Filip Maj 2019-06-19 00:05:18 -04:00
parent 7587a6e142
commit 0f61c4c0e1
544 changed files with 54548 additions and 55498 deletions

View file

@ -0,0 +1,92 @@
/*
===========================================================================
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 System;
using System.Net.Sockets;
using System.Collections.Concurrent;
using System.Net;
using Meteor.Common;
using Meteor.World.DataObjects;
namespace Meteor.World
{
class ClientConnection
{
//Connection stuff
public Socket socket;
public byte[] buffer;
private BlockingCollection<BasePacket> SendPacketQueue = new BlockingCollection<BasePacket>(1000);
public int lastPartialSize = 0;
//Instance Stuff
public Session owner;
public void QueuePacket(BasePacket packet)
{
SendPacketQueue.Add(packet);
}
public void QueuePacket(SubPacket subpacket)
{
bool isAuthed = true;
bool isEncrypted = false;
subpacket.SetTargetId(owner.sessionId);
SendPacketQueue.Add(BasePacket.CreatePacket(subpacket, isAuthed, isEncrypted));
}
public void FlushQueuedSendPackets()
{
if (!socket.Connected)
return;
while (SendPacketQueue.Count > 0)
{
BasePacket packet = SendPacketQueue.Take();
byte[] packetBytes = packet.GetPacketBytes();
try
{
socket.Send(packetBytes);
}
catch (Exception e)
{ Program.Log.Error(e, "Weird case, socket was d/ced: {0}"); }
}
}
public String GetAddress()
{
return String.Format("{0}:{1}", (socket.RemoteEndPoint as IPEndPoint).Address, (socket.RemoteEndPoint as IPEndPoint).Port);
}
public bool IsConnected()
{
return (socket.Poll(1, SelectMode.SelectRead) && socket.Available == 0);
}
public void Disconnect()
{
if (socket.Connected)
socket.Disconnect(false);
}
}
}

View file

@ -0,0 +1,35 @@
/*
===========================================================================
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/>.
===========================================================================
*/
namespace Meteor.World.DataObjects
{
class DBWorld
{
public uint id;
public string address;
public ushort port;
public ushort listPosition;
public ushort population;
public string name;
public bool isActive;
public string motd;
}
}

View file

@ -0,0 +1,158 @@
/*
===========================================================================
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 System;
using System.Collections.Generic;
using Meteor.Common;
using Meteor.World.Packets.Send.Subpackets.Groups;
namespace Meteor.World.DataObjects.Group
{
class Group
{
public const uint PlayerPartyGroup = 10001;
public const uint CompanyGroup = 20002;
public const uint GroupInvitationRelationGroup = 50001;
public const uint TradeRelationGroup = 50002;
public const uint RetainerMeetingRelationGroup = 50003;
public const uint BazaarBuyItemRelationGroup = 50009;
public const uint RetainerGroup = 80001;
public readonly ulong groupIndex;
public Group(ulong groupIndex)
{
this.groupIndex = groupIndex;
}
public virtual int GetMemberCount()
{
return 0;
}
public virtual uint GetTypeId()
{
return 0;
}
public virtual string GetGroupName()
{
return "";
}
public virtual int GetGroupLocalizedName()
{
return -1;
}
public virtual List<GroupMember> BuildMemberList(uint id)
{
return new List<GroupMember>();
}
public void SendGroupPacketsAll(params uint[] sessionIds)
{
for (int i = 0; i < sessionIds.Length; i++)
{
Session session = Server.GetServer().GetSession(sessionIds[i]);
if (session != null)
SendGroupPackets(session);
}
}
public void SendGroupPacketsAll(List<uint> sessionIds)
{
for (int i = 0; i < sessionIds.Count; i++)
{
Session session = Server.GetServer().GetSession(sessionIds[i]);
if (session != null)
SendGroupPackets(session);
}
}
public void SendDeletePackets(params uint[] sessionIds)
{
for (int i = 0; i < sessionIds.Length; i++)
{
Session session = Server.GetServer().GetSession(sessionIds[i]);
if (session != null)
SendDeletePacket(session);
}
}
public void SendDeletePackets(List<uint> sessionIds)
{
for (int i = 0; i < sessionIds.Count; i++)
{
Session session = Server.GetServer().GetSession(sessionIds[i]);
if (session != null)
SendDeletePacket(session);
}
}
public void SendGroupPackets(Session session)
{
ulong time = Utils.MilisUnixTimeStampUTC();
List<GroupMember> members = BuildMemberList(session.sessionId);
session.clientConnection.QueuePacket(GroupHeaderPacket.buildPacket(session.sessionId, session.currentZoneId, time, this));
session.clientConnection.QueuePacket(GroupMembersBeginPacket.buildPacket(session.sessionId, session.currentZoneId, time, this));
int currentIndex = 0;
while (true)
{
int memberCount = Math.Min(GetMemberCount(), members.Count);
if (memberCount - currentIndex >= 64)
session.clientConnection.QueuePacket(GroupMembersX64Packet.buildPacket(session.sessionId, session.currentZoneId, time, members, ref currentIndex));
else if (memberCount - currentIndex >= 32)
session.clientConnection.QueuePacket(GroupMembersX32Packet.buildPacket(session.sessionId, session.currentZoneId, time, members, ref currentIndex));
else if (memberCount - currentIndex >= 16)
session.clientConnection.QueuePacket(GroupMembersX16Packet.buildPacket(session.sessionId, session.currentZoneId, time, members, ref currentIndex));
else if (memberCount - currentIndex > 0)
session.clientConnection.QueuePacket(GroupMembersX08Packet.buildPacket(session.sessionId, session.currentZoneId, time, members, ref currentIndex));
else
break;
}
session.clientConnection.QueuePacket(GroupMembersEndPacket.buildPacket(session.sessionId, session.currentZoneId, time, this));
}
public void SendDeletePacket(Session session)
{
if (session != null)
session.clientConnection.QueuePacket(DeleteGroupPacket.buildPacket(session.sessionId, this));
}
public virtual void SendInitWorkValues(Session session)
{
}
}
}

View file

@ -0,0 +1,329 @@
/*
===========================================================================
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 System;
using System.Collections.Generic;
using Meteor.Common;
using Meteor.World.Actor.Group.Work;
using Meteor.World.Packets.Send.Subpackets.Groups;
namespace Meteor.World.DataObjects.Group
{
class Linkshell : Group
{
public ulong dbId;
public string name;
public LinkshellWork work = new LinkshellWork();
private List<LinkshellMember> members = new List<LinkshellMember>();
public Linkshell(ulong dbId, ulong groupIndex, string name, ushort crestId, uint master, byte rank) : base(groupIndex)
{
this.dbId = dbId;
this.name = name;
work._globalSave.crestIcon[0] = crestId;
work._globalSave.master = master;
work._globalSave.rank = rank;
}
public void setMaster(uint actorId)
{
work._globalSave.master = (ulong)((0xB36F92 << 8) | actorId);
}
public void setCrest(ushort crestId)
{
work._globalSave.crestIcon[0] = crestId;
}
public void setRank(byte rank = 1)
{
work._globalSave.rank = rank;
}
public void setMemberRank(int index, byte rank)
{
if (members.Count >= index)
return;
work._memberSave[index].rank = rank;
}
public void AddMember(uint charaId, byte rank = LinkshellManager.RANK_MEMBER)
{
members.Add(new LinkshellMember(charaId, dbId, rank));
members.Sort();
}
public void RemoveMember(uint charaId)
{
for (int i = 0; i < members.Count; i++)
{
if (members[i].charaId == charaId)
{
members.Remove(members[i]);
members.Sort();
break;
}
}
}
public override int GetMemberCount()
{
return members.Count;
}
public override string GetGroupName()
{
return name;
}
public override uint GetTypeId()
{
return Group.CompanyGroup;
}
public override List<GroupMember> BuildMemberList(uint id)
{
lock (members)
{
List<GroupMember> groupMembers = new List<GroupMember>();
foreach (LinkshellMember member in members)
groupMembers.Add(new GroupMember(member.charaId, -1, 0, false, true, Server.GetServer().GetNameForId(member.charaId)));
return groupMembers;
}
}
public uint[] GetMemberIds()
{
lock (members)
{
uint[] memberIds = new uint[members.Count];
for (int i = 0; i < memberIds.Length; i++)
memberIds[i] = members[i].charaId;
return memberIds;
}
}
public override void SendInitWorkValues(Session session)
{
SynchGroupWorkValuesPacket groupWork = new SynchGroupWorkValuesPacket(groupIndex);
groupWork.addProperty(this, "work._globalSave.master");
groupWork.addProperty(this, "work._globalSave.crestIcon[0]");
groupWork.addProperty(this, "work._globalSave.rank");
for (int i = 0; i < members.Count; i++)
{
work._memberSave[i].rank = members[i].rank;
groupWork.addProperty(this, String.Format("work._memberSave[{0}].rank", i));
}
groupWork.setTarget("/_init");
SubPacket test = groupWork.buildPacket(session.sessionId);
test.DebugPrintSubPacket();
session.clientConnection.QueuePacket(test);
}
public void ResendWorkValues()
{
SynchGroupWorkValuesPacket groupWork = new SynchGroupWorkValuesPacket(groupIndex);
groupWork.addProperty(this, "work._globalSave.master");
groupWork.addProperty(this, "work._globalSave.crestIcon[0]");
groupWork.addProperty(this, "work._globalSave.rank");
for (int i = 0; i < members.Count; i++)
{
work._memberSave[i].rank = members[i].rank;
groupWork.addProperty(this, String.Format("work._memberSave[{0}].rank", i));
}
groupWork.setTarget("memberRank");
lock (members)
{
for (int i = 0; i < members.Count; i++)
{
Session session = Server.GetServer().GetSession(members[i].charaId);
if (session != null)
{
SubPacket test = groupWork.buildPacket(session.sessionId);
session.clientConnection.QueuePacket(test);
}
}
}
}
public void LoadMembers()
{
members = Database.GetLSMembers(this);
}
public void OnPlayerJoin(Session inviteeSession)
{
for (int i = 0; i < members.Count; i++)
{
Session session = Server.GetServer().GetSession(members[i].charaId);
if (session == null)
continue;
if (inviteeSession.Equals(session))
session.SendGameMessage(25157, 0x20, (object) 0, (object)inviteeSession, name);
else
session.SendGameMessage(25284, 0x20, (object) 0, (object)Server.GetServer().GetNameForId(inviteeSession.sessionId), name);
}
}
public LinkshellMember GetMember(string name)
{
lock (members)
{
for (int i = 0; i < members.Count; i++)
{
if (Server.GetServer().GetNameForId((members[i].charaId)).Equals(name))
return members[i];
}
return null;
}
}
public bool HasMember(uint id)
{
lock (members)
{
for (int i = 0; i < members.Count; i++)
{
if (members[i].charaId == id)
return true;
}
return false;
}
}
public void DisbandRequest(Session session)
{
throw new NotImplementedException();
}
public void LeaveRequest(Session requestSession)
{
uint leaver = requestSession.sessionId;
//Check if ls contains this person
if (!HasMember(leaver))
{
return;
}
//Send you are leaving message
requestSession.SendGameMessage(25162, 0x20, (Object)1, name);
//All good, remove
Server.GetServer().GetWorldManager().GetLinkshellManager().RemoveMemberFromLinkshell(requestSession.sessionId, name);
SendGroupPacketsAll(GetMemberIds());
ResendWorkValues();
//If active, remove it
if (requestSession.activeLinkshellName.Equals(name))
{
SubPacket activeLsPacket = SetActiveLinkshellPacket.BuildPacket(requestSession.sessionId, 0);
requestSession.clientConnection.QueuePacket(activeLsPacket);
requestSession.SetActiveLS("");
}
//Delete group for kicked guy
SendDeletePacket(requestSession);
}
public void KickRequest(Session requestSession, string kickedName)
{
LinkshellMember kicked = GetMember(kickedName);
Session kickedSession = Server.GetServer().GetSession(kicked.charaId);
//Check if ls contains this person
if (!HasMember(kicked.charaId))
{
requestSession.SendGameMessage(25281, 0x20, (Object)1, (Object)kickedName, (Object)name);
return;
}
//Send you are exiled message
lock (members)
{
for (int i = 0; i < members.Count; i++)
{
Session session = Server.GetServer().GetSession(members[i].charaId);
if (session == null)
continue;
if (session.sessionId == kicked.charaId)
session.SendGameMessage(25184, 0x20, (Object)1, (Object)name);
else
session.SendGameMessage(25280, 0x20, (Object)1, (Object)kickedName, (Object)name);
}
}
//All good, remove
Server.GetServer().GetWorldManager().GetLinkshellManager().RemoveMemberFromLinkshell(kicked.charaId, name);
SendGroupPacketsAll(GetMemberIds());
ResendWorkValues();
//If active, remove it
if (requestSession.activeLinkshellName.Equals(name))
{
SubPacket activeLsPacket = SetActiveLinkshellPacket.BuildPacket(requestSession.sessionId, 0);
requestSession.clientConnection.QueuePacket(activeLsPacket);
requestSession.SetActiveLS("");
}
//Delete group for kicked guy
SendDeletePacket(kickedSession);
}
public void RankChangeRequest(Session requestSession, string name, byte rank)
{
lock (members)
{
for (int i = 0; i < members.Count; i++)
{
if (Server.GetServer().GetNameForId(members[i].charaId).Equals(name))
{
if (Database.LinkshellChangeRank(members[i].charaId, rank))
{
members[i].rank = rank;
ResendWorkValues();
requestSession.SendGameMessage(25277, 0x20, (object)(100000 + rank), (object)name);
}
return;
}
}
}
}
}
}

View file

@ -0,0 +1,44 @@
/*
===========================================================================
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 System;
namespace Meteor.World.DataObjects.Group
{
class LinkshellMember : IComparable<LinkshellMember>
{
public readonly uint charaId;
public readonly ulong lsId;
public byte rank;
public LinkshellMember(uint charaId, ulong lsId, byte rank)
{
this.charaId = charaId;
this.lsId = lsId;
this.rank = rank;
}
public int CompareTo(LinkshellMember other)
{
return Server.GetServer().GetNameForId(charaId).CompareTo(Server.GetServer().GetNameForId(other.charaId));
}
}
}

View file

@ -0,0 +1,288 @@
/*
===========================================================================
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 System;
using System.Collections.Generic;
using Meteor.Common;
using Meteor.World.Actor.Group.Work;
using Meteor.World.Packets.Send.Subpackets.Groups;
namespace Meteor.World.DataObjects.Group
{
class Party : Group
{
public PartyWork partyGroupWork = new PartyWork();
public List<uint> members = new List<uint>();
public Party(ulong groupId, uint leaderCharaId) : base(groupId)
{
partyGroupWork._globalTemp.owner = (ulong)(((ulong)leaderCharaId << 32) | 0xB36F92);
members.Add(leaderCharaId);
}
public void SetLeaderPlayerRequest(Session requestSession, string name)
{
SetLeaderPlayerRequest(requestSession, GetIdForName(name));
}
public void SetLeaderPlayerRequest(Session requestSession, uint actorId)
{
if (GetLeader() != requestSession.sessionId)
{
requestSession.SendGameMessage(30428, 0x20, Server.GetServer().GetNameForId(requestSession.sessionId));
return;
}
uint newLeader = actorId;
if (!members.Contains(actorId))
{
requestSession.SendGameMessage(30567, 0x20);
return;
}
else if (newLeader == GetLeader())
{
requestSession.SendGameMessage(30559, 0x20, (Object)Server.GetServer().GetNameForId(actorId));
return;
}
SetLeader(newLeader);
SendLeaderWorkToAllMembers();
for (int i = 0; i < members.Count; i++)
{
Session session = Server.GetServer().GetSession(members[i]);
if (session == null)
continue;
session.SendGameMessage(30429, 0x20, (Object)Server.GetServer().GetNameForId(actorId));
}
Server.GetServer().GetWorldManager().SendPartySync(this);
}
public void KickPlayerRequest(Session requestSession, string name)
{
KickPlayerRequest(requestSession, GetIdForName(name));
}
public void KickPlayerRequest(Session requestSession, uint actorId)
{
if (GetLeader() != requestSession.sessionId)
{
requestSession.SendGameMessage(30428, 0x20, Server.GetServer().GetNameForId(requestSession.sessionId));
return;
}
uint kickedMemberId = actorId;
if (!members.Contains(actorId))
{
requestSession.SendGameMessage(30575, 0x20);
return;
}
for (int i = 0; i < members.Count; i++)
{
Session session = Server.GetServer().GetSession(members[i]);
if (session == null)
continue;
if (members[i] == kickedMemberId)
session.SendGameMessage(30410, 0x20);
else
session.SendGameMessage(30428, 0x20, (Object)Server.GetServer().GetNameForId(actorId));
}
//All good, remove
Server.GetServer().GetWorldManager().GetPartyManager().RemoveFromParty(groupIndex, kickedMemberId);
SendGroupPacketsAll(members);
Server.GetServer().GetWorldManager().SendPartySync(this);
//Set the kicked guy to a new party
Session kickedSession = Server.GetServer().GetSession(kickedMemberId);
if (kickedSession != null)
{
Party kickedPlayersNewParty = Server.GetServer().GetWorldManager().GetPartyManager().CreateParty(kickedMemberId);
kickedPlayersNewParty.SendGroupPackets(kickedSession);
Server.GetServer().GetWorldManager().SendPartySync(kickedPlayersNewParty);
kickedPlayersNewParty.SendInitWorkValues(kickedSession);
}
}
public void LeavePlayerRequest(Session requestSession)
{
uint leaver = requestSession.sessionId;
//Check if party contains this person
if (!members.Contains(leaver))
{
return;
}
//Send you are leaving messages
for (int i = 0; i < members.Count; i++)
{
Session session = Server.GetServer().GetSession(members[i]);
if (session == null)
continue;
session.SendGameMessage(30431, 0x20, (Object)Server.GetServer().GetNameForId(leaver));
}
//All good, remove
Server.GetServer().GetWorldManager().GetPartyManager().RemoveFromParty(groupIndex, leaver);
SendGroupPacketsAll(members);
Server.GetServer().GetWorldManager().SendPartySync(this);
//Set the left guy to a new party
if (requestSession != null)
{
Party kickedPlayersNewParty = Server.GetServer().GetWorldManager().GetPartyManager().CreateParty(leaver);
kickedPlayersNewParty.SendGroupPackets(requestSession);
Server.GetServer().GetWorldManager().SendPartySync(kickedPlayersNewParty);
kickedPlayersNewParty.SendInitWorkValues(requestSession);
}
}
public void DisbandPlayerRequest(Session requestSession)
{
uint disbander = requestSession.sessionId;
//Check if leader
if (GetLeader() != disbander)
{
requestSession.SendGameMessage(30428, 0x20, Server.GetServer().GetNameForId(requestSession.sessionId));
return;
}
Server.GetServer().GetWorldManager().GetPartyManager().DeleteParty(groupIndex);
//Send game messages and set new parties
for (int i = 0; i < members.Count; i++)
{
Session session = Server.GetServer().GetSession(members[i]);
if (session == null)
continue;
session.SendGameMessage(30401, 0x20);
//Set char to new party
Party newParty = Server.GetServer().GetWorldManager().GetPartyManager().CreateParty(members[i]);
newParty.SendGroupPackets(session);
Server.GetServer().GetWorldManager().SendPartySync(newParty);
newParty.SendInitWorkValues(session);
}
Server.GetServer().GetWorldManager().SendPartySync(this);
}
public void SendLeaderWorkToAllMembers()
{
for (int i = 0; i < members.Count; i++)
{
SynchGroupWorkValuesPacket leaderUpdate = new SynchGroupWorkValuesPacket(groupIndex);
leaderUpdate.addProperty(this, "partyGroupWork._globalTemp.owner");
leaderUpdate.setTarget("partyGroupWork/leader");
Session session = Server.GetServer().GetSession(members[i]);
if (session == null)
continue;
else
session.clientConnection.QueuePacket(leaderUpdate.buildPacket(session.sessionId));
}
}
public void SetLeader(uint actorId)
{
partyGroupWork._globalTemp.owner = (ulong)(((ulong)actorId << 32) | 0xB36F92);
}
public uint GetLeader()
{
return (uint)(((ulong)partyGroupWork._globalTemp.owner >> 32) & 0xFFFFFFFF);
}
public uint GetIdForName(string name)
{
for (int i = 0; i < members.Count; i++)
{
if (Server.GetServer().GetNameForId(members[i]).Equals(name))
{
return members[i];
}
}
return 0;
}
public bool IsInParty(uint charaId)
{
return members.Contains(charaId);
}
public override void SendInitWorkValues(Session session)
{
SynchGroupWorkValuesPacket groupWork = new SynchGroupWorkValuesPacket(groupIndex);
groupWork.addProperty(this, "partyGroupWork._globalTemp.owner");
groupWork.setTarget("/_init");
SubPacket test = groupWork.buildPacket(session.sessionId);
session.clientConnection.QueuePacket(test);
test.DebugPrintSubPacket();
}
public override int GetMemberCount()
{
return members.Count;
}
public override uint GetTypeId()
{
return Group.PlayerPartyGroup;
}
public override List<GroupMember> BuildMemberList(uint id)
{
List<GroupMember> groupMembers = new List<GroupMember>();
groupMembers.Add(new GroupMember(id, -1, 0, false, true, Server.GetServer().GetNameForId(id)));
foreach (uint charaId in members)
{
if (charaId != id)
groupMembers.Add(new GroupMember(charaId, -1, 0, false, true, Server.GetServer().GetNameForId(charaId)));
}
return groupMembers;
}
public void OnPlayerJoin(Session inviteeSession)
{
for (int i = 0; i < members.Count; i++)
{
Session session = Server.GetServer().GetSession(members[i]);
if (session == null)
continue;
session.SendGameMessage(30427, 0x20, (Object)Server.GetServer().GetNameForId(inviteeSession.sessionId));
}
}
}
}

View file

@ -0,0 +1,93 @@
/*
===========================================================================
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 System.Collections.Generic;
using Meteor.Common;
using Meteor.World.Actor.Group.Work;
using Meteor.World.Packets.Send.Subpackets.Groups;
namespace Meteor.World.DataObjects.Group
{
class Relation : Group
{
public RelationWork work = new RelationWork();
private uint charaOther;
private ulong topicGroup;
public Relation(ulong groupIndex, uint host, uint other, uint command, ulong topicGroup) : base (groupIndex)
{
this.charaOther = other;
work._globalTemp.host = ((ulong)host << 32) | (0xc17909);
work._globalTemp.variableCommand = command;
this.topicGroup = topicGroup;
}
public uint GetHost()
{
return (uint)(((ulong)work._globalTemp.host >> 32) & 0xFFFFFFFF);
}
public uint GetOther()
{
return charaOther;
}
public override int GetMemberCount()
{
return 2;
}
public override uint GetTypeId()
{
return Group.GroupInvitationRelationGroup;
}
public ulong GetTopicGroupIndex()
{
return topicGroup;
}
public override List<GroupMember> BuildMemberList(uint id)
{
List<GroupMember> groupMembers = new List<GroupMember>();
uint hostId = (uint)((work._globalTemp.host >> 32) & 0xFFFFFFFF);
groupMembers.Add(new GroupMember(hostId, -1, 0, false, Server.GetServer().GetSession(hostId) != null, Server.GetServer().GetNameForId(hostId)));
groupMembers.Add(new GroupMember(charaOther, -1, 0, false, Server.GetServer().GetSession(charaOther) != null, Server.GetServer().GetNameForId(charaOther)));
return groupMembers;
}
public override void SendInitWorkValues(Session session)
{
SynchGroupWorkValuesPacket groupWork = new SynchGroupWorkValuesPacket(groupIndex);
groupWork.addProperty(this, "work._globalTemp.host");
groupWork.addProperty(this, "work._globalTemp.variableCommand");
groupWork.setTarget("/_init");
SubPacket test = groupWork.buildPacket(session.sessionId);
test.DebugPrintSubPacket();
session.clientConnection.QueuePacket(test);
}
}
}

View file

@ -0,0 +1,99 @@
/*
===========================================================================
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 System;
using System.Collections.Generic;
using Meteor.Common;
using Meteor.World.Actor.Group.Work;
using Meteor.World.Packets.Send.Subpackets.Groups;
namespace Meteor.World.DataObjects.Group
{
class RetainerGroup : Group
{
public RetainerWork work = new RetainerWork();
public uint owner;
public List<RetainerGroupMember> members = new List<RetainerGroupMember>();
public RetainerGroup(ulong groupId, uint owner) : base(groupId)
{
this.owner = owner;
}
public void setRetainerProperties(int index, byte cdIDOffset, ushort placeName, byte condition, byte level)
{
if (members.Count >= index)
return;
work._memberSave[index].cdIDOffset = cdIDOffset;
work._memberSave[index].placeName = placeName;
work._memberSave[index].conditions = condition;
work._memberSave[index].level = level;
}
public override void SendInitWorkValues(Session session)
{
SynchGroupWorkValuesPacket groupWork = new SynchGroupWorkValuesPacket(groupIndex);
for (int i = 0; i < members.Count; i++)
{
work._memberSave[i].cdIDOffset = members[i].cdIDOffset;
work._memberSave[i].placeName = members[i].placeName;
work._memberSave[i].conditions = members[i].conditions;
work._memberSave[i].level = members[i].level;
groupWork.addProperty(this, String.Format("work._memberSave[{0}].cdIDOffset", i));
groupWork.addProperty(this, String.Format("work._memberSave[{0}].placeName", i));
groupWork.addProperty(this, String.Format("work._memberSave[{0}].conditions", i));
groupWork.addProperty(this, String.Format("work._memberSave[{0}].level", i));
}
groupWork.setTarget("/_init");
SubPacket test = groupWork.buildPacket(session.sessionId);
session.clientConnection.QueuePacket(test);
}
public override int GetMemberCount()
{
return members.Count + 1;
}
public override uint GetTypeId()
{
return Group.RetainerGroup;
}
public override List<GroupMember> BuildMemberList(uint id)
{
List<GroupMember> groupMembers = new List<GroupMember>();
//Add retainers
foreach (RetainerGroupMember member in members)
groupMembers.Add(new GroupMember(member.id, -1, 0, false, true, member.name));
//Add player
groupMembers.Add(new GroupMember(owner, -1, 0, false, true, Server.GetServer().GetNameForId(owner)));
return groupMembers;
}
}
}

View file

@ -0,0 +1,45 @@
/*
===========================================================================
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/>.
===========================================================================
*/
namespace Meteor.World.DataObjects.Group
{
class RetainerGroupMember
{
public uint id;
public string name;
public uint classActorId;
public byte cdIDOffset;
public ushort placeName;
public byte conditions;
public byte level;
public RetainerGroupMember(uint id, string name, uint classActorId, byte cdIDOffset, ushort placeName, byte conditions, byte level)
{
this.id = id;
this.name = name;
this.classActorId = classActorId;
this.cdIDOffset = cdIDOffset;
this.placeName = placeName;
this.conditions = conditions;
this.level = level;
}
}
}

View file

@ -0,0 +1,51 @@
/*
===========================================================================
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 Meteor.Common;
using Meteor.World.Packets.Send.Subpackets.Groups;
namespace Meteor.World.DataObjects.Group
{
class RetainerMeetingRelationGroup : Relation
{
public RetainerMeetingRelationGroup(ulong groupIndex, uint host, uint other, uint command, ulong topicGroup)
: base(groupIndex, host, other, command, topicGroup)
{
}
public override uint GetTypeId()
{
return Group.RetainerMeetingRelationGroup;
}
public override void SendInitWorkValues(Session session)
{
SynchGroupWorkValuesPacket groupWork = new SynchGroupWorkValuesPacket(groupIndex);
groupWork.setTarget("/_init");
SubPacket test = groupWork.buildPacket(session.sessionId);
test.DebugPrintSubPacket();
session.clientConnection.QueuePacket(test);
}
}
}

View file

@ -0,0 +1,37 @@
/*
===========================================================================
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 System;
namespace Meteor.World.DataObjects
{
class LuaParam
{
public int typeID;
public Object value;
public LuaParam(int type, Object value)
{
this.typeID = type;
this.value = value;
}
}
}

View file

@ -0,0 +1,406 @@
/*
===========================================================================
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 System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Meteor.Common;
namespace Meteor.World.DataObjects
{
class LuaUtils
{
public class Type7Param
{
public uint actorId;
public byte unknown;
public byte slot;
public byte inventoryType;
public Type7Param(uint actorId, byte unknown, byte slot, byte inventoryType)
{
this.actorId = actorId;
this.unknown = unknown;
this.slot = slot;
this.inventoryType = inventoryType;
}
}
public class Type9Param
{
public ulong item1;
public ulong item2;
public Type9Param(ulong item1, ulong item2)
{
this.item1 = item1;
this.item2 = item2;
}
}
public static List<LuaParam> ReadLuaParams(BinaryReader reader)
{
List<LuaParam> luaParams = new List<LuaParam>();
bool isDone = false;
while (true)
{
byte code = reader.ReadByte();
object value = null;
bool wasNil = false;
switch (code)
{
case 0x0: //Int32
value = Utils.SwapEndian(reader.ReadInt32());
break;
case 0x1: //Int32
value = Utils.SwapEndian(reader.ReadUInt32());
break;
case 0x2: //Null Termed String
List<byte> list = new List<byte>();
while(true){
byte readByte = reader.ReadByte();
if (readByte == 0)
break;
list.Add(readByte);
}
value = Encoding.ASCII.GetString(list.ToArray());
break;
case 0x3: //Boolean True
value = true;
break;
case 0x4: //Boolean False
value = false;
break;
case 0x5: //Nil
wasNil = true;
break;
case 0x6: //Actor (By Id)
value = Utils.SwapEndian(reader.ReadUInt32());
break;
case 0x7: //Weird one used for inventory
uint type7ActorId = Utils.SwapEndian(reader.ReadUInt32());
byte type7Unknown = reader.ReadByte();
byte type7Slot = reader.ReadByte();
byte type7InventoryType = reader.ReadByte();
value = new Type7Param(type7ActorId, type7Unknown, type7Slot, type7InventoryType);
break;
case 0x9: //Two Longs (only storing first one)
value = new Type9Param(Utils.SwapEndian(reader.ReadUInt64()), Utils.SwapEndian(reader.ReadUInt64()));
break;
case 0xC: //Byte
value = reader.ReadByte();
break;
case 0x1B: //Short?
value = reader.ReadUInt16();
break;
case 0xF: //End
isDone = true;
continue;
}
if (isDone)
break;
if (value != null)
luaParams.Add(new LuaParam(code, value));
else if (wasNil)
luaParams.Add(new LuaParam(code, value));
}
return luaParams;
}
public static void WriteLuaParams(BinaryWriter writer, List<LuaParam> luaParams)
{
foreach (LuaParam l in luaParams)
{
if (l.typeID == 0x1)
writer.Write((Byte)0);
else
writer.Write((Byte)l.typeID);
switch (l.typeID)
{
case 0x0: //Int32
writer.Write((Int32)Utils.SwapEndian((Int32)l.value));
break;
case 0x1: //Int32
writer.Write((UInt32)Utils.SwapEndian((UInt32)l.value));
break;
case 0x2: //Null Termed String
string sv = (string)l.value;
writer.Write(Encoding.ASCII.GetBytes(sv), 0, Encoding.ASCII.GetByteCount(sv));
writer.Write((Byte)0);
break;
case 0x3: //Boolean True
break;
case 0x4: //Boolean False
break;
case 0x5: //Nil
break;
case 0x6: //Actor (By Id)
writer.Write((UInt32)Utils.SwapEndian((UInt32)l.value));
break;
case 0x7: //Weird one used for inventory
Type7Param type7 = (Type7Param)l.value;
writer.Write((UInt32)Utils.SwapEndian((UInt32)type7.actorId));
writer.Write((Byte)type7.unknown);
writer.Write((Byte)type7.slot);
writer.Write((Byte)type7.inventoryType);
break;
case 0x9: //Two Longs (only storing first one)
writer.Write((UInt64)Utils.SwapEndian(((Type9Param)l.value).item1));
writer.Write((UInt64)Utils.SwapEndian(((Type9Param)l.value).item2));
break;
case 0xC: //Byte
writer.Write((Byte)l.value);
break;
case 0x1B: //Short?
break;
case 0xF: //End
continue;
}
}
writer.Write((Byte)0xF);
}
public static List<LuaParam> ReadLuaParams(byte[] bytesIn)
{
List<LuaParam> luaParams = new List<LuaParam>();
using (MemoryStream memStream = new MemoryStream(bytesIn))
{
using (BinaryReader reader = new BinaryReader(memStream))
{
bool isDone = false;
while (true)
{
byte code = reader.ReadByte();
object value = null;
bool wasNil = false;
switch (code)
{
case 0x0: //Int32
value = Utils.SwapEndian(reader.ReadInt32());
break;
case 0x1: //Int32
value = Utils.SwapEndian(reader.ReadUInt32());
break;
case 0x2: //Null Termed String
List<byte> list = new List<byte>();
while (true)
{
byte readByte = reader.ReadByte();
if (readByte == 0)
break;
list.Add(readByte);
}
value = Encoding.ASCII.GetString(list.ToArray());
break;
case 0x3: //Boolean True
value = true;
break;
case 0x4: //Boolean False
value = false;
break;
case 0x5: //Nil
wasNil = true;
break;
case 0x6: //Actor (By Id)
value = Utils.SwapEndian(reader.ReadUInt32());
break;
case 0x7: //Weird one used for inventory
uint type7ActorId = Utils.SwapEndian(reader.ReadUInt32());
byte type7Unknown = reader.ReadByte();
byte type7Slot = reader.ReadByte();
byte type7InventoryType = reader.ReadByte();
value = new Type7Param(type7ActorId, type7Unknown, type7Slot, type7InventoryType);
break;
case 0x9: //Two Longs (only storing first one)
value = new Type9Param(Utils.SwapEndian(reader.ReadUInt64()), Utils.SwapEndian(reader.ReadUInt64()));
break;
case 0xC: //Byte
value = reader.ReadByte();
break;
case 0x1B: //Short?
value = reader.ReadUInt16();
break;
case 0xF: //End
isDone = true;
continue;
}
if (isDone)
break;
if (value != null)
luaParams.Add(new LuaParam(code, value));
else if (wasNil)
luaParams.Add(new LuaParam(code, value));
}
}
}
return luaParams;
}
public static List<LuaParam> CreateLuaParamList(params object[] list)
{
List<LuaParam> luaParams = new List<LuaParam>();
foreach (object o in list)
{
if (o != null && o.GetType().IsArray)
{
Array arrayO = (Array)o;
foreach (object o2 in arrayO)
AddToList(o2, luaParams);
}
else
AddToList(o, luaParams);
}
return luaParams;
}
private static void AddToList(object o, List<LuaParam> luaParams)
{
if (o is int)
{
luaParams.Add(new LuaParam(0x0, (int)o));
}
else if (o is uint)
{
luaParams.Add(new LuaParam(0x1, (uint)o));
}
else if (o is Double)
{
if (((double)o) % 1 == 0)
luaParams.Add(new LuaParam(0x0, (int)(double)o));
}
else if (o is string)
{
luaParams.Add(new LuaParam(0x2, (string)o));
}
else if (o is bool)
{
if (((bool)o))
luaParams.Add(new LuaParam(0x3, null));
else
luaParams.Add(new LuaParam(0x4, null));
}
else if (o == null)
{
luaParams.Add(new LuaParam(0x5, null));
}
else if (o is Session)
{
luaParams.Add(new LuaParam(0x6, (uint)((Session)o).sessionId));
}
else if (o is Type7Param)
{
luaParams.Add(new LuaParam(0x7, (Type7Param)o));
}
else if (o is Type9Param)
{
luaParams.Add(new LuaParam(0x9, (Type9Param)o));
}
else if (o is byte)
{
luaParams.Add(new LuaParam(0xC, (byte)o));
}
}
public static object[] CreateLuaParamObjectList(List <LuaParam> luaParams)
{
object[] list = new object[luaParams.Count];
for (int i = 0; i < list.Length; i++)
list[i] = luaParams[i].value;
return list;
}
public static string DumpParams(List<LuaParam> lParams)
{
if (lParams == null)
return "Param list was null?";
string dumpString = "";
for (int i = 0; i < lParams.Count; i++)
{
switch (lParams[i].typeID)
{
case 0x0: //Int32
dumpString += String.Format("0x{0:X}", (int)lParams[i].value);
break;
case 0x1: //Int32
dumpString += String.Format("0x{0:X}", (uint)lParams[i].value);
break;
case 0x2: //Null Termed String
dumpString += String.Format("\"{0}\"", (string)lParams[i].value);
break;
case 0x3: //Boolean True
dumpString += "true";
break;
case 0x4: //Boolean False
dumpString += "false";
break;
case 0x5: //NULL???
dumpString += "nil";
break;
case 0x6: //Actor (By Id)
dumpString += String.Format("0x{0:X}", (uint)lParams[i].value);
break;
case 0x7: //Weird one used for inventory
Type7Param type7Param = ((Type7Param)lParams[i].value);
dumpString += String.Format("Type7 Param: (0x{0:X}, 0x{1:X}, 0x{2:X}, 0x{3:X})", type7Param.actorId, type7Param.unknown, type7Param.slot, type7Param.inventoryType);
break;
case 0xC: //Byte
dumpString += String.Format("0x{0:X}", (byte)lParams[i].value);
break;
case 0x9: //Long (+ 8 bytes ignored)
Type9Param type9Param = ((Type9Param)lParams[i].value);
dumpString += String.Format("Type9 Param: (0x{0:X}, 0x{1:X})", type9Param.item1, type9Param.item2);
break;
case 0x1B: //Short?
dumpString += String.Format("0x{0:X}", (ushort)lParams[i].value);
break;
case 0xF: //End
break;
}
if (i != lParams.Count - 1)
dumpString += ", ";
}
return dumpString;
}
}
}

View file

@ -0,0 +1,94 @@
/*
===========================================================================
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 Meteor.World.Packets.Send.Subpackets;
namespace Meteor.World.DataObjects
{
class Session
{
public enum Channel {ZONE, CHAT};
public readonly uint sessionId;
public string characterName;
public uint currentZoneId;
public string activeLinkshellName = "";
public readonly ClientConnection clientConnection;
public readonly Channel type;
public ZoneServer routing1, routing2;
public Session(uint sessionId, ClientConnection connection, Channel type)
{
this.sessionId = sessionId;
this.clientConnection = connection;
this.type = type;
connection.owner = this;
Database.LoadZoneSessionInfo(this);
}
public void SendGameMessage(uint actorId, ushort textId, byte log, params object[] msgParams)
{
if (msgParams == null || msgParams.Length == 0)
{
clientConnection.QueuePacket(GameMessagePacket.BuildPacket(0x5FF80001, actorId, 0x5FF80001, textId, log));
}
else
clientConnection.QueuePacket(GameMessagePacket.BuildPacket(0x5FF80001, actorId, 0x5FF80001, textId, log, LuaUtils.CreateLuaParamList(msgParams)));
}
public void SendGameMessage( ushort textId, byte log, params object[] msgParams)
{
if (msgParams == null || msgParams.Length == 0)
clientConnection.QueuePacket(GameMessagePacket.BuildPacket(0x5FF80001, 0x5FF80001, textId, log));
else
clientConnection.QueuePacket(GameMessagePacket.BuildPacket(0x5FF80001, 0x5FF80001, textId, log, LuaUtils.CreateLuaParamList(msgParams)));
}
public void SendGameMessage( ushort textId, byte log, string customSender, params object[] msgParams)
{
if (msgParams == null || msgParams.Length == 0)
clientConnection.QueuePacket(GameMessagePacket.BuildPacket(0x5FF80001, 0x5FF80001, textId, customSender, log));
else
clientConnection.QueuePacket(GameMessagePacket.BuildPacket(0x5FF80001, 0x5FF80001, textId, customSender, log, LuaUtils.CreateLuaParamList(msgParams)));
}
public void SendGameMessage(ushort textId, byte log, uint displayId, params object[] msgParams)
{
if (msgParams == null || msgParams.Length == 0)
clientConnection.QueuePacket(GameMessagePacket.BuildPacket(0x5FF80001, 0x5FF80001, textId, displayId, log));
else
clientConnection.QueuePacket(GameMessagePacket.BuildPacket(0x5FF80001, 0x5FF80001, textId, displayId, log, LuaUtils.CreateLuaParamList(msgParams)));
}
public bool SetActiveLS(string name)
{
if (Database.SetActiveLS(this, name))
{
activeLinkshellName = name;
return true;
}
return false;
}
}
}

View file

@ -0,0 +1,188 @@
/*
===========================================================================
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 System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using Meteor.Common;
using Meteor.World.Packets.WorldPackets.Send;
namespace Meteor.World.DataObjects
{
class ZoneServer
{
public readonly string zoneServerIp;
public readonly int zoneServerPort;
public readonly List<uint> ownedZoneIds;
public bool isConnected = false;
public Socket zoneServerConnection;
private ClientConnection conn;
private byte[] buffer = new byte[0xFFFF];
public ZoneServer(string ip, int port, uint firstId)
{
zoneServerIp = ip;
zoneServerPort = port;
ownedZoneIds = new List<uint>();
ownedZoneIds.Add(firstId);
}
public void AddLoadedZone(uint id)
{
ownedZoneIds.Add(id);
}
public bool Connect()
{
Program.Log.Info("Connecting to zone server @ {0}:{1}", zoneServerIp, zoneServerPort);
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse(zoneServerIp), zoneServerPort);
zoneServerConnection = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
try
{
zoneServerConnection.Connect(remoteEP);
isConnected = true;
conn = new ClientConnection();
conn.socket = zoneServerConnection;
conn.buffer = new byte[0xFFFF];
try
{
zoneServerConnection.BeginReceive(conn.buffer, 0, conn.buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), conn);
}
catch (Exception e)
{
throw new ApplicationException("Error occured starting listeners, check inner exception", e);
}
}
catch (Exception)
{ Program.Log.Error("Failed to connect"); return false; }
return true;
}
public void SendPacket(SubPacket subpacket)
{
if (isConnected)
{
byte[] packetBytes = subpacket.GetBytes();
try
{
zoneServerConnection.Send(packetBytes);
}
catch (Exception e)
{ Program.Log.Error(e, "Weird case, socket was d/ced: {0}"); }
}
else
{
if (Connect())
SendPacket(subpacket);
}
}
private void ReceiveCallback(IAsyncResult result)
{
ClientConnection conn = (ClientConnection)result.AsyncState;
//Check if disconnected
if ((conn.socket.Poll(1, SelectMode.SelectRead) && conn.socket.Available == 0))
{
conn = null;
isConnected = false;
Program.Log.Info("Zone server @ {0}:{1} disconnected!", zoneServerIp, zoneServerPort);
return;
}
try
{
int bytesRead = conn.socket.EndReceive(result);
bytesRead += conn.lastPartialSize;
if (bytesRead >= 0)
{
int offset = 0;
//Build packets until can no longer or out of data
while (true)
{
SubPacket subpacket = SubPacket.CreatePacket(ref offset, conn.buffer, bytesRead);
//If can't build packet, break, else process another
if (subpacket == null)
break;
else
Server.GetServer().OnReceiveSubPacketFromZone(this, subpacket);
}
//Not all bytes consumed, transfer leftover to beginning
if (offset < bytesRead)
Array.Copy(conn.buffer, offset, conn.buffer, 0, bytesRead - offset);
conn.lastPartialSize = bytesRead - offset;
//Build any queued subpackets into basepackets and send
conn.FlushQueuedSendPackets();
if (offset < bytesRead)
//Need offset since not all bytes consumed
conn.socket.BeginReceive(conn.buffer, bytesRead - offset, conn.buffer.Length - (bytesRead - offset), SocketFlags.None, new AsyncCallback(ReceiveCallback), conn);
else
//All bytes consumed, full buffer available
conn.socket.BeginReceive(conn.buffer, 0, conn.buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), conn);
}
else
{
conn = null;
isConnected = false;
Program.Log.Info("Zone server @ {0}:{1} disconnected!", zoneServerIp, zoneServerPort);
}
}
catch (SocketException)
{
conn = null;
isConnected = false;
Program.Log.Info("Zone server @ {0}:{1} disconnected!", zoneServerIp, zoneServerPort);
}
}
public void SendSessionStart(Session session, bool isLogin = false)
{
SendPacket(SessionBeginPacket.BuildPacket(session, isLogin));
}
public void SendSessionEnd(Session session)
{
SendPacket(SessionEndPacket.BuildPacket(session));
}
public void SendSessionEnd(Session session, uint destinationZoneId, string destinationPrivateArea, byte spawnType, float spawnX, float spawnY, float spawnZ, float spawnRotation)
{
SendPacket(SessionEndPacket.BuildPacket(session, destinationZoneId, destinationPrivateArea, spawnType, spawnX, spawnY, spawnZ, spawnRotation));
}
}
}