Merged Ioncannon/ffxiv-classic-server into master

This commit is contained in:
CuriousJorge 2017-10-09 21:11:07 -04:00
commit 5ccc2435b0
656 changed files with 24304 additions and 4976 deletions

View File

@ -3,11 +3,11 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using FFXIVClassic.Common;
using NLog; using NLog;
using NLog.Targets; using NLog.Targets;
using Ionic.Zlib;
namespace FFXIVClassic_Map_Server.packets namespace FFXIVClassic.Common
{ {
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct BasePacketHeader public struct BasePacketHeader
@ -295,6 +295,41 @@ namespace FFXIVClassic_Map_Server.packets
return packet; return packet;
} }
/// <summary>
/// Builds a packet from the incoming buffer + offset. If a packet can be built, it is returned else null.
/// </summary>
/// <param name="offset">Current offset in buffer.</param>
/// <param name="buffer">Incoming buffer.</param>
/// <returns>Returns either a BasePacket or null if not enough data.</returns>
public static BasePacket CreatePacket(ref int offset, byte[] buffer, int bytesRead)
{
BasePacket newPacket = null;
//Too small to even get length
if (bytesRead <= offset)
return null;
ushort packetSize = BitConverter.ToUInt16(buffer, offset);
//Too small to whole packet
if (bytesRead < offset + packetSize)
return null;
if (buffer.Length < offset + packetSize)
return null;
try
{
newPacket = new BasePacket(buffer, ref offset);
}
catch (OverflowException)
{
return null;
}
return newPacket;
}
public static unsafe void EncryptPacket(Blowfish blowfish, BasePacket packet) public static unsafe void EncryptPacket(Blowfish blowfish, BasePacket packet)
{ {
var data = packet.data; var data = packet.data;
@ -347,6 +382,28 @@ namespace FFXIVClassic_Map_Server.packets
} }
} }
public static unsafe void DecompressPacket(ref BasePacket packet)
{
using (var compressedStream = new MemoryStream(packet.data))
using (var zipStream = new ZlibStream(compressedStream, Ionic.Zlib.CompressionMode.Decompress))
using (var resultStream = new MemoryStream())
{
zipStream.CopyTo(resultStream);
packet.data = resultStream.ToArray();
}
}
public static unsafe void CompressPacket(ref BasePacket packet)
{
using (var compressedStream = new MemoryStream(packet.data))
using (var zipStream = new ZlibStream(compressedStream, Ionic.Zlib.CompressionMode.Compress))
using (var resultStream = new MemoryStream())
{
zipStream.CopyTo(resultStream);
packet.data = resultStream.ToArray();
}
}
#endregion #endregion
} }

View File

@ -38,6 +38,9 @@
<Prefer32Bit>false</Prefer32Bit> <Prefer32Bit>false</Prefer32Bit>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="DotNetZip">
<HintPath>..\packages\DotNetZip.1.10.1\lib\net20\DotNetZip.dll</HintPath>
</Reference>
<Reference Include="MySql.Data, Version=6.9.8.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d, processorArchitecture=MSIL"> <Reference Include="MySql.Data, Version=6.9.8.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d, processorArchitecture=MSIL">
<HintPath>..\packages\MySql.Data.6.9.8\lib\net45\MySql.Data.dll</HintPath> <HintPath>..\packages\MySql.Data.6.9.8\lib\net45\MySql.Data.dll</HintPath>
<Private>True</Private> <Private>True</Private>
@ -56,12 +59,14 @@
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="BasePacket.cs" />
<Compile Include="Bitfield.cs" /> <Compile Include="Bitfield.cs" />
<Compile Include="Blowfish.cs" /> <Compile Include="Blowfish.cs" />
<Compile Include="EfficientHashTables.cs" /> <Compile Include="EfficientHashTables.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Sql.cs" /> <Compile Include="Sql.cs" />
<Compile Include="STA_INIFile.cs" /> <Compile Include="STA_INIFile.cs" />
<Compile Include="SubPacket.cs" />
<Compile Include="Utils.cs" /> <Compile Include="Utils.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -4,7 +4,7 @@ using FFXIVClassic.Common;
using NLog; using NLog;
using NLog.Targets; using NLog.Targets;
namespace FFXIVClassic_Lobby_Server.packets namespace FFXIVClassic.Common
{ {
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct SubPacketHeader public struct SubPacketHeader
@ -72,26 +72,38 @@ namespace FFXIVClassic_Lobby_Server.packets
offset += header.subpacketSize; offset += header.subpacketSize;
} }
public SubPacket(ushort opcode, uint sourceId, uint targetId, byte[] data) public SubPacket(ushort opcode, uint sourceId, byte[] data) : this(true, opcode, sourceId, data) { }
public SubPacket(bool isGameMessage, ushort opcode, uint sourceId, byte[] data)
{ {
header = new SubPacketHeader(); header = new SubPacketHeader();
gameMessage = new GameMessageHeader();
gameMessage.opcode = opcode; if (isGameMessage)
{
gameMessage = new GameMessageHeader();
gameMessage.opcode = opcode;
gameMessage.timestamp = Utils.UnixTimeStampUTC();
gameMessage.unknown4 = 0x14;
gameMessage.unknown5 = 0x00;
gameMessage.unknown6 = 0x00;
}
header.sourceId = sourceId; header.sourceId = sourceId;
header.targetId = targetId; header.targetId = 0;
gameMessage.timestamp = Utils.UnixTimeStampUTC(); if (isGameMessage)
header.type = 0x03;
else
header.type = opcode;
header.type = 0x03;
header.unknown1 = 0x00; header.unknown1 = 0x00;
gameMessage.unknown4 = 0x14;
gameMessage.unknown5 = 0x00;
gameMessage.unknown6 = 0x00;
this.data = data; this.data = data;
header.subpacketSize = (ushort) (SUBPACKET_SIZE + GAMEMESSAGE_SIZE + data.Length); header.subpacketSize = (ushort) (SUBPACKET_SIZE + data.Length);
if (isGameMessage)
header.subpacketSize += GAMEMESSAGE_SIZE;
} }
public SubPacket(SubPacket original, uint newTargetId) public SubPacket(SubPacket original, uint newTargetId)
@ -105,6 +117,11 @@ namespace FFXIVClassic_Lobby_Server.packets
data = original.data; data = original.data;
} }
public void SetTargetId(uint target)
{
this.header.targetId = target;
}
public byte[] GetHeaderBytes() public byte[] GetHeaderBytes()
{ {
var size = Marshal.SizeOf(header); var size = Marshal.SizeOf(header);
@ -141,6 +158,41 @@ namespace FFXIVClassic_Lobby_Server.packets
return outBytes; return outBytes;
} }
/// <summary>
/// Builds a packet from the incoming buffer + offset. If a packet can be built, it is returned else null.
/// </summary>
/// <param name="offset">Current offset in buffer.</param>
/// <param name="buffer">Incoming buffer.</param>
/// <returns>Returns either a BasePacket or null if not enough data.</returns>
public static SubPacket CreatePacket(ref int offset, byte[] buffer, int bytesRead)
{
SubPacket newPacket = null;
//Too small to even get length
if (bytesRead <= offset)
return null;
ushort packetSize = BitConverter.ToUInt16(buffer, offset);
//Too small to whole packet
if (bytesRead < offset + packetSize)
return null;
if (buffer.Length < offset + packetSize)
return null;
try
{
newPacket = new SubPacket(buffer, ref offset);
}
catch (OverflowException)
{
return null;
}
return newPacket;
}
public void DebugPrintSubPacket() public void DebugPrintSubPacket()
{ {
#if DEBUG #if DEBUG
@ -157,6 +209,9 @@ namespace FFXIVClassic_Lobby_Server.packets
logger.ColorDebug(Utils.ByteArrayToHex(data, SUBPACKET_SIZE + GAMEMESSAGE_SIZE), logger.ColorDebug(Utils.ByteArrayToHex(data, SUBPACKET_SIZE + GAMEMESSAGE_SIZE),
ConsoleOutputColor.DarkMagenta); ConsoleOutputColor.DarkMagenta);
} }
else
logger.ColorDebug(Utils.ByteArrayToHex(data, SUBPACKET_SIZE),
ConsoleOutputColor.DarkMagenta);
#endif #endif
} }
} }

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="Microsoft.Net.Compilers" version="2.0.0-beta3" targetFramework="net45" developmentDependency="true" /> <package id="DotNetZip" version="1.10.1" targetFramework="net45" />
<package id="MySql.Data" version="6.9.8" targetFramework="net45" /> <package id="MySql.Data" version="6.9.8" targetFramework="net45" />
<package id="NLog" version="4.3.5" targetFramework="net45" /> <package id="NLog" version="4.3.5" targetFramework="net45" />
</packages> </packages>

View File

@ -1,6 +1,5 @@
using System; using System;
using System.Net.Sockets; using System.Net.Sockets;
using FFXIVClassic_Lobby_Server.packets;
using FFXIVClassic.Common; using FFXIVClassic.Common;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using Cyotek.Collections.Generic; using Cyotek.Collections.Generic;

View File

@ -1,6 +1,8 @@
using FFXIVClassic.Common; using FFXIVClassic.Common;
using System; using System;
using System.IO; using System.IO;
using System.Linq;
using System.Net;
namespace FFXIVClassic_Lobby_Server namespace FFXIVClassic_Lobby_Server
{ {
@ -23,7 +25,7 @@ namespace FFXIVClassic_Lobby_Server
if (!File.Exists("./lobby_config.ini")) if (!File.Exists("./lobby_config.ini"))
{ {
Program.Log.Error("FILE NOT FOUND!"); Program.Log.Error("FILE NOT FOUND!");
return false; Program.Log.Error("Loading defaults...");
} }
INIFile configIni = new INIFile("./lobby_config.ini"); INIFile configIni = new INIFile("./lobby_config.ini");
@ -40,5 +42,49 @@ namespace FFXIVClassic_Lobby_Server
return true; return true;
} }
public static void ApplyLaunchArgs(string[] launchArgs)
{
var args = (from arg in launchArgs select arg.ToLower().Trim().TrimStart('-')).ToList();
for (var i = 0; i + 1 < args.Count; i += 2)
{
var arg = args[i];
var val = args[i + 1];
var legit = false;
if (arg == "ip")
{
IPAddress ip;
if (IPAddress.TryParse(val, out ip) && (legit = true))
OPTIONS_BINDIP = val;
}
else if (arg == "port")
{
UInt16 port;
if (UInt16.TryParse(val, out port) && (legit = true))
OPTIONS_PORT = val;
}
else if (arg == "user" && (legit = true))
{
DATABASE_USERNAME = val;
}
else if (arg == "p" && (legit = true))
{
DATABASE_PASSWORD = val;
}
else if (arg == "db" && (legit = true))
{
DATABASE_NAME = val;
}
else if (arg == "host" && (legit = true))
{
DATABASE_HOST = val;
}
if (!legit)
{
Program.Log.Error("Invalid parameter <{0}> for argument: <--{1}> or argument doesnt exist!", val, arg);
}
}
}
} }
} }

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\Microsoft.Net.Compilers.2.0.0-beta3\build\Microsoft.Net.Compilers.props" Condition="Exists('..\packages\Microsoft.Net.Compilers.2.0.0-beta3\build\Microsoft.Net.Compilers.props') AND '$(OS)' == 'Windows_NT'" /> <Import Project="..\packages\Microsoft.Net.Compilers.2.0.0-beta3\build\Microsoft.Net.Compilers.props" Condition="Exists('..\packages\Microsoft.Net.Compilers.2.0.0-beta3\build\Microsoft.Net.Compilers.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props') AND '$(OS)' == 'Windows_NT'" /> <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@ -91,7 +91,6 @@
<Compile Include="Database.cs" /> <Compile Include="Database.cs" />
<Compile Include="dataobjects\World.cs" /> <Compile Include="dataobjects\World.cs" />
<Compile Include="PacketProcessor.cs" /> <Compile Include="PacketProcessor.cs" />
<Compile Include="packets\BasePacket.cs" />
<Compile Include="packets\receive\CharacterModifyPacket.cs" /> <Compile Include="packets\receive\CharacterModifyPacket.cs" />
<Compile Include="packets\receive\SecurityHandshakePacket.cs" /> <Compile Include="packets\receive\SecurityHandshakePacket.cs" />
<Compile Include="packets\receive\SelectCharacterPacket.cs" /> <Compile Include="packets\receive\SelectCharacterPacket.cs" />
@ -101,7 +100,6 @@
<Compile Include="packets\send\ErrorPacket.cs" /> <Compile Include="packets\send\ErrorPacket.cs" />
<Compile Include="packets\HardCoded_Packets.cs" /> <Compile Include="packets\HardCoded_Packets.cs" />
<Compile Include="packets\send\SelectCharacterConfirmPacket.cs" /> <Compile Include="packets\send\SelectCharacterConfirmPacket.cs" />
<Compile Include="packets\SubPacket.cs" />
<Compile Include="packets\send\CharacterListPacket.cs" /> <Compile Include="packets\send\CharacterListPacket.cs" />
<Compile Include="packets\send\ImportListPacket.cs" /> <Compile Include="packets\send\ImportListPacket.cs" />
<Compile Include="packets\send\AccountListPacket.cs" /> <Compile Include="packets\send\AccountListPacket.cs" />
@ -135,7 +133,7 @@
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup> <PropertyGroup>
<PostBuildEvent>xcopy "$(SolutionDir)data\lobby_config.ini" "$(SolutionDir)$(ProjectName)\$(OutDir)" /d</PostBuildEvent> <PostBuildEvent>xcopy "$(SolutionDir)data\lobby_config.ini" "$(SolutionDir)$(ProjectName)\$(OutDir)" /y</PostBuildEvent>
</PropertyGroup> </PropertyGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup> <PropertyGroup>

View File

@ -38,13 +38,13 @@
<target xsi:type="ColoredConsole" name="packets" <target xsi:type="ColoredConsole" name="packets"
layout="${message}"> layout="${message}">
<highlight-row <highlight-row
condition="equals('${logger}', 'FFXIVClassic_Lobby_Server.packets.BasePacket') and equals('${event-context:item=color}', '6')" condition="equals('${logger}', 'FFXIVClassic.Common.BasePacket') and equals('${event-context:item=color}', '6')"
backgroundColor="DarkYellow" foregroundColor="NoChange" /> backgroundColor="DarkYellow" foregroundColor="NoChange" />
<highlight-row <highlight-row
condition="equals('${logger}', 'FFXIVClassic_Lobby_Server.packets.SubPacket') and equals('${event-context:item=color}', '4')" condition="equals('${logger}', 'FFXIVClassic.Common.SubPacket') and equals('${event-context:item=color}', '4')"
backgroundColor="DarkRed" foregroundColor="NoChange" /> backgroundColor="DarkRed" foregroundColor="NoChange" />
<highlight-row <highlight-row
condition="equals('${logger}', 'FFXIVClassic_Lobby_Server.packets.SubPacket') and equals('${event-context:item=color}', '5')" condition="equals('${logger}', 'FFXIVClassic.Common.SubPacket') and equals('${event-context:item=color}', '5')"
backgroundColor="DarkMagenta" foregroundColor="NoChange" /> backgroundColor="DarkMagenta" foregroundColor="NoChange" />
</target> </target>
</targets> </targets>

View File

@ -90,14 +90,15 @@ namespace FFXIVClassic_Lobby_Server
if (userId == 0) if (userId == 0)
{ {
ErrorPacket errorPacket = new ErrorPacket(sessionPacket.sequence, 0, 0, 13001, "Your session has expired, please login again."); ErrorPacket errorPacket = new ErrorPacket(sessionPacket.sequence, 0, 0, 13001, "Your session has expired, please login again.");
SubPacket subpacket = errorPacket.BuildPacket(); SubPacket subpacket = errorPacket.BuildPacket();
BasePacket errorBasePacket = BasePacket.CreatePacket(subpacket, true, false); subpacket.SetTargetId(0xe0006868);
BasePacket.EncryptPacket(client.blowfish, errorBasePacket); BasePacket errorBasePacket = BasePacket.CreatePacket(subpacket, true, false);
client.QueuePacket(errorBasePacket); BasePacket.EncryptPacket(client.blowfish, errorBasePacket);
client.QueuePacket(errorBasePacket);
Program.Log.Info("Invalid session, kicking..."); Program.Log.Info("Invalid session, kicking...");
return; return;
} }
Program.Log.Info("USER ID: {0}", userId); Program.Log.Info("USER ID: {0}", userId);

View File

@ -20,13 +20,16 @@ namespace FFXIVClassic_Lobby_Server
TextWriterTraceListener myWriter = new TextWriterTraceListener(System.Console.Out); TextWriterTraceListener myWriter = new TextWriterTraceListener(System.Console.Out);
Debug.Listeners.Add(myWriter); Debug.Listeners.Add(myWriter);
#endif #endif
Program.Log.Info("--------FFXIV 1.0 Lobby Server--------"); Log.Info("==================================");
Log.Info("FFXIV Classic Lobby Server");
Log.Info("Version: 0.1");
Log.Info("==================================");
bool startServer = true; bool startServer = true;
//Load Config //Load Config
if (!ConfigConstants.Load()) ConfigConstants.Load();
startServer = false; ConfigConstants.ApplyLaunchArgs(args);
//Test DB Connection //Test DB Connection
Program.Log.Info("Testing DB connection to \"{0}\"... ", ConfigConstants.DATABASE_HOST); Program.Log.Info("Testing DB connection to \"{0}\"... ", ConfigConstants.DATABASE_HOST);

View File

@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Threading; using System.Threading;
using FFXIVClassic_Lobby_Server.packets;
using FFXIVClassic.Common; using FFXIVClassic.Common;
using NLog; using NLog;

View File

@ -1,361 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using FFXIVClassic.Common;
using NLog;
using NLog.Targets;
namespace FFXIVClassic_Lobby_Server.packets
{
[StructLayout(LayoutKind.Sequential)]
public struct BasePacketHeader
{
public byte isAuthenticated;
public byte isEncrypted;
public ushort connectionType;
public ushort packetSize;
public ushort numSubpackets;
public ulong timestamp; //Miliseconds
}
public class BasePacket
{
public const int TYPE_ZONE = 1;
public const int TYPE_CHAT = 2;
public const int BASEPACKET_SIZE = 0x10;
private static readonly Logger logger = LogManager.GetCurrentClassLogger();
public byte[] data;
public BasePacketHeader header;
//Loads a sniffed packet from a file
public unsafe BasePacket(string path)
{
var bytes = File.ReadAllBytes(path);
if (bytes.Length < BASEPACKET_SIZE)
throw new OverflowException("Packet Error: Packet was too small");
fixed (byte* pdata = &bytes[0])
{
header = (BasePacketHeader) Marshal.PtrToStructure(new IntPtr(pdata), typeof(BasePacketHeader));
}
if (bytes.Length < header.packetSize)
throw new OverflowException("Packet Error: Packet size didn't equal given size");
int packetSize = header.packetSize;
if (packetSize - BASEPACKET_SIZE != 0)
{
data = new byte[packetSize - BASEPACKET_SIZE];
Array.Copy(bytes, BASEPACKET_SIZE, data, 0, packetSize - BASEPACKET_SIZE);
}
else
data = new byte[0];
}
//Loads a sniffed packet from a byte array
public unsafe BasePacket(byte[] bytes)
{
if (bytes.Length < BASEPACKET_SIZE)
throw new OverflowException("Packet Error: Packet was too small");
fixed (byte* pdata = &bytes[0])
{
header = (BasePacketHeader) Marshal.PtrToStructure(new IntPtr(pdata), typeof(BasePacketHeader));
}
if (bytes.Length < header.packetSize)
throw new OverflowException("Packet Error: Packet size didn't equal given size");
int packetSize = header.packetSize;
data = new byte[packetSize - BASEPACKET_SIZE];
Array.Copy(bytes, BASEPACKET_SIZE, data, 0, packetSize - BASEPACKET_SIZE);
}
public unsafe BasePacket(byte[] bytes, ref int offset)
{
if (bytes.Length < offset + BASEPACKET_SIZE)
throw new OverflowException("Packet Error: Packet was too small");
fixed (byte* pdata = &bytes[offset])
{
header = (BasePacketHeader) Marshal.PtrToStructure(new IntPtr(pdata), typeof(BasePacketHeader));
}
int packetSize = header.packetSize;
if (bytes.Length < offset + header.packetSize)
throw new OverflowException("Packet Error: Packet size didn't equal given size");
data = new byte[packetSize - BASEPACKET_SIZE];
Array.Copy(bytes, offset + BASEPACKET_SIZE, data, 0, packetSize - BASEPACKET_SIZE);
offset += packetSize;
}
public BasePacket(BasePacketHeader header, byte[] data)
{
this.header = header;
this.data = data;
}
public List<SubPacket> GetSubpackets()
{
var subpackets = new List<SubPacket>(header.numSubpackets);
var offset = 0;
while (offset < data.Length)
subpackets.Add(new SubPacket(data, ref offset));
return subpackets;
}
public static unsafe BasePacketHeader GetHeader(byte[] bytes)
{
BasePacketHeader header;
if (bytes.Length < BASEPACKET_SIZE)
throw new OverflowException("Packet Error: Packet was too small");
fixed (byte* pdata = &bytes[0])
{
header = (BasePacketHeader) Marshal.PtrToStructure(new IntPtr(pdata), typeof(BasePacketHeader));
}
return header;
}
public byte[] GetHeaderBytes()
{
var size = Marshal.SizeOf(header);
var arr = new byte[size];
var ptr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(header, ptr, true);
Marshal.Copy(ptr, arr, 0, size);
Marshal.FreeHGlobal(ptr);
return arr;
}
public byte[] GetPacketBytes()
{
var outBytes = new byte[header.packetSize];
Array.Copy(GetHeaderBytes(), 0, outBytes, 0, BASEPACKET_SIZE);
Array.Copy(data, 0, outBytes, BASEPACKET_SIZE, data.Length);
return outBytes;
}
//Replaces all instances of the sniffed actorID with the given one
public void ReplaceActorID(uint actorID)
{
using (var mem = new MemoryStream(data))
{
using (var binWriter = new BinaryWriter(mem))
{
using (var binreader = new BinaryReader(mem))
{
while (binreader.BaseStream.Position + 4 < data.Length)
{
var read = binreader.ReadUInt32();
if (read == 0x029B2941 || read == 0x02977DC7 || read == 0x0297D2C8 || read == 0x0230d573 ||
read == 0x23317df || read == 0x23344a3 || read == 0x1730bdb) //Original ID
{
binWriter.BaseStream.Seek(binreader.BaseStream.Position - 0x4, SeekOrigin.Begin);
binWriter.Write(actorID);
}
}
}
}
}
}
//Replaces all instances of the sniffed actorID with the given one
public void ReplaceActorID(uint fromActorID, uint actorID)
{
using (var mem = new MemoryStream(data))
{
using (var binWriter = new BinaryWriter(mem))
{
using (var binreader = new BinaryReader(mem))
{
while (binreader.BaseStream.Position + 4 < data.Length)
{
var read = binreader.ReadUInt32();
if (read == fromActorID) //Original ID
{
binWriter.BaseStream.Seek(binreader.BaseStream.Position - 0x4, SeekOrigin.Begin);
binWriter.Write(actorID);
}
}
}
}
}
}
public void DebugPrintPacket()
{
#if DEBUG
logger.ColorDebug(
string.Format("IsAuth:{0} Size:0x{1:X}, NumSubpackets:{2}{3}{4}",
header.isAuthenticated, header.packetSize, header.numSubpackets,
Environment.NewLine, Utils.ByteArrayToHex(GetHeaderBytes())), ConsoleOutputColor.DarkYellow);
foreach (var sub in GetSubpackets())
{
sub.DebugPrintSubPacket();
}
#endif
}
#region Utility Functions
public static BasePacket CreatePacket(List<SubPacket> subpackets, bool isAuthed, bool isEncrypted)
{
//Create Header
var header = new BasePacketHeader();
byte[] data = null;
header.isAuthenticated = isAuthed ? (byte) 1 : (byte) 0;
header.isEncrypted = isEncrypted ? (byte) 1 : (byte) 0;
header.numSubpackets = (ushort) subpackets.Count;
header.packetSize = BASEPACKET_SIZE;
header.timestamp = Utils.MilisUnixTimeStampUTC();
//Get packet size
foreach (var subpacket in subpackets)
header.packetSize += subpacket.header.subpacketSize;
data = new byte[header.packetSize - 0x10];
//Add Subpackets
var offset = 0;
foreach (var subpacket in subpackets)
{
var subpacketData = subpacket.GetBytes();
Array.Copy(subpacketData, 0, data, offset, subpacketData.Length);
offset += (ushort) subpacketData.Length;
}
Debug.Assert(data != null && offset == data.Length && header.packetSize == 0x10 + offset);
var packet = new BasePacket(header, data);
return packet;
}
public static BasePacket CreatePacket(SubPacket subpacket, bool isAuthed, bool isEncrypted)
{
//Create Header
var header = new BasePacketHeader();
byte[] data = null;
header.isAuthenticated = isAuthed ? (byte) 1 : (byte) 0;
header.isEncrypted = isEncrypted ? (byte) 1 : (byte) 0;
header.numSubpackets = 1;
header.packetSize = BASEPACKET_SIZE;
header.timestamp = Utils.MilisUnixTimeStampUTC();
//Get packet size
header.packetSize += subpacket.header.subpacketSize;
data = new byte[header.packetSize - 0x10];
//Add Subpackets
var subpacketData = subpacket.GetBytes();
Array.Copy(subpacketData, 0, data, 0, subpacketData.Length);
Debug.Assert(data != null);
var packet = new BasePacket(header, data);
return packet;
}
public static BasePacket CreatePacket(byte[] data, bool isAuthed, bool isEncrypted)
{
Debug.Assert(data != null);
//Create Header
var header = new BasePacketHeader();
header.isAuthenticated = isAuthed ? (byte) 1 : (byte) 0;
header.isEncrypted = isEncrypted ? (byte) 1 : (byte) 0;
header.numSubpackets = 1;
header.packetSize = BASEPACKET_SIZE;
header.timestamp = Utils.MilisUnixTimeStampUTC();
//Get packet size
header.packetSize += (ushort) data.Length;
var packet = new BasePacket(header, data);
return packet;
}
public static unsafe void EncryptPacket(Blowfish blowfish, BasePacket packet)
{
var data = packet.data;
int size = packet.header.packetSize;
var offset = 0;
while (offset < data.Length)
{
if (data.Length < offset + SubPacket.SUBPACKET_SIZE)
throw new OverflowException("Packet Error: Subpacket was too small");
SubPacketHeader header;
fixed (byte* pdata = &data[offset])
{
header = (SubPacketHeader) Marshal.PtrToStructure(new IntPtr(pdata), typeof(SubPacketHeader));
}
if (data.Length < offset + header.subpacketSize)
throw new OverflowException("Packet Error: Subpacket size didn't equal subpacket data");
blowfish.Encipher(data, offset + 0x10, header.subpacketSize - 0x10);
offset += header.subpacketSize;
}
}
public static unsafe void DecryptPacket(Blowfish blowfish, ref BasePacket packet)
{
var data = packet.data;
int size = packet.header.packetSize;
var offset = 0;
while (offset < data.Length)
{
if (data.Length < offset + SubPacket.SUBPACKET_SIZE)
throw new OverflowException("Packet Error: Subpacket was too small");
SubPacketHeader header;
fixed (byte* pdata = &data[offset])
{
header = (SubPacketHeader) Marshal.PtrToStructure(new IntPtr(pdata), typeof(SubPacketHeader));
}
if (data.Length < offset + header.subpacketSize)
throw new OverflowException("Packet Error: Subpacket size didn't equal subpacket data");
blowfish.Decipher(data, offset + 0x10, header.subpacketSize - 0x10);
offset += header.subpacketSize;
}
}
#endregion
}
public static class LoggerExtensions
{
public static void ColorDebug(this Logger logger, string message, ConsoleOutputColor color)
{
var logEvent = new LogEventInfo(LogLevel.Debug, logger.Name, message);
logEvent.Properties["color"] = (int) color;
logger.Log(logEvent);
}
}
}

View File

@ -1,4 +1,5 @@
using FFXIVClassic_Lobby_Server.dataobjects; using FFXIVClassic.Common;
using FFXIVClassic_Lobby_Server.dataobjects;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
@ -60,7 +61,8 @@ namespace FFXIVClassic_Lobby_Server.packets
byte[] data = memStream.GetBuffer(); byte[] data = memStream.GetBuffer();
binWriter.Dispose(); binWriter.Dispose();
memStream.Dispose(); memStream.Dispose();
SubPacket subpacket = new SubPacket(OPCODE, 0xe0006868, 0xe0006868, data); SubPacket subpacket = new SubPacket(OPCODE, 0xe0006868, data);
subpacket.SetTargetId(0xe0006868);
subPackets.Add(subpacket); subPackets.Add(subpacket);
accountCount = 0; accountCount = 0;
} }
@ -87,7 +89,8 @@ namespace FFXIVClassic_Lobby_Server.packets
byte[] data = memStream.GetBuffer(); byte[] data = memStream.GetBuffer();
binWriter.Dispose(); binWriter.Dispose();
memStream.Dispose(); memStream.Dispose();
SubPacket subpacket = new SubPacket(OPCODE, 0xe0006868, 0xe0006868, data); SubPacket subpacket = new SubPacket(OPCODE, 0xe0006868, data);
subpacket.SetTargetId(0xe0006868);
subPackets.Add(subpacket); subPackets.Add(subpacket);
} }

View File

@ -1,4 +1,5 @@
using System; using FFXIVClassic.Common;
using System;
using System.IO; using System.IO;
using System.Text; using System.Text;
@ -58,7 +59,7 @@ namespace FFXIVClassic_Lobby_Server.packets
binWriter.Dispose(); binWriter.Dispose();
memStream.Dispose(); memStream.Dispose();
return new SubPacket(OPCODE, 0xe0006868, 0xe0006868, data); return new SubPacket(OPCODE, 0xe0006868, data);
} }
} }
} }

View File

@ -1,4 +1,5 @@
using FFXIVClassic_Lobby_Server.dataobjects; using FFXIVClassic.Common;
using FFXIVClassic_Lobby_Server.dataobjects;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
@ -86,7 +87,8 @@ namespace FFXIVClassic_Lobby_Server.packets
byte[] data = memStream.GetBuffer(); byte[] data = memStream.GetBuffer();
binWriter.Dispose(); binWriter.Dispose();
memStream.Dispose(); memStream.Dispose();
SubPacket subpacket = new SubPacket(OPCODE, 0xe0006868, 0xe0006868, data); SubPacket subpacket = new SubPacket(OPCODE, 0xe0006868, data);
subpacket.SetTargetId(0xe0006868);
subPackets.Add(subpacket); subPackets.Add(subpacket);
characterCount = 0; characterCount = 0;
} }
@ -132,7 +134,8 @@ namespace FFXIVClassic_Lobby_Server.packets
byte[] data = memStream.GetBuffer(); byte[] data = memStream.GetBuffer();
binWriter.Dispose(); binWriter.Dispose();
memStream.Dispose(); memStream.Dispose();
SubPacket subpacket = new SubPacket(OPCODE, 0xe0006868, 0xe0006868, data); SubPacket subpacket = new SubPacket(OPCODE, 0xe0006868, data);
subpacket.SetTargetId(0xe0006868);
subPackets.Add(subpacket); subPackets.Add(subpacket);
characterCount = 0; characterCount = 0;
} }
@ -144,7 +147,8 @@ namespace FFXIVClassic_Lobby_Server.packets
byte[] data = memStream.GetBuffer(); byte[] data = memStream.GetBuffer();
binWriter.Dispose(); binWriter.Dispose();
memStream.Dispose(); memStream.Dispose();
SubPacket subpacket = new SubPacket(OPCODE, 0xe0006868, 0xe0006868, data); SubPacket subpacket = new SubPacket(OPCODE, 0xe0006868, data);
subpacket.SetTargetId(0xe0006868);
subPackets.Add(subpacket); subPackets.Add(subpacket);
} }

View File

@ -1,4 +1,5 @@
using System; using FFXIVClassic.Common;
using System;
using System.IO; using System.IO;
using System.Text; using System.Text;
@ -37,7 +38,8 @@ namespace FFXIVClassic_Lobby_Server.packets
byte[] data = memStream.GetBuffer(); byte[] data = memStream.GetBuffer();
binWriter.Dispose(); binWriter.Dispose();
memStream.Dispose(); memStream.Dispose();
SubPacket subpacket = new SubPacket(OPCODE, 0xe0006868, 0xe0006868, data); SubPacket subpacket = new SubPacket(OPCODE, 0xe0006868, data);
subpacket.SetTargetId(0xe0006868);
return subpacket; return subpacket;
} }
} }

View File

@ -1,4 +1,5 @@
using System; using FFXIVClassic.Common;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text; using System.Text;
@ -63,7 +64,8 @@ namespace FFXIVClassic_Lobby_Server.packets
byte[] data = memStream.GetBuffer(); byte[] data = memStream.GetBuffer();
binWriter.Dispose(); binWriter.Dispose();
memStream.Dispose(); memStream.Dispose();
SubPacket subpacket = new SubPacket(OPCODE, 0xe0006868, 0xe0006868, data); SubPacket subpacket = new SubPacket(OPCODE, 0xe0006868, data);
subpacket.SetTargetId(0xe0006868);
subPackets.Add(subpacket); subPackets.Add(subpacket);
namesCount = 0; namesCount = 0;
} }
@ -90,7 +92,8 @@ namespace FFXIVClassic_Lobby_Server.packets
byte[] data = memStream.GetBuffer(); byte[] data = memStream.GetBuffer();
binWriter.Dispose(); binWriter.Dispose();
memStream.Dispose(); memStream.Dispose();
SubPacket subpacket = new SubPacket(OPCODE, 0xe0006868, 0xe0006868, data); SubPacket subpacket = new SubPacket(OPCODE, 0xe0006868, data);
subpacket.SetTargetId(0xe0006868);
subPackets.Add(subpacket); subPackets.Add(subpacket);
} }

View File

@ -1,4 +1,5 @@
using System; using FFXIVClassic.Common;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text; using System.Text;
@ -64,7 +65,8 @@ namespace FFXIVClassic_Lobby_Server.packets
byte[] data = memStream.GetBuffer(); byte[] data = memStream.GetBuffer();
binWriter.Dispose(); binWriter.Dispose();
memStream.Dispose(); memStream.Dispose();
SubPacket subpacket = new SubPacket(OPCODE, 0xe0006868, 0xe0006868, data); SubPacket subpacket = new SubPacket(OPCODE, 0xe0006868, data);
subpacket.SetTargetId(0xe0006868);
subPackets.Add(subpacket); subPackets.Add(subpacket);
retainerCount = 0; retainerCount = 0;
} }
@ -91,7 +93,8 @@ namespace FFXIVClassic_Lobby_Server.packets
byte[] data = memStream.GetBuffer(); byte[] data = memStream.GetBuffer();
binWriter.Dispose(); binWriter.Dispose();
memStream.Dispose(); memStream.Dispose();
SubPacket subpacket = new SubPacket(OPCODE, 0xe0006868, 0xe0006868, data); SubPacket subpacket = new SubPacket(OPCODE, 0xe0006868, data);
subpacket.SetTargetId(0xe0006868);
subPackets.Add(subpacket); subPackets.Add(subpacket);
} }

View File

@ -1,4 +1,5 @@
using System; using FFXIVClassic.Common;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text; using System.Text;
@ -48,7 +49,8 @@ namespace FFXIVClassic_Lobby_Server.packets
data = memStream.GetBuffer(); data = memStream.GetBuffer();
} }
SubPacket subpacket = new SubPacket(OPCODE, 0xe0006868, 0xe0006868, data); SubPacket subpacket = new SubPacket(OPCODE, 0xe0006868, data);
subpacket.SetTargetId(0xe0006868);
subPackets.Add(subpacket); subPackets.Add(subpacket);
return subPackets; return subPackets;

View File

@ -1,4 +1,5 @@
using FFXIVClassic_Lobby_Server.dataobjects; using FFXIVClassic.Common;
using FFXIVClassic_Lobby_Server.dataobjects;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
@ -62,7 +63,8 @@ namespace FFXIVClassic_Lobby_Server.packets
byte[] data = memStream.GetBuffer(); byte[] data = memStream.GetBuffer();
binWriter.Dispose(); binWriter.Dispose();
memStream.Dispose(); memStream.Dispose();
SubPacket subpacket = new SubPacket(OPCODE, 0xe0006868, 0xe0006868, data); SubPacket subpacket = new SubPacket(OPCODE, 0xe0006868, data);
subpacket.SetTargetId(0xe0006868);
subPackets.Add(subpacket); subPackets.Add(subpacket);
serverCount = 0; serverCount = 0;
} }
@ -89,7 +91,8 @@ namespace FFXIVClassic_Lobby_Server.packets
byte[] data = memStream.GetBuffer(); byte[] data = memStream.GetBuffer();
binWriter.Dispose(); binWriter.Dispose();
memStream.Dispose(); memStream.Dispose();
SubPacket subpacket = new SubPacket(OPCODE, 0xe0006868, 0xe0006868, data); SubPacket subpacket = new SubPacket(OPCODE, 0xe0006868, data);
subpacket.SetTargetId(0xe0006868);
subPackets.Add(subpacket); subPackets.Add(subpacket);
} }

View File

@ -1,72 +1,36 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
using System.Threading;
using FFXIVClassic.Common; using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.dataobjects; using FFXIVClassic_Map_Server.dataobjects;
using FFXIVClassic_Map_Server.packets;
using System.IO; using System.IO;
using FFXIVClassic_Map_Server.packets.send.actor; using FFXIVClassic_Map_Server.packets.send.actor;
using FFXIVClassic_Map_Server;
using FFXIVClassic_Map_Server.packets.send; using FFXIVClassic_Map_Server.packets.send;
using FFXIVClassic_Map_Server.dataobjects.chara;
using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.lua; using FFXIVClassic_Map_Server.lua;
using FFXIVClassic_Map_Server.actors.chara.player; using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.Properties;
namespace FFXIVClassic_Map_Server namespace FFXIVClassic_Map_Server
{ {
class CommandProcessor class CommandProcessor
{ {
private Dictionary<uint, ConnectedPlayer> mConnectedPlayerList; private static Dictionary<uint, ItemData> gamedataItems = Server.GetGamedataItems();
private static Dictionary<uint, Item> gamedataItems = Server.GetGamedataItems();
// For the moment, this is the only predefined item
// TODO: make a list/enum in the future so that items can be given by name, instead of by id
const UInt32 ITEM_GIL = 1000001; const UInt32 ITEM_GIL = 1000001;
public CommandProcessor(Dictionary<uint, ConnectedPlayer> playerList)
{
mConnectedPlayerList = playerList;
}
public void ChangeProperty(uint id, uint value, string target)
{
SetActorPropetyPacket ChangeProperty = new SetActorPropetyPacket(target);
ChangeProperty.SetTarget(target);
ChangeProperty.AddInt(id, value);
ChangeProperty.AddTarget();
foreach (KeyValuePair<uint, ConnectedPlayer> entry in mConnectedPlayerList)
{
SubPacket ChangePropertyPacket = ChangeProperty.BuildPacket((entry.Value.actorID), (entry.Value.actorID));
BasePacket packet = BasePacket.CreatePacket(ChangePropertyPacket, true, false);
packet.DebugPrintPacket();
entry.Value.QueuePacket(packet);
}
}
/// <summary> /// <summary>
/// We only use the default options for SendMessagePacket. /// We only use the default options for SendMessagePacket.
/// May as well make it less unwieldly to view /// May as well make it less unwieldly to view
/// </summary> /// </summary>
/// <param name="client"></param> /// <param name="client"></param>
/// <param name="message"></param> /// <param name="message"></param>
private void SendMessage(ConnectedPlayer client, String message) private void SendMessage(Session session, String message)
{ {
if (client != null) if (session != null)
client.GetActor().QueuePacket(SendMessagePacket.BuildPacket(client.actorID, client.actorID, SendMessagePacket.MESSAGE_TYPE_GENERAL_INFO, "", message)); session.GetActor().QueuePacket(SendMessagePacket.BuildPacket(session.id, SendMessagePacket.MESSAGE_TYPE_GENERAL_INFO, "", message));
} }
internal bool DoCommand(string input, ConnectedPlayer client) internal bool DoCommand(string input, Session session)
{ {
if (!input.Any() || input.Equals("")) if (!input.Any() || input.Equals(""))
return false; return false;
@ -81,14 +45,16 @@ namespace FFXIVClassic_Map_Server
) )
.SelectMany(str => str).ToArray(); .SelectMany(str => str).ToArray();
split = split.Select(temp => temp.ToLower()).ToArray(); // Ignore case on commands split = split.ToArray(); // Ignore case on commands
var cmd = split[0]; var cmd = split[0];
if (cmd.Any()) if (cmd.Any())
{ {
// if client isnt null, take player to be the player actor // if client isnt null, take player to be the player actor
var player = client?.GetActor(); Player player = null;
if (session != null)
player = session.GetActor();
if (cmd.Equals("help")) if (cmd.Equals("help"))
{ {
@ -125,11 +91,11 @@ namespace FFXIVClassic_Map_Server
if (split[0].Equals("reloaditems")) if (split[0].Equals("reloaditems"))
{ {
Program.Log.Info(String.Format("Got request to reload item gamedata")); Program.Log.Info(String.Format("Got request to reload item gamedata"));
SendMessage(client, "Reloading Item Gamedata..."); SendMessage(session, "Reloading Item Gamedata...");
gamedataItems.Clear(); gamedataItems.Clear();
gamedataItems = Database.GetItemGamedata(); gamedataItems = Database.GetItemGamedata();
Program.Log.Info(String.Format("Loaded {0} items.", gamedataItems.Count)); Program.Log.Info(String.Format("Loaded {0} items.", gamedataItems.Count));
SendMessage(client, String.Format("Loaded {0} items.", gamedataItems.Count)); SendMessage(session, String.Format("Loaded {0} items.", gamedataItems.Count));
return true; return true;
} }
#endregion #endregion
@ -139,7 +105,7 @@ namespace FFXIVClassic_Map_Server
{ {
if (split.Length == 4) if (split.Length == 4)
{ {
ChangeProperty(Utils.MurmurHash2(split[1], 0), Convert.ToUInt32(split[2], 16), split[3]); // ChangeProperty(Utils.MurmurHash2(split[1], 0), Convert.ToUInt32(split[2], 16), split[3]);
} }
return true; return true;
} }
@ -150,7 +116,7 @@ namespace FFXIVClassic_Map_Server
{ {
if (split.Length == 4) if (split.Length == 4)
{ {
ChangeProperty(Convert.ToUInt32(split[1], 16), Convert.ToUInt32(split[2], 16), split[3]); //ChangeProperty(Convert.ToUInt32(split[1], 16), Convert.ToUInt32(split[2], 16), split[3]);
} }
return true; return true;
} }

View File

@ -1,6 +1,11 @@
using FFXIVClassic.Common; using FFXIVClassic.Common;
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Net.Sockets;
using MoonSharp.Interpreter.Interop;
using System.Linq;
using System.Net;
namespace FFXIVClassic_Map_Server namespace FFXIVClassic_Map_Server
{ {
@ -8,9 +13,9 @@ namespace FFXIVClassic_Map_Server
{ {
public static String OPTIONS_BINDIP; public static String OPTIONS_BINDIP;
public static String OPTIONS_PORT; public static String OPTIONS_PORT;
public static bool OPTIONS_TIMESTAMP = false; public static bool OPTIONS_TIMESTAMP = false;
public static uint DATABASE_WORLDID; public static uint DATABASE_WORLDID;
public static String DATABASE_HOST; public static String DATABASE_HOST;
public static String DATABASE_PORT; public static String DATABASE_PORT;
public static String DATABASE_NAME; public static String DATABASE_NAME;
@ -24,13 +29,13 @@ namespace FFXIVClassic_Map_Server
if (!File.Exists("./map_config.ini")) if (!File.Exists("./map_config.ini"))
{ {
Program.Log.Error("FILE NOT FOUND"); Program.Log.Error("FILE NOT FOUND");
return false; Program.Log.Error("Loading defaults... ");
} }
INIFile configIni = new INIFile("./map_config.ini"); INIFile configIni = new INIFile("./map_config.ini");
ConfigConstants.OPTIONS_BINDIP = configIni.GetValue("General", "server_ip", "127.0.0.1"); ConfigConstants.OPTIONS_BINDIP = configIni.GetValue("General", "server_ip", "127.0.0.1");
ConfigConstants.OPTIONS_PORT = configIni.GetValue("General", "server_port", "54992"); ConfigConstants.OPTIONS_PORT = configIni.GetValue("General", "server_port", "1989");
ConfigConstants.OPTIONS_TIMESTAMP = configIni.GetValue("General", "showtimestamp", "true").ToLower().Equals("true"); ConfigConstants.OPTIONS_TIMESTAMP = configIni.GetValue("General", "showtimestamp", "true").ToLower().Equals("true");
ConfigConstants.DATABASE_WORLDID = UInt32.Parse(configIni.GetValue("Database", "worldid", "0")); ConfigConstants.DATABASE_WORLDID = UInt32.Parse(configIni.GetValue("Database", "worldid", "0"));
@ -42,5 +47,50 @@ namespace FFXIVClassic_Map_Server
return true; return true;
} }
public static void ApplyLaunchArgs(string[] launchArgs)
{
var args = (from arg in launchArgs select arg.ToLower().Trim().TrimStart('-')).ToList();
for (var i = 0; i + 1 < args.Count; i += 2)
{
var arg = args[i];
var val = args[i + 1];
var legit = false;
if (arg == "ip")
{
IPAddress ip;
if (IPAddress.TryParse(val, out ip) && (legit = true))
OPTIONS_BINDIP = val;
}
else if (arg == "port")
{
UInt16 port;
if (UInt16.TryParse(val, out port) && (legit = true))
OPTIONS_PORT = val;
}
else if (arg == "user" && (legit = true))
{
DATABASE_USERNAME = val;
}
else if (arg == "p" && (legit = true))
{
DATABASE_PASSWORD = val;
}
else if (arg == "db" && (legit = true))
{
DATABASE_NAME = val;
}
else if (arg == "host" && (legit = true))
{
DATABASE_HOST = val;
}
if (!legit)
{
Program.Log.Error("Invalid parameter <{0}> for argument: <--{1}> or argument doesnt exist!", val, arg);
}
}
}
} }
} }

View File

@ -5,7 +5,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using FFXIVClassic.Common; using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.utils; using FFXIVClassic_Map_Server.utils;
using FFXIVClassic_Map_Server.packets;
using FFXIVClassic_Map_Server.packets.send.player; using FFXIVClassic_Map_Server.packets.send.player;
using FFXIVClassic_Map_Server.dataobjects; using FFXIVClassic_Map_Server.dataobjects;
using FFXIVClassic_Map_Server.Actors; using FFXIVClassic_Map_Server.Actors;
@ -48,29 +48,6 @@ namespace FFXIVClassic_Map_Server
return id; return id;
} }
public static DBWorld GetServer(uint serverId)
{
using (var 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)))
{
DBWorld world = null;
try
{
conn.Open();
world = conn.Query<DBWorld>("SELECT * FROM servers WHERE id=@ServerId", new { ServerId = serverId }).SingleOrDefault();
}
catch (MySqlException e)
{
Program.Log.Error(e.ToString());
}
finally
{
conn.Dispose();
}
return world;
}
}
public static List<Npc> GetNpcList() public static List<Npc> GetNpcList()
{ {
using (var 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))) using (var 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)))
@ -94,11 +71,11 @@ namespace FFXIVClassic_Map_Server
} }
} }
public static Dictionary<uint, Item> GetItemGamedata() public static Dictionary<uint, ItemData> GetItemGamedata()
{ {
using (var 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))) using (var 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)))
{ {
Dictionary<uint, Item> gamedataItems = new Dictionary<uint, Item>(); Dictionary<uint, ItemData> gamedataItems = new Dictionary<uint, ItemData>();
try try
{ {
@ -108,11 +85,12 @@ namespace FFXIVClassic_Map_Server
SELECT SELECT
* *
FROM gamedata_items FROM gamedata_items
LEFT JOIN gamedata_items_equipment ON gamedata_items.catalogID = gamedata_items_equipment.catalogID LEFT JOIN gamedata_items_equipment ON gamedata_items.catalogID = gamedata_items_equipment.catalogID
LEFT JOIN gamedata_items_accessory ON gamedata_items.catalogID = gamedata_items_accessory.catalogID LEFT JOIN gamedata_items_accessory ON gamedata_items.catalogID = gamedata_items_accessory.catalogID
LEFT JOIN gamedata_items_armor ON gamedata_items.catalogID = gamedata_items_armor.catalogID LEFT JOIN gamedata_items_armor ON gamedata_items.catalogID = gamedata_items_armor.catalogID
LEFT JOIN gamedata_items_weapon ON gamedata_items.catalogID = gamedata_items_weapon.catalogID LEFT JOIN gamedata_items_weapon ON gamedata_items.catalogID = gamedata_items_weapon.catalogID
LEFT JOIN gamedata_items_graphics ON gamedata_items.catalogID = gamedata_items_graphics.catalogID LEFT JOIN gamedata_items_graphics ON gamedata_items.catalogID = gamedata_items_graphics.catalogID
LEFT JOIN gamedata_items_graphics_extra ON gamedata_items.catalogID = gamedata_items_graphics_extra.catalogID
"; ";
MySqlCommand cmd = new MySqlCommand(query, conn); MySqlCommand cmd = new MySqlCommand(query, conn);
@ -122,16 +100,16 @@ namespace FFXIVClassic_Map_Server
while (reader.Read()) while (reader.Read())
{ {
uint id = reader.GetUInt32("catalogID"); uint id = reader.GetUInt32("catalogID");
Item item = null; ItemData item = null;
if (Item.IsWeapon(id)) if (ItemData.IsWeapon(id))
item = new WeaponItem(reader); item = new WeaponItem(reader);
else if (Item.IsArmor(id)) else if (ItemData.IsArmor(id))
item = new ArmorItem(reader); item = new ArmorItem(reader);
else if (Item.IsAccessory(id)) else if (ItemData.IsAccessory(id))
item = new AccessoryItem(reader); item = new AccessoryItem(reader);
else else
item = new Item(reader); item = new ItemData(reader);
gamedataItems.Add(item.catalogID, item); gamedataItems.Add(item.catalogID, item);
} }
@ -150,6 +128,47 @@ namespace FFXIVClassic_Map_Server
} }
} }
public static Dictionary<uint, GuildleveData> GetGuildleveGamedata()
{
using (var 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)))
{
Dictionary<uint, GuildleveData> gamedataGuildleves = new Dictionary<uint, GuildleveData>();
try
{
conn.Open();
string query = @"
SELECT
*
FROM gamedata_guildleves
";
MySqlCommand cmd = new MySqlCommand(query, conn);
using (MySqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
uint id = reader.GetUInt32("id");
GuildleveData guildleve = new GuildleveData(reader);
gamedataGuildleves.Add(guildleve.id, guildleve);
}
}
}
catch (MySqlException e)
{
Program.Log.Error(e.ToString());
}
finally
{
conn.Dispose();
}
return gamedataGuildleves;
}
}
public static void SavePlayerAppearance(Player player) public static void SavePlayerAppearance(Player player)
{ {
string query; string query;
@ -259,7 +278,11 @@ namespace FFXIVClassic_Map_Server
positionY = @y, positionY = @y,
positionZ = @z, positionZ = @z,
rotation = @rot, rotation = @rot,
currentZoneId = @zoneId destinationZoneId = @destZone,
destinationSpawnType = @destSpawn,
currentZoneId = @zoneId,
currentPrivateArea = @privateArea,
currentPrivateAreaType = @privateAreaType
WHERE id = @charaId WHERE id = @charaId
"; ";
@ -270,6 +293,10 @@ namespace FFXIVClassic_Map_Server
cmd.Parameters.AddWithValue("@z", player.positionZ); cmd.Parameters.AddWithValue("@z", player.positionZ);
cmd.Parameters.AddWithValue("@rot", player.rotation); cmd.Parameters.AddWithValue("@rot", player.rotation);
cmd.Parameters.AddWithValue("@zoneId", player.zoneId); cmd.Parameters.AddWithValue("@zoneId", player.zoneId);
cmd.Parameters.AddWithValue("@privateArea", player.privateArea);
cmd.Parameters.AddWithValue("@privateAreaType", player.privateAreaType);
cmd.Parameters.AddWithValue("@destZone", player.destinationZone);
cmd.Parameters.AddWithValue("@destSpawn", player.destinationSpawnType);
cmd.ExecuteNonQuery(); cmd.ExecuteNonQuery();
} }
@ -318,6 +345,42 @@ namespace FFXIVClassic_Map_Server
} }
} }
public static void SavePlayerHomePoints(Player player)
{
string query;
MySqlCommand cmd;
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();
query = @"
UPDATE characters SET
homepoint = @homepoint,
homepointInn = @homepointInn
WHERE id = @charaId
";
cmd = new MySqlCommand(query, conn);
cmd.Parameters.AddWithValue("@charaId", player.actorId);
cmd.Parameters.AddWithValue("@homepoint", player.homepoint);
cmd.Parameters.AddWithValue("@homepointInn", player.homepointInn);
cmd.ExecuteNonQuery();
}
catch (MySqlException e)
{
Program.Log.Error(e.ToString());
}
finally
{
conn.Dispose();
}
}
}
public static void SaveQuest(Player player, Quest quest) public static void SaveQuest(Player player, Quest quest)
{ {
int slot = player.GetQuestSlot(quest.actorId); int slot = player.GetQuestSlot(quest.actorId);
@ -343,17 +406,18 @@ namespace FFXIVClassic_Map_Server
query = @" query = @"
INSERT INTO characters_quest_scenario INSERT INTO characters_quest_scenario
(characterId, slot, questId, questData, questFlags) (characterId, slot, questId, currentPhase, questData, questFlags)
VALUES VALUES
(@charaId, @slot, @questId, @questData, @questFlags) (@charaId, @slot, @questId, @phase, @questData, @questFlags)
ON DUPLICATE KEY UPDATE ON DUPLICATE KEY UPDATE
questData = @questData, questFlags = @questFlags questId = @questId, currentPhase = @phase, questData = @questData, questFlags = @questFlags
"; ";
cmd = new MySqlCommand(query, conn); cmd = new MySqlCommand(query, conn);
cmd.Parameters.AddWithValue("@charaId", player.actorId); cmd.Parameters.AddWithValue("@charaId", player.actorId);
cmd.Parameters.AddWithValue("@slot", slot); cmd.Parameters.AddWithValue("@slot", slot);
cmd.Parameters.AddWithValue("@questId", 0xFFFFF & quest.actorId); cmd.Parameters.AddWithValue("@questId", 0xFFFFF & quest.actorId);
cmd.Parameters.AddWithValue("@phase", quest.GetPhase());
cmd.Parameters.AddWithValue("@questData", quest.GetSerializedQuestData()); cmd.Parameters.AddWithValue("@questData", quest.GetSerializedQuestData());
cmd.Parameters.AddWithValue("@questFlags", quest.GetQuestFlags()); cmd.Parameters.AddWithValue("@questFlags", quest.GetQuestFlags());
@ -370,6 +434,209 @@ namespace FFXIVClassic_Map_Server
} }
} }
public static void MarkGuildleve(Player player, uint glId, bool isAbandoned, bool isCompleted)
{
string query;
MySqlCommand cmd;
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();
query = @"
UPDATE characters_quest_guildleve_regional
SET abandoned = @abandoned, completed = @completed
WHERE characterId = @charaId and guildleveId = @guildleveId
";
cmd = new MySqlCommand(query, conn);
cmd.Parameters.AddWithValue("@charaId", player.actorId);
cmd.Parameters.AddWithValue("@guildleveId", glId);
cmd.Parameters.AddWithValue("@abandoned", isAbandoned);
cmd.Parameters.AddWithValue("@completed", isCompleted);
cmd.ExecuteNonQuery();
}
catch (MySqlException e)
{
Program.Log.Error(e.ToString());
}
finally
{
conn.Dispose();
}
}
}
public static void SaveGuildleve(Player player, uint glId, int slot)
{
string query;
MySqlCommand cmd;
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();
query = @"
INSERT INTO characters_quest_guildleve_regional
(characterId, slot, guildleveId, abandoned, completed)
VALUES
(@charaId, @slot, @guildleveId, @abandoned, @completed)
ON DUPLICATE KEY UPDATE
guildleveId = @guildleveId, abandoned = @abandoned, completed = @completed
";
cmd = new MySqlCommand(query, conn);
cmd.Parameters.AddWithValue("@charaId", player.actorId);
cmd.Parameters.AddWithValue("@slot", slot);
cmd.Parameters.AddWithValue("@guildleveId", glId);
cmd.Parameters.AddWithValue("@abandoned", 0);
cmd.Parameters.AddWithValue("@completed", 0);
cmd.ExecuteNonQuery();
}
catch (MySqlException e)
{
Program.Log.Error(e.ToString());
}
finally
{
conn.Dispose();
}
}
}
public static void RemoveGuildleve(Player player, uint glId)
{
string query;
MySqlCommand cmd;
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();
query = @"
DELETE FROM characters_quest_guildleve_regional
WHERE characterId = @charaId and guildleveId = @guildleveId
";
cmd = new MySqlCommand(query, conn);
cmd.Parameters.AddWithValue("@charaId", player.actorId);
cmd.Parameters.AddWithValue("@guildleveId", glId);
cmd.ExecuteNonQuery();
}
catch (MySqlException e)
{
Program.Log.Error(e.ToString());
}
finally
{
conn.Dispose();
}
}
}
public static void RemoveQuest(Player player, uint questId)
{
string query;
MySqlCommand cmd;
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();
query = @"
DELETE FROM characters_quest_scenario
WHERE characterId = @charaId and questId = @questId
";
cmd = new MySqlCommand(query, conn);
cmd.Parameters.AddWithValue("@charaId", player.actorId);
cmd.Parameters.AddWithValue("@questId", 0xFFFFF & questId);
cmd.ExecuteNonQuery();
}
catch (MySqlException e)
{
Program.Log.Error(e.ToString());
}
finally
{
conn.Dispose();
}
}
}
public static void CompleteQuest(Player player, uint questId)
{
string query;
MySqlCommand cmd;
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();
query = @"
INSERT INTO characters_quest_completed
(characterId, questId)
VALUES
(@charaId, @questId)
ON DUPLICATE KEY UPDATE characterId=characterId
";
cmd = new MySqlCommand(query, conn);
cmd.Parameters.AddWithValue("@charaId", player.actorId);
cmd.Parameters.AddWithValue("@questId", 0xFFFFF & questId);
cmd.ExecuteNonQuery();
}
catch (MySqlException e)
{
Program.Log.Error(e.ToString());
}
finally
{
conn.Dispose();
}
}
}
public static bool IsQuestCompleted(Player player, uint questId)
{
bool isCompleted = false;
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();
MySqlCommand cmd = new MySqlCommand("SELECT * FROM characters_quest_completed WHERE characterId = @charaId and questId = @questId", conn);
cmd.Parameters.AddWithValue("@charaId", player.actorId);
cmd.Parameters.AddWithValue("@questId", questId);
isCompleted = cmd.ExecuteScalar() != null;
}
catch (MySqlException e)
{
Program.Log.Error(e.ToString());
}
finally
{
conn.Dispose();
}
}
return isCompleted;
}
public static void LoadPlayerCharacter(Player player) public static void LoadPlayerCharacter(Player player)
{ {
string query; string query;
@ -403,7 +670,13 @@ namespace FFXIVClassic_Map_Server
tribe, tribe,
restBonus, restBonus,
achievementPoints, achievementPoints,
playTime playTime,
destinationZoneId,
destinationSpawnType,
currentPrivateArea,
currentPrivateAreaType,
homepoint,
homepointInn
FROM characters WHERE id = @charId"; FROM characters WHERE id = @charId";
cmd = new MySqlCommand(query, conn); cmd = new MySqlCommand(query, conn);
@ -421,7 +694,6 @@ namespace FFXIVClassic_Map_Server
player.currentMainState = reader.GetUInt16(5); player.currentMainState = reader.GetUInt16(5);
player.zoneId = reader.GetUInt32(6); player.zoneId = reader.GetUInt32(6);
player.isZoning = true; player.isZoning = true;
player.zone = Server.GetWorldManager().GetZone(player.zoneId);
player.gcCurrent = reader.GetByte(7); player.gcCurrent = reader.GetByte(7);
player.gcRankLimsa = reader.GetByte(8); player.gcRankLimsa = reader.GetByte(8);
player.gcRankGridania = reader.GetByte(9); player.gcRankGridania = reader.GetByte(9);
@ -435,6 +707,22 @@ namespace FFXIVClassic_Map_Server
player.playerWork.restBonusExpRate = reader.GetInt32(17); player.playerWork.restBonusExpRate = reader.GetInt32(17);
player.achievementPoints = reader.GetUInt32(18); player.achievementPoints = reader.GetUInt32(18);
player.playTime = reader.GetUInt32(19); player.playTime = reader.GetUInt32(19);
player.homepoint = reader.GetUInt32("homepoint");
player.homepointInn = reader.GetByte("homepointInn");
player.destinationZone = reader.GetUInt32("destinationZoneId");
player.destinationSpawnType = reader.GetByte("destinationSpawnType");
if (!reader.IsDBNull(reader.GetOrdinal("currentPrivateArea")))
player.privateArea = reader.GetString("currentPrivateArea");
player.privateAreaType = reader.GetUInt32("currentPrivateAreaType");
if (player.destinationZone != 0)
player.zoneId = player.destinationZone;
if (player.privateArea != null && !player.privateArea.Equals(""))
player.zone = Server.GetWorldManager().GetPrivateArea(player.zoneId, player.privateArea, player.privateAreaType);
else
player.zone = Server.GetWorldManager().GetZone(player.zoneId);
} }
} }
@ -690,7 +978,8 @@ namespace FFXIVClassic_Map_Server
slot, slot,
questId, questId,
questData, questData,
questFlags questFlags,
currentPhase
FROM characters_quest_scenario WHERE characterId = @charId"; FROM characters_quest_scenario WHERE characterId = @charId";
cmd = new MySqlCommand(query, conn); cmd = new MySqlCommand(query, conn);
@ -703,6 +992,7 @@ namespace FFXIVClassic_Map_Server
player.playerWork.questScenario[index] = 0xA0F00000 | reader.GetUInt32(1); player.playerWork.questScenario[index] = 0xA0F00000 | reader.GetUInt32(1);
string questData = null; string questData = null;
uint questFlags = 0; uint questFlags = 0;
uint currentPhase = 0;
if (!reader.IsDBNull(2)) if (!reader.IsDBNull(2))
questData = reader.GetString(2); questData = reader.GetString(2);
@ -714,8 +1004,11 @@ namespace FFXIVClassic_Map_Server
else else
questFlags = 0; questFlags = 0;
if (!reader.IsDBNull(4))
currentPhase = reader.GetUInt32(4);
string questName = Server.GetStaticActors(player.playerWork.questScenario[index]).actorName; string questName = Server.GetStaticActors(player.playerWork.questScenario[index]).actorName;
player.questScenario[index] = new Quest(player, player.playerWork.questScenario[index], questName, questData, questFlags); player.questScenario[index] = new Quest(player, player.playerWork.questScenario[index], questName, questData, questFlags, currentPhase);
} }
} }
@ -1246,6 +1539,82 @@ namespace FFXIVClassic_Map_Server
return cheevosPacket.BuildPacket(player.actorId); return cheevosPacket.BuildPacket(player.actorId);
} }
public static bool CreateLinkshell(Player player, string lsName, ushort lsCrest)
{
bool success = false;
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 = @"
INSERT INTO server_linkshells
(name, master, crest)
VALUES
(@lsName, @master, @crest)
;
";
MySqlCommand cmd = new MySqlCommand(query, conn);
cmd.Parameters.AddWithValue("@lsName", lsName);
cmd.Parameters.AddWithValue("@master", player.actorId);
cmd.Parameters.AddWithValue("@crest", lsCrest);
cmd.ExecuteNonQuery();
success = true;
}
catch (MySqlException e)
{
Program.Log.Error(e.ToString());
}
finally
{
conn.Dispose();
}
}
return success;
}
public static void SaveNpcLS(Player player, uint npcLSId, bool isCalling, bool isExtra)
{
string query;
MySqlCommand cmd;
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();
query = @"
INSERT INTO characters_npclinkshell
(characterId, npcLinkshellId, isCalling, isExtra)
VALUES
(@charaId, @lsId, @calling, @extra)
ON DUPLICATE KEY UPDATE
characterId = @charaId, npcLinkshellId = @lsId, isCalling = @calling, isExtra = @extra
";
cmd = new MySqlCommand(query, conn);
cmd.Parameters.AddWithValue("@charaId", player.actorId);
cmd.Parameters.AddWithValue("@lsId", npcLSId);
cmd.Parameters.AddWithValue("@calling", isCalling ? 1 : 0);
cmd.Parameters.AddWithValue("@extra", isExtra ? 1 : 0);
cmd.ExecuteNonQuery();
}
catch (MySqlException e)
{
Program.Log.Error(e.ToString());
}
finally
{
conn.Dispose();
}
}
}
public static bool SaveSupportTicket(GMSupportTicketPacket gmTicket, string playerName) public static bool SaveSupportTicket(GMSupportTicketPacket gmTicket, string playerName)
{ {
@ -1556,4 +1925,5 @@ namespace FFXIVClassic_Map_Server
} }
} }
} }

View File

@ -35,6 +35,9 @@
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>
<PropertyGroup>
<RunPostBuildEvent>Always</RunPostBuildEvent>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Cyotek.Collections.Generic.CircularBuffer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=58daa28b0b2de221, processorArchitecture=MSIL"> <Reference Include="Cyotek.Collections.Generic.CircularBuffer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=58daa28b0b2de221, processorArchitecture=MSIL">
<HintPath>..\packages\Cyotek.CircularBuffer.1.0.0.0\lib\net20\Cyotek.Collections.Generic.CircularBuffer.dll</HintPath> <HintPath>..\packages\Cyotek.CircularBuffer.1.0.0.0\lib\net20\Cyotek.Collections.Generic.CircularBuffer.dll</HintPath>
@ -73,6 +76,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="actors\area\PrivateArea.cs" /> <Compile Include="actors\area\PrivateArea.cs" />
<Compile Include="actors\area\PrivateAreaContent.cs" />
<Compile Include="actors\area\SpawnLocation.cs" /> <Compile Include="actors\area\SpawnLocation.cs" />
<Compile Include="actors\area\Zone.cs" /> <Compile Include="actors\area\Zone.cs" />
<Compile Include="actors\chara\npc\ActorClass.cs" /> <Compile Include="actors\chara\npc\ActorClass.cs" />
@ -83,17 +87,28 @@
<Compile Include="actors\chara\Work.cs" /> <Compile Include="actors\chara\Work.cs" />
<Compile Include="actors\debug\Debug.cs" /> <Compile Include="actors\debug\Debug.cs" />
<Compile Include="actors\director\Director.cs" /> <Compile Include="actors\director\Director.cs" />
<Compile Include="actors\director\OpeningDirector.cs" /> <Compile Include="actors\director\GuildleveDirector.cs" />
<Compile Include="actors\director\quest\QuestDirectorMan0g001.cs" /> <Compile Include="actors\director\Work\GuildleveWork.cs" />
<Compile Include="actors\director\quest\QuestDirectorMan0l001.cs" />
<Compile Include="actors\director\quest\QuestDirectorMan0u001.cs" />
<Compile Include="actors\director\WeatherDirector.cs" />
<Compile Include="actors\EventList.cs" /> <Compile Include="actors\EventList.cs" />
<Compile Include="actors\group\GLContentGroup.cs" />
<Compile Include="actors\group\ContentGroup.cs" />
<Compile Include="actors\group\Work\ContentGroupWork.cs" />
<Compile Include="actors\group\Work\GlobalTemp.cs" />
<Compile Include="actors\group\Group.cs" />
<Compile Include="actors\group\MonsterParty.cs" />
<Compile Include="actors\group\Party.cs" />
<Compile Include="actors\group\Relation.cs" />
<Compile Include="actors\group\Work\GroupGlobalSave.cs" />
<Compile Include="actors\group\Work\GroupGlobalTemp.cs" />
<Compile Include="actors\group\Work\GroupMemberSave.cs" />
<Compile Include="actors\group\Work\PartyWork.cs" />
<Compile Include="actors\group\Work\RelationWork.cs" />
<Compile Include="actors\judge\Judge.cs" /> <Compile Include="actors\judge\Judge.cs" />
<Compile Include="actors\quest\Quest.cs" /> <Compile Include="actors\quest\Quest.cs" />
<Compile Include="actors\StaticActors.cs" /> <Compile Include="actors\StaticActors.cs" />
<Compile Include="actors\world\WorldMaster.cs" /> <Compile Include="actors\world\WorldMaster.cs" />
<Compile Include="ClientConnection.cs" /> <Compile Include="dataobjects\GuildleveData.cs" />
<Compile Include="dataobjects\ZoneConnection.cs" />
<Compile Include="CommandProcessor.cs" /> <Compile Include="CommandProcessor.cs" />
<Compile Include="ConfigConstants.cs" /> <Compile Include="ConfigConstants.cs" />
<Compile Include="Database.cs" /> <Compile Include="Database.cs" />
@ -110,24 +125,21 @@
<Compile Include="actors\chara\CharaWork.cs" /> <Compile Include="actors\chara\CharaWork.cs" />
<Compile Include="actors\chara\ParameterSave.cs" /> <Compile Include="actors\chara\ParameterSave.cs" />
<Compile Include="actors\chara\player\PlayerWork.cs" /> <Compile Include="actors\chara\player\PlayerWork.cs" />
<Compile Include="dataobjects\DBWorld.cs" />
<Compile Include="dataobjects\InventoryItem.cs" /> <Compile Include="dataobjects\InventoryItem.cs" />
<Compile Include="dataobjects\ConnectedPlayer.cs" /> <Compile Include="dataobjects\Session.cs" />
<Compile Include="dataobjects\Item.cs" /> <Compile Include="dataobjects\ItemData.cs" />
<Compile Include="dataobjects\RecruitmentDetails.cs" /> <Compile Include="dataobjects\RecruitmentDetails.cs" />
<Compile Include="dataobjects\SeamlessBoundry.cs" /> <Compile Include="dataobjects\SeamlessBoundry.cs" />
<Compile Include="dataobjects\SearchEntry.cs" /> <Compile Include="dataobjects\SearchEntry.cs" />
<Compile Include="lua\LuaEngine.cs" /> <Compile Include="lua\LuaEngine.cs" />
<Compile Include="lua\LuaEvent.cs" />
<Compile Include="lua\LuaParam.cs" /> <Compile Include="lua\LuaParam.cs" />
<Compile Include="lua\LuaNpc.cs" />
<Compile Include="lua\LuaPlayer.cs" />
<Compile Include="lua\LuaScript.cs" /> <Compile Include="lua\LuaScript.cs" />
<Compile Include="lua\LuaUtils.cs" />
<Compile Include="PacketProcessor.cs" /> <Compile Include="PacketProcessor.cs" />
<Compile Include="packets\BasePacket.cs" />
<Compile Include="packets\receive\ChatMessagePacket.cs" /> <Compile Include="packets\receive\ChatMessagePacket.cs" />
<Compile Include="packets\receive\events\EventUpdatePacket.cs" /> <Compile Include="packets\receive\events\EventUpdatePacket.cs" />
<Compile Include="packets\receive\events\EventStartPacket.cs" /> <Compile Include="packets\receive\events\EventStartPacket.cs" />
<Compile Include="packets\receive\GroupCreatedPacket.cs" />
<Compile Include="packets\receive\HandshakePacket.cs" /> <Compile Include="packets\receive\HandshakePacket.cs" />
<Compile Include="packets\receive\LangaugeCodePacket.cs" /> <Compile Include="packets\receive\LangaugeCodePacket.cs" />
<Compile Include="packets\receive\ParameterDataRequestPacket.cs" /> <Compile Include="packets\receive\ParameterDataRequestPacket.cs" />
@ -143,63 +155,74 @@
<Compile Include="packets\receive\supportdesk\GMSupportTicketPacket.cs" /> <Compile Include="packets\receive\supportdesk\GMSupportTicketPacket.cs" />
<Compile Include="packets\receive\supportdesk\GMTicketIssuesRequestPacket.cs" /> <Compile Include="packets\receive\supportdesk\GMTicketIssuesRequestPacket.cs" />
<Compile Include="packets\receive\_0x02ReceivePacket.cs" /> <Compile Include="packets\receive\_0x02ReceivePacket.cs" />
<Compile Include="packets\receive\_0x07Packet.cs" /> <Compile Include="packets\receive\ZoneInCompletePacket.cs" />
<Compile Include="packets\send\Actor\ActorDoEmotePacket.cs" /> <Compile Include="packets\send\actor\ActorDoEmotePacket.cs" />
<Compile Include="packets\send\Actor\ActorInstantiatePacket.cs" /> <Compile Include="packets\send\actor\ActorInstantiatePacket.cs" />
<Compile Include="packets\send\Actor\ActorSpecialGraphicPacket.cs" /> <Compile Include="packets\send\actor\ActorSpecialGraphicPacket.cs" />
<Compile Include="packets\send\Actor\BattleAction1Packet.cs" /> <Compile Include="packets\send\actor\battle\BattleAction.cs" />
<Compile Include="packets\send\Actor\battle\BattleAction.cs" /> <Compile Include="packets\send\actor\battle\BattleActionX00Packet.cs" />
<Compile Include="packets\send\Actor\battle\BattleActionX00Packet.cs" /> <Compile Include="packets\send\actor\battle\BattleActionX18Packet.cs" />
<Compile Include="packets\send\Actor\battle\BattleActionX18Packet.cs" /> <Compile Include="packets\send\actor\battle\BattleActionX10Packet.cs" />
<Compile Include="packets\send\Actor\battle\BattleActionX10Packet.cs" /> <Compile Include="packets\send\actor\DeleteAllActorsPacket.cs" />
<Compile Include="packets\send\Actor\DeleteAllActorsPacket.cs" /> <Compile Include="packets\send\actor\events\SetEventStatus.cs" />
<Compile Include="packets\send\Actor\events\SetEventStatus.cs" /> <Compile Include="packets\send\actor\events\SetNoticeEventCondition.cs" />
<Compile Include="packets\send\Actor\events\SetNoticeEventCondition.cs" /> <Compile Include="packets\send\actor\events\SetPushEventConditionWithTriggerBox.cs" />
<Compile Include="packets\send\Actor\events\SetPushEventConditionWithTriggerBox.cs" /> <Compile Include="packets\send\actor\events\SetPushEventConditionWithFan.cs" />
<Compile Include="packets\send\Actor\events\SetPushEventConditionWithFan.cs" /> <Compile Include="packets\send\actor\events\SetEmoteEventCondition.cs" />
<Compile Include="packets\send\Actor\events\SetEmoteEventCondition.cs" /> <Compile Include="packets\send\actor\events\SetTalkEventCondition.cs" />
<Compile Include="packets\send\Actor\events\SetTalkEventCondition.cs" /> <Compile Include="packets\send\actor\events\SetPushEventConditionWithCircle.cs" />
<Compile Include="packets\send\Actor\events\SetPushEventConditionWithCircle.cs" /> <Compile Include="packets\send\actor\inventory\InventoryRemoveX01Packet.cs" />
<Compile Include="packets\send\Actor\inventory\InventoryRemoveX01Packet.cs" /> <Compile Include="packets\send\actor\inventory\InventoryRemoveX08Packet.cs" />
<Compile Include="packets\send\Actor\inventory\InventoryRemoveX08Packet.cs" /> <Compile Include="packets\send\actor\inventory\InventoryRemoveX16Packet.cs" />
<Compile Include="packets\send\Actor\inventory\InventoryRemoveX16Packet.cs" /> <Compile Include="packets\send\actor\inventory\InventoryRemoveX32Packet.cs" />
<Compile Include="packets\send\Actor\inventory\InventoryRemoveX32Packet.cs" /> <Compile Include="packets\send\actor\inventory\InventoryRemoveX64Packet.cs" />
<Compile Include="packets\send\Actor\inventory\InventoryRemoveX64Packet.cs" /> <Compile Include="packets\send\actor\inventory\EquipmentListX64Packet.cs" />
<Compile Include="packets\send\Actor\inventory\EquipmentListX64Packet.cs" /> <Compile Include="packets\send\actor\inventory\EquipmentListX32Packet.cs" />
<Compile Include="packets\send\Actor\inventory\EquipmentListX32Packet.cs" /> <Compile Include="packets\send\actor\inventory\EquipmentListX16Packet.cs" />
<Compile Include="packets\send\Actor\inventory\EquipmentListX16Packet.cs" /> <Compile Include="packets\send\actor\inventory\InventoryListX01Packet.cs" />
<Compile Include="packets\send\Actor\inventory\InventoryListX01Packet.cs" /> <Compile Include="packets\send\actor\inventory\InventoryListX08Packet.cs" />
<Compile Include="packets\send\Actor\inventory\InventoryListX08Packet.cs" /> <Compile Include="packets\send\actor\inventory\InventoryListX16Packet.cs" />
<Compile Include="packets\send\Actor\inventory\InventoryListX16Packet.cs" /> <Compile Include="packets\send\actor\inventory\InventoryListX64Packet.cs" />
<Compile Include="packets\send\Actor\inventory\InventoryListX64Packet.cs" /> <Compile Include="packets\send\actor\inventory\InventoryListX32Packet.cs" />
<Compile Include="packets\send\Actor\inventory\InventoryListX32Packet.cs" /> <Compile Include="packets\send\actor\PlayAnimationOnActorPacket.cs" />
<Compile Include="packets\send\Actor\_0x132Packet.cs" /> <Compile Include="packets\send\actor\PlayBGAnimation.cs" />
<Compile Include="packets\send\Actor\SetActorIsZoningPacket.cs" /> <Compile Include="packets\send\actor\_0x132Packet.cs" />
<Compile Include="packets\send\Actor\battle\BattleActionX01Packet.cs" /> <Compile Include="packets\send\actor\SetActorIsZoningPacket.cs" />
<Compile Include="packets\send\Actor\inventory\EquipmentListX01Packet.cs" /> <Compile Include="packets\send\actor\battle\BattleActionX01Packet.cs" />
<Compile Include="packets\send\Actor\inventory\InventoryBeginChangePacket.cs" /> <Compile Include="packets\send\actor\inventory\EquipmentListX01Packet.cs" />
<Compile Include="packets\send\Actor\inventory\InventoryEndChangePacket.cs" /> <Compile Include="packets\send\actor\inventory\InventoryBeginChangePacket.cs" />
<Compile Include="packets\send\Actor\inventory\InventoryItemEndPacket.cs" /> <Compile Include="packets\send\actor\inventory\InventoryEndChangePacket.cs" />
<Compile Include="packets\send\Actor\inventory\InventoryItemPacket.cs" /> <Compile Include="packets\send\actor\inventory\InventoryItemEndPacket.cs" />
<Compile Include="packets\send\Actor\inventory\InventorySetBeginPacket.cs" /> <Compile Include="packets\send\actor\inventory\InventoryItemPacket.cs" />
<Compile Include="packets\send\Actor\inventory\InventorySetEndPacket.cs" /> <Compile Include="packets\send\actor\inventory\InventorySetBeginPacket.cs" />
<Compile Include="packets\send\Actor\inventory\EquipmentListX08Packet.cs" /> <Compile Include="packets\send\actor\inventory\InventorySetEndPacket.cs" />
<Compile Include="packets\send\Actor\RemoveActorPacket.cs" /> <Compile Include="packets\send\actor\inventory\EquipmentListX08Packet.cs" />
<Compile Include="packets\send\Actor\SetActorIconPacket.cs" /> <Compile Include="packets\send\actor\RemoveActorPacket.cs" />
<Compile Include="packets\send\Actor\SetActorIdleAnimationPacket.cs" /> <Compile Include="packets\send\actor\SetActorIconPacket.cs" />
<Compile Include="packets\send\Actor\SetActorStatusPacket.cs" /> <Compile Include="packets\send\actor\SetActorSubStatPacket.cs" />
<Compile Include="packets\send\Actor\_0xFPacket.cs" /> <Compile Include="packets\send\actor\SetActorStatusPacket.cs" />
<Compile Include="packets\send\actor\SetActorBGPropertiesPacket.cs" />
<Compile Include="packets\send\actor\_0xFPacket.cs" />
<Compile Include="packets\send\groups\CreateNamedGroup.cs" />
<Compile Include="packets\send\groups\CreateNamedGroupMultiple.cs" />
<Compile Include="packets\send\events\EndEventPacket.cs" /> <Compile Include="packets\send\events\EndEventPacket.cs" />
<Compile Include="packets\send\events\KickEventPacket.cs" /> <Compile Include="packets\send\events\KickEventPacket.cs" />
<Compile Include="packets\send\events\RunEventFunctionPacket.cs" /> <Compile Include="packets\send\events\RunEventFunctionPacket.cs" />
<Compile Include="packets\send\GameMessagePacket.cs" /> <Compile Include="packets\send\GameMessagePacket.cs" />
<Compile Include="packets\send\list\ListEntry.cs" /> <Compile Include="packets\send\groups\DeleteGroupPacket.cs" />
<Compile Include="packets\send\list\ListUtils.cs" /> <Compile Include="packets\send\groups\GroupHeaderPacket.cs" />
<Compile Include="packets\send\list\SetListPropertyPacket.cs" /> <Compile Include="packets\send\groups\GroupMember.cs" />
<Compile Include="packets\send\list\ListBeginPacket.cs" /> <Compile Include="packets\send\groups\GroupMembersBeginPacket.cs" />
<Compile Include="packets\send\list\ListEndPacket.cs" /> <Compile Include="packets\send\groups\GroupMembersEndPacket.cs" />
<Compile Include="packets\send\list\ListEntriesEndPacket.cs" /> <Compile Include="packets\send\groups\ContentMembersX08Packet.cs" />
<Compile Include="packets\send\list\ListStartPacket.cs" /> <Compile Include="packets\send\groups\GroupMembersX08Packet.cs" />
<Compile Include="packets\send\groups\ContentMembersX16Packet.cs" />
<Compile Include="packets\send\groups\GroupMembersX16Packet.cs" />
<Compile Include="packets\send\groups\ContentMembersX32Packet.cs" />
<Compile Include="packets\send\groups\GroupMembersX32Packet.cs" />
<Compile Include="packets\send\groups\ContentMembersX64Packet.cs" />
<Compile Include="packets\send\groups\GroupMembersX64Packet.cs" />
<Compile Include="packets\send\groups\SynchGroupWorkValuesPacket.cs" />
<Compile Include="packets\send\player\GenericDataPacket.cs" /> <Compile Include="packets\send\player\GenericDataPacket.cs" />
<Compile Include="packets\send\player\SendAchievementRatePacket.cs" /> <Compile Include="packets\send\player\SendAchievementRatePacket.cs" />
<Compile Include="packets\send\player\SetCurrentJobPacket.cs" /> <Compile Include="packets\send\player\SetCurrentJobPacket.cs" />
@ -214,11 +237,10 @@
<Compile Include="packets\send\Actor\SetActorTargetPacket.cs" /> <Compile Include="packets\send\Actor\SetActorTargetPacket.cs" />
<Compile Include="packets\send\Actor\SetActorStatusAllPacket.cs" /> <Compile Include="packets\send\Actor\SetActorStatusAllPacket.cs" />
<Compile Include="packets\send\login\0x2Packet.cs" /> <Compile Include="packets\send\login\0x2Packet.cs" />
<Compile Include="packets\send\Actor\AddActorPacket.cs" /> <Compile Include="packets\send\actor\AddActorPacket.cs" />
<Compile Include="packets\send\Actor\MoveActorToPositionPacket.cs" /> <Compile Include="packets\send\actor\MoveActorToPositionPacket.cs" />
<Compile Include="packets\send\Actor\SetActorAppearancePacket.cs" /> <Compile Include="packets\send\actor\SetActorAppearancePacket.cs" />
<Compile Include="packets\send\Actor\SetActorPositionPacket.cs" /> <Compile Include="packets\send\actor\SetActorPositionPacket.cs" />
<Compile Include="packets\send\login\0x7ResponsePacket.cs" />
<Compile Include="packets\send\LogoutPacket.cs" /> <Compile Include="packets\send\LogoutPacket.cs" />
<Compile Include="packets\send\player\SetCompletedAchievementsPacket.cs" /> <Compile Include="packets\send\player\SetCompletedAchievementsPacket.cs" />
<Compile Include="packets\send\player\AchievementEarnedPacket.cs" /> <Compile Include="packets\send\player\AchievementEarnedPacket.cs" />
@ -228,9 +250,10 @@
<Compile Include="packets\send\player\SetHasGoobbuePacket.cs" /> <Compile Include="packets\send\player\SetHasGoobbuePacket.cs" />
<Compile Include="packets\send\player\SetHasChocoboPacket.cs" /> <Compile Include="packets\send\player\SetHasChocoboPacket.cs" />
<Compile Include="packets\send\player\SetLatestAchievementsPacket.cs" /> <Compile Include="packets\send\player\SetLatestAchievementsPacket.cs" />
<Compile Include="packets\send\player\SetPlayerItemStoragePacket.cs" />
<Compile Include="packets\send\player\SetPlayerDreamPacket.cs" /> <Compile Include="packets\send\player\SetPlayerDreamPacket.cs" />
<Compile Include="packets\send\player\SetPlayerTitlePacket.cs" /> <Compile Include="packets\send\player\SetPlayerTitlePacket.cs" />
<Compile Include="packets\send\player\_0x196Packet.cs" /> <Compile Include="packets\send\player\SetSpecialEventWorkPacket.cs" />
<Compile Include="packets\send\PongPacket.cs" /> <Compile Include="packets\send\PongPacket.cs" />
<Compile Include="packets\send\QuitPacket.cs" /> <Compile Include="packets\send\QuitPacket.cs" />
<Compile Include="packets\send\recruitment\CurrentRecruitmentDetailsPacket.cs" /> <Compile Include="packets\send\recruitment\CurrentRecruitmentDetailsPacket.cs" />
@ -258,12 +281,28 @@
<Compile Include="packets\send\_0x02Packet.cs" /> <Compile Include="packets\send\_0x02Packet.cs" />
<Compile Include="packets\send\_0x10Packet.cs" /> <Compile Include="packets\send\_0x10Packet.cs" />
<Compile Include="packets\send\_0xE2Packet.cs" /> <Compile Include="packets\send\_0xE2Packet.cs" />
<Compile Include="packets\SubPacket.cs" />
<Compile Include="packets\receive\PingPacket.cs" /> <Compile Include="packets\receive\PingPacket.cs" />
<Compile Include="packets\receive\UpdatePlayerPositionPacket.cs" /> <Compile Include="packets\receive\UpdatePlayerPositionPacket.cs" />
<Compile Include="packets\WorldPackets\Receive\ErrorPacket.cs" />
<Compile Include="packets\WorldPackets\Receive\PartySyncPacket.cs" />
<Compile Include="packets\WorldPackets\Receive\SessionEndPacket.cs" />
<Compile Include="packets\WorldPackets\Receive\SessionBeginPacket.cs" />
<Compile Include="packets\WorldPackets\Send\Group\CreateLinkshellPacket.cs" />
<Compile Include="packets\WorldPackets\Send\Group\DeleteLinkshellPacket.cs" />
<Compile Include="packets\WorldPackets\Send\Group\LinkshellInviteCancelPacket.cs" />
<Compile Include="packets\WorldPackets\Send\Group\LinkshellChangePacket.cs" />
<Compile Include="packets\WorldPackets\Send\Group\LinkshellRankChangePacket.cs" />
<Compile Include="packets\WorldPackets\Send\Group\ModifyLinkshellPacket.cs" />
<Compile Include="packets\WorldPackets\Send\Group\GroupInviteResultPacket.cs" />
<Compile Include="packets\WorldPackets\Send\Group\LinkshellInvitePacket.cs" />
<Compile Include="packets\WorldPackets\Send\Group\PartyInvitePacket.cs" />
<Compile Include="packets\WorldPackets\Send\Group\LinkshellLeavePacket.cs" />
<Compile Include="packets\WorldPackets\Send\Group\PartyLeavePacket.cs" />
<Compile Include="packets\WorldPackets\Send\Group\PartyModifyPacket.cs" />
<Compile Include="packets\WorldPackets\Send\SessionBeginConfirmPacket.cs" />
<Compile Include="packets\WorldPackets\Send\SessionEndConfirmPacket.cs" />
<Compile Include="Program.cs" /> <Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="lua\LuaUtils.cs" />
<Compile Include="Properties\Resources.Designer.cs"> <Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen> <AutoGen>True</AutoGen>
<DesignTime>True</DesignTime> <DesignTime>True</DesignTime>
@ -286,6 +325,7 @@
<SubType>Designer</SubType> <SubType>Designer</SubType>
</None> </None>
<None Include="packages.config" /> <None Include="packages.config" />
<Compile Include="packets\WorldPackets\Send\WorldRequestZoneChangePacket.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<EmbeddedResource Include="Properties\Resources.resx"> <EmbeddedResource Include="Properties\Resources.resx">
@ -295,9 +335,12 @@
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup> <PropertyGroup>
<PostBuildEvent>xcopy "$(SolutionDir)data\map_config.ini" "$(SolutionDir)$(ProjectName)\$(OutDir)" /d <PostBuildEvent>
xcopy "$(SolutionDir)data\scripts" "$(SolutionDir)$(ProjectName)\$(OutDir)scripts\" /e /d /y /s </PostBuildEvent>
xcopy "$(SolutionDir)data\staticactors.bin" "$(SolutionDir)$(ProjectName)\$(OutDir)" /d</PostBuildEvent> </PropertyGroup>
<PropertyGroup>
<PreBuildEvent>
</PreBuildEvent>
</PropertyGroup> </PropertyGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup> <PropertyGroup>

View File

@ -38,13 +38,13 @@
<target xsi:type="ColoredConsole" name="packets" <target xsi:type="ColoredConsole" name="packets"
layout="${message}"> layout="${message}">
<highlight-row <highlight-row
condition="equals('${logger}', 'FFXIVClassic_Map_Server.packets.BasePacket') and equals('${event-context:item=color}', '6')" condition="equals('${logger}', 'FFXIVClassic.Common.BasePacket') and equals('${event-context:item=color}', '6')"
backgroundColor="DarkYellow" foregroundColor="NoChange" /> backgroundColor="DarkYellow" foregroundColor="NoChange" />
<highlight-row <highlight-row
condition="equals('${logger}', 'FFXIVClassic_Map_Server.packets.SubPacket') and equals('${event-context:item=color}', '4')" condition="equals('${logger}', 'FFXIVClassic.Common.SubPacket') and equals('${event-context:item=color}', '4')"
backgroundColor="DarkRed" foregroundColor="NoChange" /> backgroundColor="DarkRed" foregroundColor="NoChange" />
<highlight-row <highlight-row
condition="equals('${logger}', 'FFXIVClassic_Map_Server.packets.SubPacket') and equals('${event-context:item=color}', '5')" condition="equals('${logger}', 'FFXIVClassic.Common.SubPacket') and equals('${event-context:item=color}', '5')"
backgroundColor="DarkMagenta" foregroundColor="NoChange" /> backgroundColor="DarkMagenta" foregroundColor="NoChange" />
</target> </target>
</targets> </targets>
@ -55,6 +55,7 @@
<logger name='FFXIVClassic_Map_Server.Program' minlevel='Trace' writeTo='console' /> <logger name='FFXIVClassic_Map_Server.Program' minlevel='Trace' writeTo='console' />
<logger name='FFXIVClassic_Map_Server.lua.*' minlevel='Trace' writeTo='console' /> <logger name='FFXIVClassic_Map_Server.lua.*' minlevel='Trace' writeTo='console' />
<logger name='FFXIVClassic_Map_Server.packets.*' minlevel='Debug' writeTo='packets' /> <logger name='FFXIVClassic_Map_Server.packets.*' minlevel='Debug' writeTo='packets' />
<logger name='FFXIVClassic.Common.*' minlevel='Debug' writeTo='packets' />
<!-- <!--
Write all events with minimal level of Debug (So Debug, Info, Warn, Error and Fatal, but not Trace) to "f" Write all events with minimal level of Debug (So Debug, Info, Warn, Error and Fatal, but not Trace) to "f"
<logger name="*" minlevel="Debug" writeTo="f" /> <logger name="*" minlevel="Debug" writeTo="f" />

View File

@ -1,5 +1,5 @@
using FFXIVClassic.Common; using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.packets;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
@ -18,408 +18,333 @@ using FFXIVClassic_Map_Server.packets.send.recruitment;
using FFXIVClassic_Map_Server.packets.receive.events; using FFXIVClassic_Map_Server.packets.receive.events;
using FFXIVClassic_Map_Server.lua; using FFXIVClassic_Map_Server.lua;
using FFXIVClassic_Map_Server.Actors; using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.packets.WorldPackets.Send;
using FFXIVClassic_Map_Server.packets.WorldPackets.Receive;
using FFXIVClassic_Map_Server.actors.director;
namespace FFXIVClassic_Map_Server namespace FFXIVClassic_Map_Server
{ {
class PacketProcessor class PacketProcessor
{ {
Server mServer; Server mServer;
CommandProcessor cp;
Dictionary<uint, ConnectedPlayer> mPlayers;
List<ClientConnection> mConnections;
public PacketProcessor(Server server, Dictionary<uint, ConnectedPlayer> playerList, List<ClientConnection> connectionList) public PacketProcessor(Server server)
{ {
mPlayers = playerList;
mConnections = connectionList;
mServer = server; mServer = server;
cp = new CommandProcessor(playerList);
} }
public void ProcessPacket(ClientConnection client, BasePacket packet) public void ProcessPacket(ZoneConnection client, SubPacket subpacket)
{ {
if (packet.header.isCompressed == 0x01) Session session = mServer.GetSession(subpacket.header.sourceId);
BasePacket.DecryptPacket(client.blowfish, ref packet);
List<SubPacket> subPackets = packet.GetSubpackets(); if (session == null && subpacket.gameMessage.opcode != 0x1000)
foreach (SubPacket subpacket in subPackets) return;
{
if (subpacket.header.type == 0x01) //Normal Game Opcode
switch (subpacket.gameMessage.opcode)
{ {
packet.DebugPrintPacket(); //World Server - Error
byte[] reply1Data = { case 0x100A:
0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ErrorPacket worldError = new ErrorPacket(subpacket.data);
0x18, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFD, 0xFF, 0xFF, switch (worldError.errorCode)
0xE5, 0x6E, 0x01, 0xE0, 0x00, 0x00, 0x00, 0x0
};
byte[] reply2Data = {
0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x38, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x2B, 0x5F, 0x26,
0x66, 0x00, 0x00, 0x00, 0xC8, 0xD6, 0xAF, 0x2B, 0x38, 0x2B, 0x5F, 0x26, 0xB8, 0x8D, 0xF0, 0x2B,
0xC8, 0xFD, 0x85, 0xFE, 0xA8, 0x7C, 0x5B, 0x09, 0x38, 0x2B, 0x5F, 0x26, 0xC8, 0xD6, 0xAF, 0x2B,
0xB8, 0x8D, 0xF0, 0x2B, 0x88, 0xAF, 0x5E, 0x26
};
BasePacket reply1 = new BasePacket(reply1Data);
BasePacket reply2 = new BasePacket(reply2Data);
//Write Timestamp into Reply1
using (MemoryStream mem = new MemoryStream(reply1.data))
{
using (BinaryWriter binReader = new BinaryWriter(mem))
{ {
binReader.BaseStream.Seek(0x14, SeekOrigin.Begin); case 0x01:
binReader.Write((UInt32)Utils.UnixTimeStampUTC()); session.GetActor().SendGameMessage(Server.GetWorldManager().GetActor(), 60005, 0x20);
}
}
//Read in Actor Id that owns this connection
uint actorID = 0;
using (MemoryStream mem = new MemoryStream(packet.data))
{
using (BinaryReader binReader = new BinaryReader(mem))
{
try
{
byte[] readIn = new byte[12];
binReader.BaseStream.Seek(0x14, SeekOrigin.Begin);
binReader.Read(readIn, 0, 12);
actorID = UInt32.Parse(Encoding.ASCII.GetString(readIn));
}
catch (Exception)
{ }
}
}
//Should never happen.... unless actor id IS 0!
if (actorID == 0)
break;
client.owner = actorID;
//Write Actor ID into reply2
using (MemoryStream mem = new MemoryStream(reply2.data))
{
using (BinaryWriter binReader = new BinaryWriter(mem))
{
binReader.BaseStream.Seek(0x10, SeekOrigin.Begin);
binReader.Write(actorID);
}
}
ConnectedPlayer player = null;
if (packet.header.connectionType == BasePacket.TYPE_ZONE)
{
while (mPlayers != null && !mPlayers.ContainsKey(client.owner))
{ }
player = mPlayers[client.owner];
}
//Create connected player if not Created
if (player == null)
{
player = new ConnectedPlayer(actorID);
mPlayers[actorID] = player;
}
player.SetConnection(packet.header.connectionType, client);
if (packet.header.connectionType == BasePacket.TYPE_ZONE)
Program.Log.Info("Got {0} connection for ActorID {1} @ {2}.", "zone", actorID, client.GetAddress());
else if (packet.header.connectionType == BasePacket.TYPE_CHAT)
Program.Log.Info("Got {0} connection for ActorID {1} @ {2}.", "chat", actorID, client.GetAddress());
//Create player actor
reply1.DebugPrintPacket();
client.QueuePacket(reply1);
client.QueuePacket(reply2);
break;
}
else if (subpacket.header.type == 0x07)
{
BasePacket init = Login0x7ResponsePacket.BuildPacket(BitConverter.ToUInt32(packet.data, 0x10), Utils.UnixTimeStampUTC(), 0x08);
//client.QueuePacket(init);
}
else if (subpacket.header.type == 0x08)
{
//Response, client's current [actorID][time]
//BasePacket init = Login0x7ResponsePacket.BuildPacket(BitConverter.ToUInt32(packet.data, 0x10), Utils.UnixTimeStampUTC(), 0x07);
//client.QueuePacket(init);
packet.DebugPrintPacket();
}
else if (subpacket.header.type == 0x03)
{
ConnectedPlayer player = null;
if(mPlayers.ContainsKey(client.owner))
player = mPlayers[client.owner];
if (player == null || !player.IsClientConnectionsReady())
return;
//Normal Game Opcode
switch (subpacket.gameMessage.opcode)
{
//Ping
case 0x0001:
//subpacket.DebugPrintSubPacket();
PingPacket pingPacket = new PingPacket(subpacket.data);
client.QueuePacket(BasePacket.CreatePacket(PongPacket.BuildPacket(player.actorID, pingPacket.time), true, false));
player.Ping();
break;
//Unknown
case 0x0002:
subpacket.DebugPrintSubPacket();
client.QueuePacket(_0x2Packet.BuildPacket(player.actorID), true, false);
Server.GetWorldManager().DoLogin(player.GetActor());
break;
//Chat Received
case 0x0003:
ChatMessagePacket chatMessage = new ChatMessagePacket(subpacket.data);
Program.Log.Info("Got type-{5} message: {0} @ {1}, {2}, {3}, Rot: {4}", chatMessage.message, chatMessage.posX, chatMessage.posY, chatMessage.posZ, chatMessage.posRot, chatMessage.logType);
subpacket.DebugPrintSubPacket();
if (chatMessage.message.StartsWith("!"))
{
if (cp.DoCommand(chatMessage.message, player))
continue;
}
player.GetActor().BroadcastPacket(SendMessagePacket.BuildPacket(player.actorID, player.actorID, chatMessage.logType, player.GetActor().customDisplayName, chatMessage.message), false);
break;
//Langauge Code
case 0x0006:
LangaugeCodePacket langCode = new LangaugeCodePacket(subpacket.data);
player.languageCode = langCode.languageCode;
break;
//Unknown - Happens a lot at login, then once every time player zones
case 0x0007:
//subpacket.DebugPrintSubPacket();
_0x07Packet unknown07 = new _0x07Packet(subpacket.data);
break;
//Update Position
case 0x00CA:
//Update Position
//subpacket.DebugPrintSubPacket();
UpdatePlayerPositionPacket posUpdate = new UpdatePlayerPositionPacket(subpacket.data);
player.UpdatePlayerActorPosition(posUpdate.x, posUpdate.y, posUpdate.z, posUpdate.rot, posUpdate.moveState);
player.GetActor().SendInstanceUpdate();
if (player.GetActor().IsInZoneChange())
player.GetActor().SetZoneChanging(false);
break;
//Set Target
case 0x00CD:
//subpacket.DebugPrintSubPacket();
SetTargetPacket setTarget = new SetTargetPacket(subpacket.data);
player.GetActor().currentTarget = setTarget.actorID;
player.GetActor().BroadcastPacket(SetActorTargetAnimatedPacket.BuildPacket(player.actorID, player.actorID, setTarget.actorID), true);
break;
//Lock Target
case 0x00CC:
LockTargetPacket lockTarget = new LockTargetPacket(subpacket.data);
player.GetActor().currentLockedTarget = lockTarget.actorID;
break;
//Start Event
case 0x012D:
subpacket.DebugPrintSubPacket();
EventStartPacket eventStart = new EventStartPacket(subpacket.data);
/*
if (eventStart.error != null)
{
player.errorMessage += eventStart.error;
if (eventStart.errorIndex == eventStart.errorNum - 1)
Program.Log.Error("\n"+player.errorMessage);
break; break;
} }
*/ break;
//World Server - Session Begin
case 0x1000:
subpacket.DebugPrintSubPacket();
Actor ownerActor = Server.GetStaticActors(eventStart.scriptOwnerActorID); SessionBeginPacket beginSessionPacket = new SessionBeginPacket(subpacket.data);
session = mServer.AddSession(subpacket.header.sourceId);
if (!beginSessionPacket.isLogin)
Server.GetWorldManager().DoZoneIn(session.GetActor(), false, session.GetActor().destinationSpawnType);
Program.Log.Info("{0} has been added to the session list.", session.GetActor().customDisplayName);
client.FlushQueuedSendPackets();
break;
//World Server - Session End
case 0x1001:
SessionEndPacket endSessionPacket = new SessionEndPacket(subpacket.data);
if (endSessionPacket.destinationZoneId == 0)
session.GetActor().CleanupAndSave();
else
session.GetActor().CleanupAndSave(endSessionPacket.destinationZoneId, endSessionPacket.destinationSpawnType, endSessionPacket.destinationX, endSessionPacket.destinationY, endSessionPacket.destinationZ, endSessionPacket.destinationRot);
Server.GetServer().RemoveSession(session.id);
Program.Log.Info("{0} has been removed from the session list.", session.GetActor().customDisplayName);
session.QueuePacket(SessionEndConfirmPacket.BuildPacket(session, endSessionPacket.destinationZoneId));
client.FlushQueuedSendPackets();
break;
//World Server - Party Synch
case 0x1020:
PartySyncPacket partySyncPacket = new PartySyncPacket(subpacket.data);
Server.GetWorldManager().PartyMemberListRecieved(partySyncPacket);
break;
//Ping
case 0x0001:
//subpacket.DebugPrintSubPacket();
PingPacket pingPacket = new PingPacket(subpacket.data);
session.QueuePacket(PongPacket.BuildPacket(session.id, pingPacket.time));
session.Ping();
break;
//Unknown
case 0x0002:
subpacket.DebugPrintSubPacket();
session.QueuePacket(_0x2Packet.BuildPacket(session.id));
client.FlushQueuedSendPackets();
break;
//Chat Received
case 0x0003:
ChatMessagePacket chatMessage = new ChatMessagePacket(subpacket.data);
//Program.Log.Info("Got type-{5} message: {0} @ {1}, {2}, {3}, Rot: {4}", chatMessage.message, chatMessage.posX, chatMessage.posY, chatMessage.posZ, chatMessage.posRot, chatMessage.logType);
if (chatMessage.message.StartsWith("!"))
{
if (Server.GetCommandProcessor().DoCommand(chatMessage.message, session))
return; ;
}
if (chatMessage.logType == SendMessagePacket.MESSAGE_TYPE_SAY || chatMessage.logType == SendMessagePacket.MESSAGE_TYPE_SHOUT)
session.GetActor().BroadcastPacket(SendMessagePacket.BuildPacket(session.id, chatMessage.logType, session.GetActor().customDisplayName, chatMessage.message), false);
break;
//Langauge Code (Client safe to send packets to now)
case 0x0006:
LangaugeCodePacket langCode = new LangaugeCodePacket(subpacket.data);
LuaEngine.GetInstance().CallLuaFunction(session.GetActor(), session.GetActor(), "onBeginLogin", true);
Server.GetWorldManager().DoZoneIn(session.GetActor(), true, 0x1);
LuaEngine.GetInstance().CallLuaFunction(session.GetActor(), session.GetActor(), "onLogin", true);
session.languageCode = langCode.languageCode;
break;
//Unknown - Happens a lot at login, then once every time player zones
case 0x0007:
//subpacket.DebugPrintSubPacket();
ZoneInCompletePacket zoneInCompletePacket = new ZoneInCompletePacket(subpacket.data);
break;
//Update Position
case 0x00CA:
//Update Position
UpdatePlayerPositionPacket posUpdate = new UpdatePlayerPositionPacket(subpacket.data);
session.UpdatePlayerActorPosition(posUpdate.x, posUpdate.y, posUpdate.z, posUpdate.rot, posUpdate.moveState);
session.GetActor().SendInstanceUpdate();
if (session.GetActor().IsInZoneChange())
session.GetActor().SetZoneChanging(false);
break;
//Set Target
case 0x00CD:
//subpacket.DebugPrintSubPacket();
SetTargetPacket setTarget = new SetTargetPacket(subpacket.data);
session.GetActor().currentTarget = setTarget.actorID;
session.GetActor().BroadcastPacket(SetActorTargetAnimatedPacket.BuildPacket(session.id, setTarget.actorID), true);
break;
//Lock Target
case 0x00CC:
LockTargetPacket lockTarget = new LockTargetPacket(subpacket.data);
session.GetActor().currentLockedTarget = lockTarget.actorID;
break;
//Start Event
case 0x012D:
subpacket.DebugPrintSubPacket();
EventStartPacket eventStart = new EventStartPacket(subpacket.data);
/*
if (eventStart.error != null)
{
player.errorMessage += eventStart.error;
if (eventStart.errorIndex == eventStart.errorNum - 1)
Program.Log.Error("\n"+player.errorMessage);
player.GetActor().currentEventOwner = eventStart.scriptOwnerActorID; break;
player.GetActor().currentEventName = eventStart.triggerName; }
*/
Actor ownerActor = Server.GetStaticActors(eventStart.scriptOwnerActorID);
session.GetActor().currentEventOwner = eventStart.scriptOwnerActorID;
session.GetActor().currentEventName = eventStart.triggerName;
if (ownerActor == null)
{
//Is it a instance actor?
ownerActor = session.GetActor().zone.FindActorInArea(session.GetActor().currentEventOwner);
if (ownerActor == null) if (ownerActor == null)
{ {
//Is it a instance actor? //Is it a Director?
ownerActor = Server.GetWorldManager().GetActorInWorld(player.GetActor().currentEventOwner); Director director = session.GetActor().GetDirector(eventStart.scriptOwnerActorID);
if (ownerActor == null) if (director != null)
ownerActor = director;
else
{ {
//Is it a Director? Program.Log.Debug("\n===Event START===\nCould not find actor 0x{0:X} for event started by caller: 0x{1:X}\nEvent Starter: {2}\nParams: {3}", eventStart.actorID, eventStart.scriptOwnerActorID, eventStart.triggerName, LuaUtils.DumpParams(eventStart.luaParams));
if (player.GetActor().currentDirector != null && player.GetActor().currentEventOwner == player.GetActor().currentDirector.actorId) break;
ownerActor = player.GetActor().currentDirector;
else
{
Program.Log.Debug("\n===Event START===\nCould not find actor 0x{0:X} for event started by caller: 0x{1:X}\nEvent Starter: {2}\nParams: {3}", eventStart.actorID, eventStart.scriptOwnerActorID, eventStart.triggerName, LuaUtils.DumpParams(eventStart.luaParams));
break;
}
} }
} }
}
player.GetActor().StartEvent(ownerActor, eventStart); session.GetActor().StartEvent(ownerActor, eventStart);
Program.Log.Debug("\n===Event START===\nSource Actor: 0x{0:X}\nCaller Actor: 0x{1:X}\nVal1: 0x{2:X}\nVal2: 0x{3:X}\nEvent Starter: {4}\nParams: {5}", eventStart.actorID, eventStart.scriptOwnerActorID, eventStart.val1, eventStart.val2, eventStart.triggerName, LuaUtils.DumpParams(eventStart.luaParams));
break;
//Unknown, happens at npc spawn and cutscene play????
case 0x00CE:
subpacket.DebugPrintSubPacket();
break;
//Event Result
case 0x012E:
subpacket.DebugPrintSubPacket();
EventUpdatePacket eventUpdate = new EventUpdatePacket(subpacket.data);
Program.Log.Debug("\n===Event UPDATE===\nSource Actor: 0x{0:X}\nCaller Actor: 0x{1:X}\nVal1: 0x{2:X}\nVal2: 0x{3:X}\nStep: 0x{4:X}\nParams: {5}", eventUpdate.actorID, eventUpdate.scriptOwnerActorID, eventUpdate.val1, eventUpdate.val2, eventUpdate.step, LuaUtils.DumpParams(eventUpdate.luaParams));
/*
//Is it a static actor? If not look in the player's instance
Actor updateOwnerActor = Server.GetStaticActors(session.GetActor().currentEventOwner);
if (updateOwnerActor == null)
{
updateOwnerActor = Server.GetWorldManager().GetActorInWorld(session.GetActor().currentEventOwner);
if (session.GetActor().currentDirector != null && session.GetActor().currentEventOwner == session.GetActor().currentDirector.actorId)
updateOwnerActor = session.GetActor().currentDirector;
Program.Log.Debug("\n===Event START===\nSource Actor: 0x{0:X}\nCaller Actor: 0x{1:X}\nVal1: 0x{2:X}\nVal2: 0x{3:X}\nEvent Starter: {4}\nParams: {5}", eventStart.actorID, eventStart.scriptOwnerActorID, eventStart.val1, eventStart.val2, eventStart.triggerName, LuaUtils.DumpParams(eventStart.luaParams));
break;
//Unknown, happens at npc spawn and cutscene play????
case 0x00CE:
break;
//Event Result
case 0x012E:
subpacket.DebugPrintSubPacket();
EventUpdatePacket eventUpdate = new EventUpdatePacket(subpacket.data);
Program.Log.Debug("\n===Event UPDATE===\nSource Actor: 0x{0:X}\nCaller Actor: 0x{1:X}\nVal1: 0x{2:X}\nVal2: 0x{3:X}\nStep: 0x{4:X}\nParams: {5}", eventUpdate.actorID, eventUpdate.scriptOwnerActorID, eventUpdate.val1, eventUpdate.val2, eventUpdate.step, LuaUtils.DumpParams(eventUpdate.luaParams));
/*
//Is it a static actor? If not look in the player's instance
Actor updateOwnerActor = Server.GetStaticActors(player.GetActor().currentEventOwner);
if (updateOwnerActor == null) if (updateOwnerActor == null)
{ break;
updateOwnerActor = Server.GetWorldManager().GetActorInWorld(player.GetActor().currentEventOwner); }
*/
session.GetActor().UpdateEvent(eventUpdate);
if (player.GetActor().currentDirector != null && player.GetActor().currentEventOwner == player.GetActor().currentDirector.actorId) //LuaEngine.DoActorOnEventUpdated(session.GetActor(), updateOwnerActor, eventUpdate);
updateOwnerActor = player.GetActor().currentDirector;
if (updateOwnerActor == null) break;
break; case 0x012F:
} subpacket.DebugPrintSubPacket();
*/ ParameterDataRequestPacket paramRequest = new ParameterDataRequestPacket(subpacket.data);
player.GetActor().UpdateEvent(eventUpdate); if (paramRequest.paramName.Equals("charaWork/exp"))
session.GetActor().SendCharaExpInfo();
//LuaEngine.DoActorOnEventUpdated(player.GetActor(), updateOwnerActor, eventUpdate); break;
//Group Created Confirm
break; case 0x0133:
case 0x012F: GroupCreatedPacket groupCreated = new GroupCreatedPacket(subpacket.data);
//subpacket.DebugPrintSubPacket(); Server.GetWorldManager().SendGroupInit(session, groupCreated.groupId);
ParameterDataRequestPacket paramRequest = new ParameterDataRequestPacket(subpacket.data); break;
if (paramRequest.paramName.Equals("charaWork/exp")) /* RECRUITMENT */
player.GetActor().SendCharaExpInfo(); //Start Recruiting
break; case 0x01C3:
/* RECRUITMENT */ StartRecruitingRequestPacket recruitRequestPacket = new StartRecruitingRequestPacket(subpacket.data);
//Start Recruiting session.QueuePacket(StartRecruitingResponse.BuildPacket(session.id, true));
case 0x01C3: break;
StartRecruitingRequestPacket recruitRequestPacket = new StartRecruitingRequestPacket(subpacket.data); //End Recruiting
client.QueuePacket(BasePacket.CreatePacket(StartRecruitingResponse.BuildPacket(player.actorID, true), true, false)); case 0x01C4:
break; session.QueuePacket(EndRecruitmentPacket.BuildPacket(session.id));
//End Recruiting break;
case 0x01C4: //Party Window Opened, Request State
client.QueuePacket(BasePacket.CreatePacket(EndRecruitmentPacket.BuildPacket(player.actorID), true, false)); case 0x01C5:
break; session.QueuePacket(RecruiterStatePacket.BuildPacket(session.id, false, false, 0));
//Party Window Opened, Request State break;
case 0x01C5: //Search Recruiting
client.QueuePacket(BasePacket.CreatePacket(RecruiterStatePacket.BuildPacket(player.actorID, true, true, 1), true, false)); case 0x01C7:
break; RecruitmentSearchRequestPacket recruitSearchPacket = new RecruitmentSearchRequestPacket(subpacket.data);
//Search Recruiting break;
case 0x01C7: //Get Recruitment Details
RecruitmentSearchRequestPacket recruitSearchPacket = new RecruitmentSearchRequestPacket(subpacket.data); case 0x01C8:
break; RecruitmentDetailsRequestPacket currentRecruitDetailsPacket = new RecruitmentDetailsRequestPacket(subpacket.data);
//Get Recruitment Details RecruitmentDetails details = new RecruitmentDetails();
case 0x01C8: details.recruiterName = "Localhost Character";
RecruitmentDetailsRequestPacket currentRecruitDetailsPacket = new RecruitmentDetailsRequestPacket(subpacket.data); details.purposeId = 2;
RecruitmentDetails details = new RecruitmentDetails(); details.locationId = 1;
details.recruiterName = "Localhost Character"; details.subTaskId = 1;
details.purposeId = 2; details.comment = "This is a test details packet sent by the server. No implementation has been Created yet...";
details.locationId = 1; details.num[0] = 1;
details.subTaskId = 1; session.QueuePacket(CurrentRecruitmentDetailsPacket.BuildPacket(session.id, details));
details.comment = "This is a test details packet sent by the server. No implementation has been Created yet..."; break;
details.num[0] = 1; //Accepted Recruiting
client.QueuePacket(BasePacket.CreatePacket(CurrentRecruitmentDetailsPacket.BuildPacket(player.actorID, details), true, false)); case 0x01C6:
break; subpacket.DebugPrintSubPacket();
//Accepted Recruiting break;
case 0x01C6: /* SOCIAL STUFF */
subpacket.DebugPrintSubPacket(); case 0x01C9:
break; AddRemoveSocialPacket addBlackList = new AddRemoveSocialPacket(subpacket.data);
/* SOCIAL STUFF */ session.QueuePacket(BlacklistAddedPacket.BuildPacket(session.id, true, addBlackList.name));
case 0x01C9: break;
AddRemoveSocialPacket addBlackList = new AddRemoveSocialPacket(subpacket.data); case 0x01CA:
client.QueuePacket(BasePacket.CreatePacket(BlacklistAddedPacket.BuildPacket(player.actorID, true, addBlackList.name), true, false)); AddRemoveSocialPacket RemoveBlackList = new AddRemoveSocialPacket(subpacket.data);
break; session.QueuePacket(BlacklistRemovedPacket.BuildPacket(session.id, true, RemoveBlackList.name));
case 0x01CA: break;
AddRemoveSocialPacket RemoveBlackList = new AddRemoveSocialPacket(subpacket.data); case 0x01CB:
client.QueuePacket(BasePacket.CreatePacket(BlacklistRemovedPacket.BuildPacket(player.actorID, true, RemoveBlackList.name), true, false)); int offset1 = 0;
break; session.QueuePacket(SendBlacklistPacket.BuildPacket(session.id, new String[] { "Test" }, ref offset1));
case 0x01CB: break;
int offset1 = 0; case 0x01CC:
client.QueuePacket(BasePacket.CreatePacket(SendBlacklistPacket.BuildPacket(player.actorID, new String[] { "Test" }, ref offset1), true, false)); AddRemoveSocialPacket addFriendList = new AddRemoveSocialPacket(subpacket.data);
break; session.QueuePacket(FriendlistAddedPacket.BuildPacket(session.id, true, (uint)addFriendList.name.GetHashCode(), true, addFriendList.name));
case 0x01CC: break;
AddRemoveSocialPacket addFriendList = new AddRemoveSocialPacket(subpacket.data); case 0x01CD:
client.QueuePacket(BasePacket.CreatePacket(FriendlistAddedPacket.BuildPacket(player.actorID, true, (uint)addFriendList.name.GetHashCode(), true, addFriendList.name), true, false)); AddRemoveSocialPacket RemoveFriendList = new AddRemoveSocialPacket(subpacket.data);
break; session.QueuePacket(FriendlistRemovedPacket.BuildPacket(session.id, true, RemoveFriendList.name));
case 0x01CD: break;
AddRemoveSocialPacket RemoveFriendList = new AddRemoveSocialPacket(subpacket.data); case 0x01CE:
client.QueuePacket(BasePacket.CreatePacket(FriendlistRemovedPacket.BuildPacket(player.actorID, true, RemoveFriendList.name), true, false)); int offset2 = 0;
break; session.QueuePacket(SendFriendlistPacket.BuildPacket(session.id, new Tuple<long, string>[] { new Tuple<long, string>(01, "Test2") }, ref offset2));
case 0x01CE: break;
int offset2 = 0; case 0x01CF:
client.QueuePacket(BasePacket.CreatePacket(SendFriendlistPacket.BuildPacket(player.actorID, new Tuple<long, string>[] { new Tuple<long, string>(01, "Test2") }, ref offset2), true, false)); session.QueuePacket(FriendStatusPacket.BuildPacket(session.id, null));
break; break;
case 0x01CF: /* SUPPORT DESK STUFF */
client.QueuePacket(BasePacket.CreatePacket(FriendStatusPacket.BuildPacket(player.actorID, null), true, false)); //Request for FAQ/Info List
break; case 0x01D0:
/* SUPPORT DESK STUFF */ FaqListRequestPacket faqRequest = new FaqListRequestPacket(subpacket.data);
//Request for FAQ/Info List session.QueuePacket(FaqListResponsePacket.BuildPacket(session.id, new string[] { "Testing FAQ1", "Coded style!" }));
case 0x01D0: break;
FaqListRequestPacket faqRequest = new FaqListRequestPacket(subpacket.data); //Request for body of a faq/info selection
client.QueuePacket(BasePacket.CreatePacket(FaqListResponsePacket.BuildPacket(player.actorID, Database.getFAQNames(faqRequest.langCode)), true, false)); case 0x01D1:
break; FaqBodyRequestPacket faqBodyRequest = new FaqBodyRequestPacket(subpacket.data);
//Request for body of a faq/info selection session.QueuePacket(FaqBodyResponsePacket.BuildPacket(session.id, "HERE IS A GIANT BODY. Nothing else to say!"));
case 0x01D1: break;
FaqBodyRequestPacket faqBodyRequest = new FaqBodyRequestPacket(subpacket.data); //Request issue list
client.QueuePacket(BasePacket.CreatePacket(FaqBodyResponsePacket.BuildPacket(player.actorID, Database.getFAQBody(faqBodyRequest.faqIndex, faqBodyRequest.langCode)), true, false)); case 0x01D2:
break; GMTicketIssuesRequestPacket issuesRequest = new GMTicketIssuesRequestPacket(subpacket.data);
//Request issue list session.QueuePacket(IssueListResponsePacket.BuildPacket(session.id, new string[] { "Test1", "Test2", "Test3", "Test4", "Test5" }));
case 0x01D2: break;
GMTicketIssuesRequestPacket issuesRequest = new GMTicketIssuesRequestPacket(subpacket.data); //Request if GM ticket exists
client.QueuePacket(BasePacket.CreatePacket(IssueListResponsePacket.BuildPacket(player.actorID, Database.getIssues(issuesRequest.langCode)), true, false)); case 0x01D3:
break; session.QueuePacket(StartGMTicketPacket.BuildPacket(session.id, false));
//Request if GM ticket exists break;
case 0x01D3: //Request for GM response message
client.QueuePacket(BasePacket.CreatePacket(StartGMTicketPacket.BuildPacket(player.actorID, Database.isTicketOpen(player.GetActor().customDisplayName)), true, false)); case 0x01D4:
break; session.QueuePacket(GMTicketPacket.BuildPacket(session.id, "This is a GM Ticket Title", "This is a GM Ticket Body."));
//Request for GM response message break;
case 0x01D4: //GM Ticket Sent
client.QueuePacket(BasePacket.CreatePacket(GMTicketPacket.BuildPacket(player.actorID, "Ticket Title", "Enter your Help request here."), true, false)); case 0x01D5:
break; GMSupportTicketPacket gmTicket = new GMSupportTicketPacket(subpacket.data);
//GM Ticket Sent Program.Log.Info("Got GM Ticket: \n" + gmTicket.ticketTitle + "\n" + gmTicket.ticketBody);
case 0x01D5: session.QueuePacket(GMTicketSentResponsePacket.BuildPacket(session.id, true));
GMSupportTicketPacket gmTicket = new GMSupportTicketPacket(subpacket.data); break;
Program.Log.Info("Got GM Ticket: \n" + gmTicket.ticketTitle + "\n" + gmTicket.ticketBody); //Request to end ticket
bool wasError = Database.SaveSupportTicket(gmTicket, player.GetActor().customDisplayName); case 0x01D6:
client.QueuePacket(BasePacket.CreatePacket(GMTicketSentResponsePacket.BuildPacket(player.actorID, !wasError), true, false)); session.QueuePacket(EndGMTicketPacket.BuildPacket(session.id));
break;
if (!wasError) default:
client.QueuePacket(BasePacket.CreatePacket(StartGMTicketPacket.BuildPacket(player.actorID, true), true, false)); Program.Log.Debug("Unknown command 0x{0:X} received.", subpacket.gameMessage.opcode);
subpacket.DebugPrintSubPacket();
break; break;
//Request to end ticket
case 0x01D6:
Database.closeTicket(player.GetActor().customDisplayName);
client.QueuePacket(BasePacket.CreatePacket(EndGMTicketPacket.BuildPacket(player.actorID), true, false));
break;
default:
Program.Log.Debug("Unknown command 0x{0:X} received.", subpacket.gameMessage.opcode);
subpacket.DebugPrintSubPacket();
break;
}
} }
else
packet.DebugPrintPacket();
}
} }
} }
} }

View File

@ -19,7 +19,6 @@ namespace FFXIVClassic_Map_Server
static void Main(string[] args) static void Main(string[] args)
{ {
// set up logging // set up logging
Log = LogManager.GetCurrentClassLogger(); Log = LogManager.GetCurrentClassLogger();
#if DEBUG #if DEBUG
@ -28,11 +27,14 @@ namespace FFXIVClassic_Map_Server
#endif #endif
bool startServer = true; bool startServer = true;
Program.Log.Info("---------FFXIV 1.0 Map Server---------"); Log.Info("==================================");
Log.Info("FFXIV Classic Map Server");
Log.Info("Version: 0.1");
Log.Info("==================================");
//Load Config //Load Config
if (!ConfigConstants.Load()) ConfigConstants.Load();
startServer = false; ConfigConstants.ApplyLaunchArgs(args);
//Test DB Connection //Test DB Connection
Program.Log.Info("Testing DB connection... "); Program.Log.Info("Testing DB connection... ");
@ -52,25 +54,18 @@ namespace FFXIVClassic_Map_Server
} }
} }
//Check World ID
DBWorld thisWorld = Database.GetServer(ConfigConstants.DATABASE_WORLDID);
if (thisWorld != null)
Program.Log.Info("Successfully pulled world info from DB. Server name is {0}.", thisWorld.name);
else
Program.Log.Info("World info could not be retrieved from the DB. Welcome and MOTD will not be displayed.");
//Start server if A-OK //Start server if A-OK
if (startServer) if (startServer)
{ {
Server server = new Server(); Server server = new Server();
CommandProcessor cp = new CommandProcessor(server.GetConnectedPlayerList());
server.StartServer(); server.StartServer();
while (startServer) while (startServer)
{ {
String input = Console.ReadLine(); String input = Console.ReadLine();
Log.Info("[Console Input] " + input); Log.Info("[Console Input] " + input);
cp.DoCommand(input, null); Server.GetCommandProcessor().DoCommand(input, null);
} }
} }

View File

@ -2,11 +2,9 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Threading;
using FFXIVClassic_Map_Server.dataobjects; using FFXIVClassic_Map_Server.dataobjects;
using FFXIVClassic_Map_Server.packets;
using FFXIVClassic.Common; using FFXIVClassic.Common;
using NLog;
using FFXIVClassic_Map_Server.Actors; using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.lua; using FFXIVClassic_Map_Server.lua;
@ -17,7 +15,6 @@ namespace FFXIVClassic_Map_Server
public const int FFXIV_MAP_PORT = 54992; public const int FFXIV_MAP_PORT = 54992;
public const int BUFFER_SIZE = 0xFFFF; //Max basepacket size is 0xFFFF public const int BUFFER_SIZE = 0xFFFF; //Max basepacket size is 0xFFFF
public const int BACKLOG = 100; public const int BACKLOG = 100;
public const int HEALTH_THREAD_SLEEP_TIME = 5;
public const string STATIC_ACTORS_PATH = "./staticactors.bin"; public const string STATIC_ACTORS_PATH = "./staticactors.bin";
@ -25,60 +22,30 @@ namespace FFXIVClassic_Map_Server
private Socket mServerSocket; private Socket mServerSocket;
private Dictionary<uint, ConnectedPlayer> mConnectedPlayerList = new Dictionary<uint, ConnectedPlayer>(); private Dictionary<uint, Session> mSessionList = new Dictionary<uint, Session>();
private List<ClientConnection> mConnectionList = new List<ClientConnection>();
private LuaEngine mLuaEngine = new LuaEngine();
private static CommandProcessor mCommandProcessor = new CommandProcessor();
private static ZoneConnection mWorldConnection = new ZoneConnection();
private static WorldManager mWorldManager; private static WorldManager mWorldManager;
private static Dictionary<uint, Item> gamedataItems; private static Dictionary<uint, ItemData> mGamedataItems;
private static Dictionary<uint, GuildleveData> mGamedataGuildleves;
private static StaticActors mStaticActors; private static StaticActors mStaticActors;
private PacketProcessor mProcessor; private PacketProcessor mProcessor;
private Thread mConnectionHealthThread;
private bool killHealthThread = false;
private void ConnectionHealth()
{
Program.Log.Info("Connection Health thread started; it will run every {0} seconds.", HEALTH_THREAD_SLEEP_TIME);
while (!killHealthThread)
{
lock (mConnectedPlayerList)
{
List<ConnectedPlayer> dcedPlayers = new List<ConnectedPlayer>();
foreach (ConnectedPlayer cp in mConnectedPlayerList.Values)
{
if (cp.CheckIfDCing())
dcedPlayers.Add(cp);
}
foreach (ConnectedPlayer cp in dcedPlayers)
cp.GetActor().CleanupAndSave();
}
Thread.Sleep(HEALTH_THREAD_SLEEP_TIME * 1000);
}
}
public Server() public Server()
{ {
mSelf = this; mSelf = this;
} }
public static Server GetServer()
{
return mSelf;
}
public bool StartServer() public bool StartServer()
{ {
mConnectionHealthThread = new Thread(new ThreadStart(ConnectionHealth));
mConnectionHealthThread.Name = "MapThread:Health";
//mConnectionHealthThread.Start();
mStaticActors = new StaticActors(STATIC_ACTORS_PATH); mStaticActors = new StaticActors(STATIC_ACTORS_PATH);
gamedataItems = Database.GetItemGamedata(); mGamedataItems = Database.GetItemGamedata();
Program.Log.Info("Loaded {0} items.", gamedataItems.Count); Program.Log.Info("Loaded {0} items.", mGamedataItems.Count);
mGamedataGuildleves = Database.GetGuildleveGamedata();
Program.Log.Info("Loaded {0} guildleves.", mGamedataGuildleves.Count);
mWorldManager = new WorldManager(this); mWorldManager = new WorldManager(this);
mWorldManager.LoadZoneList(); mWorldManager.LoadZoneList();
@ -87,12 +54,13 @@ namespace FFXIVClassic_Map_Server
mWorldManager.LoadActorClasses(); mWorldManager.LoadActorClasses();
mWorldManager.LoadSpawnLocations(); mWorldManager.LoadSpawnLocations();
mWorldManager.SpawnAllActors(); mWorldManager.SpawnAllActors();
mWorldManager.StartZoneThread();
IPEndPoint serverEndPoint = new System.Net.IPEndPoint(IPAddress.Parse(ConfigConstants.OPTIONS_BINDIP), int.Parse(ConfigConstants.OPTIONS_PORT)); IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse(ConfigConstants.OPTIONS_BINDIP), int.Parse(ConfigConstants.OPTIONS_PORT));
try try
{ {
mServerSocket = new System.Net.Sockets.Socket(serverEndPoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp); mServerSocket = new Socket(serverEndPoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
} }
catch (Exception e) catch (Exception e)
{ {
@ -120,39 +88,72 @@ namespace FFXIVClassic_Map_Server
Program.Log.Info("Map Server has started @ {0}:{1}", (mServerSocket.LocalEndPoint as IPEndPoint).Address, (mServerSocket.LocalEndPoint as IPEndPoint).Port); Program.Log.Info("Map Server has started @ {0}:{1}", (mServerSocket.LocalEndPoint as IPEndPoint).Address, (mServerSocket.LocalEndPoint as IPEndPoint).Port);
Console.ForegroundColor = ConsoleColor.Gray; Console.ForegroundColor = ConsoleColor.Gray;
mProcessor = new PacketProcessor(this, mConnectedPlayerList, mConnectionList); mProcessor = new PacketProcessor(this);
//mGameThread = new Thread(new ThreadStart(mProcessor.update)); //mGameThread = new Thread(new ThreadStart(mProcessor.update));
//mGameThread.Start(); //mGameThread.Start();
return true; return true;
} }
public void RemovePlayer(Player player) #region Session Handling
public Session AddSession(uint id)
{ {
lock (mConnectedPlayerList) if (mSessionList.ContainsKey(id))
return mSessionList[id];
Session session = new Session(id);
mSessionList.Add(id, session);
return session;
}
public void RemoveSession(uint id)
{
if (mSessionList.ContainsKey(id))
{ {
if (mConnectedPlayerList.ContainsKey(player.actorId)) mSessionList.Remove(id);
mConnectedPlayerList.Remove(player.actorId);
} }
} }
public Session GetSession(uint id)
{
if (mSessionList.ContainsKey(id))
return mSessionList[id];
else
return null;
}
public Session GetSession(string name)
{
foreach (Session s in mSessionList.Values)
{
if (s.GetActor().customDisplayName.ToLower().Equals(name.ToLower()))
return s;
}
return null;
}
public Dictionary<uint, Session> GetSessionList()
{
return mSessionList;
}
#endregion
#region Socket Handling #region Socket Handling
private void AcceptCallback(IAsyncResult result) private void AcceptCallback(IAsyncResult result)
{ {
ClientConnection conn = null; ZoneConnection conn = null;
Socket socket = (System.Net.Sockets.Socket)result.AsyncState; Socket socket = (System.Net.Sockets.Socket)result.AsyncState;
try try
{ {
conn = new ClientConnection(); conn = new ZoneConnection();
conn.socket = socket.EndAccept(result); conn.socket = socket.EndAccept(result);
conn.buffer = new byte[BUFFER_SIZE]; conn.buffer = new byte[BUFFER_SIZE];
lock (mConnectionList) mWorldConnection = conn;
{
mConnectionList.Add(conn);
}
Program.Log.Info("Connection {0}:{1} has connected.", (conn.socket.RemoteEndPoint as IPEndPoint).Address, (conn.socket.RemoteEndPoint as IPEndPoint).Port); Program.Log.Info("Connection {0}:{1} has connected.", (conn.socket.RemoteEndPoint as IPEndPoint).Address, (conn.socket.RemoteEndPoint as IPEndPoint).Port);
//Queue recieving of data from the connection //Queue recieving of data from the connection
@ -164,11 +165,7 @@ namespace FFXIVClassic_Map_Server
{ {
if (conn != null) if (conn != null)
{ {
mWorldConnection = null;
lock (mConnectionList)
{
mConnectionList.Remove(conn);
}
} }
mServerSocket.BeginAccept(new AsyncCallback(AcceptCallback), mServerSocket); mServerSocket.BeginAccept(new AsyncCallback(AcceptCallback), mServerSocket);
} }
@ -176,53 +173,25 @@ namespace FFXIVClassic_Map_Server
{ {
if (conn != null) if (conn != null)
{ {
lock (mConnectionList) mWorldConnection = null;
{
mConnectionList.Remove(conn);
}
} }
mServerSocket.BeginAccept(new AsyncCallback(AcceptCallback), mServerSocket); mServerSocket.BeginAccept(new AsyncCallback(AcceptCallback), mServerSocket);
} }
} }
public static Actor GetStaticActors(uint id)
{
return mStaticActors.GetActor(id);
}
public static Actor GetStaticActors(string name)
{
return mStaticActors.FindStaticActor(name);
}
public static Item GetItemGamedata(uint id)
{
if (gamedataItems.ContainsKey(id))
return gamedataItems[id];
else
return null;
}
/// <summary> /// <summary>
/// Receive Callback. Reads in incoming data, converting them to base packets. Base packets are sent to be parsed. If not enough data at the end to build a basepacket, move to the beginning and prepend. /// Receive Callback. Reads in incoming data, converting them to base packets. Base packets are sent to be parsed. If not enough data at the end to build a basepacket, move to the beginning and prepend.
/// </summary> /// </summary>
/// <param name="result"></param> /// <param name="result"></param>
private void ReceiveCallback(IAsyncResult result) private void ReceiveCallback(IAsyncResult result)
{ {
ClientConnection conn = (ClientConnection)result.AsyncState; ZoneConnection conn = (ZoneConnection)result.AsyncState;
//Check if disconnected //Check if disconnected
if ((conn.socket.Poll(1, SelectMode.SelectRead) && conn.socket.Available == 0)) if ((conn.socket.Poll(1, SelectMode.SelectRead) && conn.socket.Available == 0))
{ {
if (mConnectedPlayerList.ContainsKey(conn.owner)) mWorldConnection = null;
mConnectedPlayerList.Remove(conn.owner); Program.Log.Info("Disconnected from world server!");
lock (mConnectionList)
{
mConnectionList.Remove(conn);
}
if (conn.connType == BasePacket.TYPE_ZONE)
Program.Log.Info("{0} has disconnected.", conn.owner == 0 ? conn.GetAddress() : "User " + conn.owner);
return;
} }
try try
@ -238,13 +207,13 @@ namespace FFXIVClassic_Map_Server
//Build packets until can no longer or out of data //Build packets until can no longer or out of data
while (true) while (true)
{ {
BasePacket basePacket = BuildPacket(ref offset, conn.buffer, bytesRead); SubPacket subPacket = SubPacket.CreatePacket(ref offset, conn.buffer, bytesRead);
//If can't build packet, break, else process another //If can't build packet, break, else process another
if (basePacket == null) if (subPacket == null)
break; break;
else else
mProcessor.ProcessPacket(conn, basePacket); mProcessor.ProcessPacket(conn, subPacket);
} }
//Not all bytes consumed, transfer leftover to beginning //Not all bytes consumed, transfer leftover to beginning
@ -265,79 +234,71 @@ namespace FFXIVClassic_Map_Server
} }
else else
{ {
Program.Log.Info("{0} has disconnected.", conn.owner == 0 ? conn.GetAddress() : "User " + conn.owner); mWorldConnection = null;
Program.Log.Info("Disconnected from world server!");
lock (mConnectionList)
{
mConnectionList.Remove(conn);
}
} }
} }
catch (SocketException) catch (SocketException)
{ {
if (conn.socket != null) if (conn.socket != null)
{ {
Program.Log.Info("{0} has disconnected.", conn.owner == 0 ? conn.GetAddress() : "User " + conn.owner); mWorldConnection = null;
Program.Log.Info("Disconnected from world server!");
lock (mConnectionList)
{
mConnectionList.Remove(conn);
}
} }
} }
} }
/// <summary>
/// Builds a packet from the incoming buffer + offset. If a packet can be built, it is returned else null.
/// </summary>
/// <param name="offset">Current offset in buffer.</param>
/// <param name="buffer">Incoming buffer.</param>
/// <returns>Returns either a BasePacket or null if not enough data.</returns>
public BasePacket BuildPacket(ref int offset, byte[] buffer, int bytesRead)
{
BasePacket newPacket = null;
//Too small to even get length
if (bytesRead <= offset)
return null;
ushort packetSize = BitConverter.ToUInt16(buffer, offset);
//Too small to whole packet
if (bytesRead < offset + packetSize)
return null;
if (buffer.Length < offset + packetSize)
return null;
try
{
newPacket = new BasePacket(buffer, ref offset);
}
catch (OverflowException)
{
return null;
}
return newPacket;
}
#endregion #endregion
public static ZoneConnection GetWorldConnection()
{
return mWorldConnection;
}
public static Server GetServer()
{
return mSelf;
}
public static CommandProcessor GetCommandProcessor()
{
return mCommandProcessor;
}
public static WorldManager GetWorldManager() public static WorldManager GetWorldManager()
{ {
return mWorldManager; return mWorldManager;
} }
public Dictionary<uint, ConnectedPlayer> GetConnectedPlayerList() public static Dictionary<uint, ItemData> GetGamedataItems()
{ {
return mConnectedPlayerList; return mGamedataItems;
} }
public static Dictionary<uint, Item> GetGamedataItems() public static Actor GetStaticActors(uint id)
{ {
return gamedataItems; return mStaticActors.GetActor(id);
}
public static Actor GetStaticActors(string name)
{
return mStaticActors.FindStaticActor(name);
}
public static ItemData GetItemGamedata(uint id)
{
if (mGamedataItems.ContainsKey(id))
return mGamedataItems[id];
else
return null;
}
public static GuildleveData GetGuildleveGamedata(uint id)
{
if (mGamedataGuildleves.ContainsKey(id))
return mGamedataGuildleves[id];
else
return null;
} }
} }

View File

@ -16,6 +16,13 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using FFXIVClassic_Map_Server.actors.group;
using FFXIVClassic_Map_Server.packets.send.group;
using FFXIVClassic_Map_Server.packets.WorldPackets.Receive;
using FFXIVClassic_Map_Server.packets.WorldPackets.Send.Group;
using System.Threading;
using System.Diagnostics;
using FFXIVClassic_Map_Server.actors.director;
namespace FFXIVClassic_Map_Server namespace FFXIVClassic_Map_Server
{ {
@ -27,9 +34,18 @@ namespace FFXIVClassic_Map_Server
private Dictionary<uint, List<SeamlessBoundry>> seamlessBoundryList; private Dictionary<uint, List<SeamlessBoundry>> seamlessBoundryList;
private Dictionary<uint, ZoneEntrance> zoneEntranceList; private Dictionary<uint, ZoneEntrance> zoneEntranceList;
private Dictionary<uint, ActorClass> actorClasses = new Dictionary<uint,ActorClass>(); private Dictionary<uint, ActorClass> actorClasses = new Dictionary<uint,ActorClass>();
private Dictionary<ulong, Party> currentPlayerParties = new Dictionary<ulong, Party>(); //GroupId, Party object
private Server mServer; private Server mServer;
private const int MILIS_LOOPTIME = 10;
private Timer mZoneTimer;
//Content Groups
public Dictionary<ulong, Group> mContentGroups = new Dictionary<ulong, Group>();
private Object groupLock = new Object();
public ulong groupIndexId = 1;
public WorldManager(Server server) public WorldManager(Server server)
{ {
mServer = server; mServer = server;
@ -52,7 +68,7 @@ namespace FFXIVClassic_Map_Server
id, id,
zoneName, zoneName,
regionId, regionId,
className, classPath,
dayMusic, dayMusic,
nightMusic, nightMusic,
battleMusic, battleMusic,
@ -62,10 +78,13 @@ namespace FFXIVClassic_Map_Server
canStealth, canStealth,
isInstanceRaid isInstanceRaid
FROM server_zones FROM server_zones
WHERE zoneName IS NOT NULL"; WHERE zoneName IS NOT NULL and serverIp = @ip and serverPort = @port";
MySqlCommand cmd = new MySqlCommand(query, conn); MySqlCommand cmd = new MySqlCommand(query, conn);
cmd.Parameters.AddWithValue("@ip", ConfigConstants.OPTIONS_BINDIP);
cmd.Parameters.AddWithValue("@port", ConfigConstants.OPTIONS_PORT);
using (MySqlDataReader reader = cmd.ExecuteReader()) using (MySqlDataReader reader = cmd.ExecuteReader())
{ {
while (reader.Read()) while (reader.Read())
@ -95,6 +114,7 @@ namespace FFXIVClassic_Map_Server
id, id,
parentZoneId, parentZoneId,
privateAreaName, privateAreaName,
privateAreaType,
className, className,
dayMusic, dayMusic,
nightMusic, nightMusic,
@ -113,7 +133,7 @@ namespace FFXIVClassic_Map_Server
if (zoneList.ContainsKey(parentZoneId)) if (zoneList.ContainsKey(parentZoneId))
{ {
Zone parent = zoneList[parentZoneId]; Zone parent = zoneList[parentZoneId];
PrivateArea privArea = new PrivateArea(parent, reader.GetUInt32("id"), reader.GetString("className"), reader.GetString("privateAreaName"), 1, reader.GetUInt16("dayMusic"), reader.GetUInt16("nightMusic"), reader.GetUInt16("battleMusic")); PrivateArea privArea = new PrivateArea(parent, reader.GetUInt32("id"), reader.GetString("className"), reader.GetString("privateAreaName"), reader.GetUInt32("privateAreaType"), reader.GetUInt16("dayMusic"), reader.GetUInt16("nightMusic"), reader.GetUInt16("battleMusic"));
parent.AddPrivateArea(privArea); parent.AddPrivateArea(privArea);
} }
else else
@ -168,7 +188,7 @@ namespace FFXIVClassic_Map_Server
if (!reader.IsDBNull(7)) if (!reader.IsDBNull(7))
privArea = reader.GetString(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)); ZoneEntrance entance = new ZoneEntrance(reader.GetUInt32(1), privArea, 1, reader.GetByte(2), reader.GetFloat(3), reader.GetFloat(4), reader.GetFloat(5), reader.GetFloat(6));
zoneEntranceList[id] = entance; zoneEntranceList[id] = entance;
count++; count++;
} }
@ -257,12 +277,17 @@ namespace FFXIVClassic_Map_Server
string query = @" string query = @"
SELECT SELECT
id, gamedata_actor_class.id,
classPath, classPath,
displayNameId, displayNameId,
propertyFlags, propertyFlags,
eventConditions eventConditions,
pushCommand,
pushCommandSub,
pushCommandPriority
FROM gamedata_actor_class FROM gamedata_actor_class
LEFT JOIN gamedata_actor_pushcommand
ON gamedata_actor_class.id = gamedata_actor_pushcommand.id
WHERE classPath <> '' WHERE classPath <> ''
"; ";
@ -284,7 +309,18 @@ namespace FFXIVClassic_Map_Server
else else
eventConditions = "{}"; eventConditions = "{}";
ActorClass actorClass = new ActorClass(id, classPath, nameId, propertyFlags, eventConditions); ushort pushCommand = 0;
ushort pushCommandSub = 0;
byte pushCommandPriority = 0;
if (!reader.IsDBNull(reader.GetOrdinal("pushCommand")))
{
pushCommand = reader.GetUInt16("pushCommand");
pushCommandSub = reader.GetUInt16("pushCommandSub");
pushCommandPriority = reader.GetByte("pushCommandPriority");
}
ActorClass actorClass = new ActorClass(id, classPath, nameId, propertyFlags, eventConditions, pushCommand, pushCommandSub, pushCommandPriority);
actorClasses.Add(id, actorClass); actorClasses.Add(id, actorClass);
count++; count++;
} }
@ -334,13 +370,20 @@ namespace FFXIVClassic_Map_Server
{ {
while (reader.Read()) while (reader.Read())
{ {
uint zoneId = reader.GetUInt32("zoneId");
uint classId = reader.GetUInt32("actorClassId");
if (!actorClasses.ContainsKey(classId))
continue;
if (!zoneList.ContainsKey(zoneId))
continue;
Zone zone = zoneList[zoneId];
if (zone == null)
continue;
string customName = null; string customName = null;
if (!reader.IsDBNull(11)) if (!reader.IsDBNull(11))
customName = reader.GetString("customDisplayName"); customName = reader.GetString("customDisplayName");
uint classId = reader.GetUInt32("actorClassId");
string uniqueId = reader.GetString("uniqueId"); string uniqueId = reader.GetString("uniqueId");
uint zoneId = reader.GetUInt32("zoneId");
string privAreaName = reader.GetString("privateAreaName"); string privAreaName = reader.GetString("privateAreaName");
uint privAreaLevel = reader.GetUInt32("privateAreaLevel"); uint privAreaLevel = reader.GetUInt32("privateAreaLevel");
float x = reader.GetFloat("positionX"); float x = reader.GetFloat("positionX");
@ -350,15 +393,6 @@ namespace FFXIVClassic_Map_Server
ushort state = reader.GetUInt16("actorState"); ushort state = reader.GetUInt16("actorState");
uint animId = reader.GetUInt32("animationId"); uint animId = reader.GetUInt32("animationId");
if (!actorClasses.ContainsKey(classId))
continue;
if (!zoneList.ContainsKey(zoneId))
continue;
Zone zone = zoneList[zoneId];
if (zone == null)
continue;
SpawnLocation spawn = new SpawnLocation(classId, uniqueId, zoneId, privAreaName, privAreaLevel, x, y, z, rot, state, animId); SpawnLocation spawn = new SpawnLocation(classId, uniqueId, zoneId, privAreaName, privAreaLevel, x, y, z, rot, state, animId);
zone.AddSpawnLocation(spawn); zone.AddSpawnLocation(spawn);
@ -416,7 +450,7 @@ namespace FFXIVClassic_Map_Server
player.SendMessage(0x20, "", "Doing Seamless Zone Change"); player.SendMessage(0x20, "", "Doing Seamless Zone Change");
LuaEngine.OnZoneIn(player); LuaEngine.GetInstance().CallLuaFunction(player, newZone, "onZoneIn", true);
} }
//Adds a second zone to pull actors from. Used for an improved seamless zone change. //Adds a second zone to pull actors from. Used for an improved seamless zone change.
@ -436,7 +470,7 @@ namespace FFXIVClassic_Map_Server
player.SendMessage(0x20, "", "Merging Zones"); player.SendMessage(0x20, "", "Merging Zones");
LuaEngine.OnZoneIn(player); LuaEngine.GetInstance().CallLuaFunction(player, mergedZone, "onZoneIn", true);
} }
//Checks all seamless bounding boxes in region to see if player needs to merge or zonechange //Checks all seamless bounding boxes in region to see if player needs to merge or zonechange
@ -518,12 +552,30 @@ namespace FFXIVClassic_Map_Server
} }
ZoneEntrance ze = zoneEntranceList[zoneEntrance]; ZoneEntrance ze = zoneEntranceList[zoneEntrance];
DoZoneChange(player, ze.zoneId, ze.privateAreaName, ze.spawnType, ze.spawnX, ze.spawnY, ze.spawnZ, ze.spawnRotation); DoZoneChange(player, ze.zoneId, ze.privateAreaName, ze.privateAreaType, ze.spawnType, ze.spawnX, ze.spawnY, ze.spawnZ, ze.spawnRotation);
} }
//Moves actor to new zone, and sends packets to spawn at the given coords. //Moves actor to new zone, and sends packets to spawn at the given coords.
public void DoZoneChange(Player player, uint destinationZoneId, string destinationPrivateArea, byte spawnType, float spawnX, float spawnY, float spawnZ, float spawnRotation) public void DoZoneChange(Player player, uint destinationZoneId, string destinationPrivateArea, int destinationPrivateAreaType, byte spawnType, float spawnX, float spawnY, float spawnZ, float spawnRotation)
{ {
//Add player to new zone and update
Area newArea;
if (destinationPrivateArea == null)
newArea = GetZone(destinationZoneId);
else //Add check for -1 if it is a instance
newArea = GetZone(destinationZoneId).GetPrivateArea(destinationPrivateArea, (uint)destinationPrivateAreaType);
//This server does not contain that zoneId
if (newArea == null)
{
Program.Log.Debug("Request to change to zone not on this server by: {0}.", player.customDisplayName);
RequestWorldServerZoneChange(player, destinationZoneId, spawnType, spawnX, spawnY, spawnZ, spawnRotation);
return;
}
player.playerSession.LockUpdates(true);
Area oldZone = player.zone; Area oldZone = player.zone;
//Remove player from currentZone if transfer else it's login //Remove player from currentZone if transfer else it's login
if (player.zone != null) if (player.zone != null)
@ -531,46 +583,48 @@ namespace FFXIVClassic_Map_Server
oldZone.RemoveActorFromZone(player); oldZone.RemoveActorFromZone(player);
} }
//Add player to new zone and update
Area newArea;
if (destinationPrivateArea == null)
newArea = GetZone(destinationZoneId);
else
newArea = GetZone(destinationZoneId).GetPrivateArea(destinationPrivateArea, 0);
//This server does not contain that zoneId
if (newArea == null)
{
if (oldZone != null)
{
oldZone.AddActorToZone(player);
}
var message = "WorldManager.DoZoneChange: unable to change areas, new area is not valid.";
player.SendMessage(SendMessagePacket.MESSAGE_TYPE_SYSTEM, "[Debug]", message);
Program.Log.Debug(message);
return;
}
newArea.AddActorToZone(player); newArea.AddActorToZone(player);
//Update player actor's properties //Update player actor's properties
player.zoneId = newArea.actorId; player.zoneId = newArea is PrivateArea ? ((PrivateArea)newArea).GetParentZone().actorId : newArea.actorId;
player.privateArea = newArea is PrivateArea ? ((PrivateArea)newArea).GetPrivateAreaName() : null;
player.privateAreaType = newArea is PrivateArea ? ((PrivateArea)newArea).GetPrivateAreaType() : 0;
player.zone = newArea; player.zone = newArea;
player.positionX = spawnX; player.positionX = spawnX;
player.positionY = spawnY; player.positionY = spawnY;
player.positionZ = spawnZ; player.positionZ = spawnZ;
player.rotation = spawnRotation; player.rotation = spawnRotation;
//Delete any GL directors
GuildleveDirector glDirector = player.GetGuildleveDirector();
if (glDirector != null)
player.RemoveDirector(glDirector);
//Delete content if have
if (player.currentContentGroup != null)
{
player.currentContentGroup.RemoveMember(player.actorId);
player.SetCurrentContentGroup(null);
if (oldZone is PrivateAreaContent)
((PrivateAreaContent)oldZone).CheckDestroy();
}
//Send packets //Send packets
player.playerSession.QueuePacket(DeleteAllActorsPacket.BuildPacket(player.actorId), true, false); player.playerSession.QueuePacket(DeleteAllActorsPacket.BuildPacket(player.actorId));
player.playerSession.QueuePacket(_0xE2Packet.BuildPacket(player.actorId, 0x0), true, false); player.playerSession.QueuePacket(_0xE2Packet.BuildPacket(player.actorId, 0x2));
player.SendZoneInPackets(this, spawnType); player.SendZoneInPackets(this, spawnType);
player.playerSession.ClearInstance(); player.playerSession.ClearInstance();
player.SendInstanceUpdate(); player.SendInstanceUpdate();
LuaEngine.OnZoneIn(player); player.playerSession.LockUpdates(false);
//Send "You have entered an instance" if it's a Private Area
if (newArea is PrivateArea)
player.SendGameMessage(GetActor(), 34108, 0x20);
LuaEngine.GetInstance().CallLuaFunction(player, newArea, "onZoneIn", true);
} }
//Moves actor within zone to spawn position //Moves actor within zone to spawn position
@ -596,6 +650,7 @@ namespace FFXIVClassic_Map_Server
//Remove player from currentZone if transfer else it's login //Remove player from currentZone if transfer else it's login
if (player.zone != null) if (player.zone != null)
{ {
player.playerSession.LockUpdates(true);
player.zone.RemoveActorFromZone(player); player.zone.RemoveActorFromZone(player);
player.zone.AddActorToZone(player); player.zone.AddActorToZone(player);
@ -606,35 +661,99 @@ namespace FFXIVClassic_Map_Server
player.rotation = spawnRotation; player.rotation = spawnRotation;
//Send packets //Send packets
player.playerSession.QueuePacket(_0xE2Packet.BuildPacket(player.actorId, 0x0), true, false); player.playerSession.QueuePacket(_0xE2Packet.BuildPacket(player.actorId, 0x10));
player.playerSession.QueuePacket(player.CreateSpawnTeleportPacket(player.actorId, spawnType), true, false); player.playerSession.QueuePacket(player.CreateSpawnTeleportPacket(spawnType));
player.SendInstanceUpdate();
player.playerSession.LockUpdates(false);
player.SendInstanceUpdate();
} }
} }
//Login Zone In //Moves actor to new zone, and sends packets to spawn at the given coords.
public void DoLogin(Player player) public void DoZoneChangeContent(Player player, PrivateAreaContent contentArea, float spawnX, float spawnY, float spawnZ, float spawnRotation, ushort spawnType = SetActorPositionPacket.SPAWNTYPE_WARP_DUTY)
{
//Content area was null
if (contentArea == null)
{
Program.Log.Debug("Request to change to content area not on this server by: {0}.", player.customDisplayName);
return;
}
player.playerSession.LockUpdates(true);
Area oldZone = player.zone;
//Remove player from currentZone if transfer else it's login
if (player.zone != null)
{
oldZone.RemoveActorFromZone(player);
}
contentArea.AddActorToZone(player);
//Update player actor's properties
player.zoneId = contentArea.GetParentZone().actorId;
player.privateArea = contentArea.GetPrivateAreaName();
player.privateAreaType = contentArea.GetPrivateAreaType();
player.zone = contentArea;
player.positionX = spawnX;
player.positionY = spawnY;
player.positionZ = spawnZ;
player.rotation = spawnRotation;
//Send "You have entered an instance" if it's a Private Area
player.SendGameMessage(GetActor(), 34108, 0x20);
//Send packets
player.playerSession.QueuePacket(DeleteAllActorsPacket.BuildPacket(player.actorId));
player.playerSession.QueuePacket(_0xE2Packet.BuildPacket(player.actorId, 0x10));
player.SendZoneInPackets(this, spawnType);
player.playerSession.ClearInstance();
player.SendInstanceUpdate();
player.playerSession.LockUpdates(false);
LuaEngine.GetInstance().CallLuaFunction(player, contentArea, "onZoneIn", true);
}
//Session started, zone into world
public void DoZoneIn(Player player, bool isLogin, ushort spawnType)
{ {
//Add player to new zone and update //Add player to new zone and update
Zone zone = GetZone(player.zoneId); Area playerArea;
if (player.privateArea != null)
playerArea = GetPrivateArea(player.zoneId, player.privateArea, player.privateAreaType);
else
playerArea = GetZone(player.zoneId);
//This server does not contain that zoneId //This server does not contain that zoneId
if (zone == null) if (playerArea == null)
return; return;
//Set the current zone and add player //Set the current zone and add player
player.zone = zone; player.zone = playerArea;
LuaEngine.OnBeginLogin(player); playerArea.AddActorToZone(player);
zone.AddActorToZone(player);
//Send packets //Send packets
player.SendZoneInPackets(this, 0x1); if (!isLogin)
{
player.playerSession.QueuePacket(DeleteAllActorsPacket.BuildPacket(player.actorId));
player.playerSession.QueuePacket(_0xE2Packet.BuildPacket(player.actorId, 0x2));
//player.SendZoneInPackets(this, spawnType);
}
LuaEngine.OnLogin(player); player.SendZoneInPackets(this, spawnType);
LuaEngine.OnZoneIn(player);
player.destinationZone = 0;
player.destinationSpawnType = 0;
Database.SavePlayerPosition(player);
player.playerSession.LockUpdates(false);
LuaEngine.GetInstance().CallLuaFunction(player, playerArea, "onZoneIn", true);
} }
public void ReloadZone(uint zoneId) public void ReloadZone(uint zoneId)
@ -648,15 +767,267 @@ namespace FFXIVClassic_Map_Server
} }
public ContentGroup CreateContentGroup(Director director, params Actor[] actors)
{
if (director == null)
return null;
lock (groupLock)
{
uint[] initialMembers = null;
if (actors != null)
{
initialMembers = new uint[actors.Length];
for (int i = 0; i < actors.Length; i++)
initialMembers[i] = actors[i].actorId;
}
groupIndexId = groupIndexId | 0x3000000000000000;
ContentGroup contentGroup = new ContentGroup(groupIndexId, director, initialMembers);
mContentGroups.Add(groupIndexId, contentGroup);
groupIndexId++;
if (initialMembers != null && initialMembers.Length != 0)
contentGroup.SendAll();
return contentGroup;
}
}
public ContentGroup CreateContentGroup(Director director, List<Actor> actors)
{
if (director == null)
return null;
lock (groupLock)
{
uint[] initialMembers = null;
if (actors != null)
{
initialMembers = new uint[actors.Count];
for (int i = 0; i < actors.Count; i++)
initialMembers[i] = actors[i].actorId;
}
groupIndexId = groupIndexId | 0x3000000000000000;
ContentGroup contentGroup = new ContentGroup(groupIndexId, director, initialMembers);
mContentGroups.Add(groupIndexId, contentGroup);
groupIndexId++;
if (initialMembers != null && initialMembers.Length != 0)
contentGroup.SendAll();
return contentGroup;
}
}
public ContentGroup CreateGLContentGroup(Director director, List<Actor> actors)
{
if (director == null)
return null;
lock (groupLock)
{
uint[] initialMembers = null;
if (actors != null)
{
initialMembers = new uint[actors.Count];
for (int i = 0; i < actors.Count; i++)
initialMembers[i] = actors[i].actorId;
}
groupIndexId = groupIndexId | 0x2000000000000000;
GLContentGroup contentGroup = new GLContentGroup(groupIndexId, director, initialMembers);
mContentGroups.Add(groupIndexId, contentGroup);
groupIndexId++;
if (initialMembers != null && initialMembers.Length != 0)
contentGroup.SendAll();
return contentGroup;
}
}
public void DeleteContentGroup(ulong groupId)
{
lock (groupLock)
{
if (mContentGroups.ContainsKey(groupId) && mContentGroups[groupId] is ContentGroup)
{
ContentGroup group = (ContentGroup)mContentGroups[groupId];
mContentGroups.Remove(groupId);
}
}
}
public bool SendGroupInit(Session session, ulong groupId)
{
if (mContentGroups.ContainsKey(groupId))
{
mContentGroups[groupId].SendInitWorkValues(session);
return true;
}
return false;
}
public void RequestWorldLinkshellCreate(Player player, string name, ushort crest)
{
SubPacket packet = CreateLinkshellPacket.BuildPacket(player.playerSession, name, crest, player.actorId);
player.QueuePacket(packet);
}
public void RequestWorldLinkshellCrestModify(Player player, string name, ushort crest)
{
SubPacket packet = ModifyLinkshellPacket.BuildPacket(player.playerSession, 1, name, null, crest, 0);
player.QueuePacket(packet);
}
public void RequestWorldLinkshellDelete(Player player, string name)
{
SubPacket packet = DeleteLinkshellPacket.BuildPacket(player.playerSession, name);
player.QueuePacket(packet);
}
public void RequestWorldLinkshellRankChange(Player player, string lsname, string memberName, byte newRank)
{
SubPacket packet = LinkshellRankChangePacket.BuildPacket(player.playerSession, memberName, lsname, newRank);
player.QueuePacket(packet);
}
public void RequestWorldLinkshellInviteMember(Player player, string lsname, uint invitedActorId)
{
SubPacket packet = LinkshellInvitePacket.BuildPacket(player.playerSession, invitedActorId, lsname);
player.QueuePacket(packet);
}
public void RequestWorldLinkshellCancelInvite(Player player)
{
SubPacket packet = LinkshellInviteCancelPacket.BuildPacket(player.playerSession);
player.QueuePacket(packet);
}
public void RequestWorldLinkshellLeave(Player player, string lsname)
{
SubPacket packet = LinkshellLeavePacket.BuildPacket(player.playerSession, lsname, null, false);
player.QueuePacket(packet);
}
public void RequestWorldLinkshellKick(Player player, string lsname, string kickedName)
{
SubPacket packet = LinkshellLeavePacket.BuildPacket(player.playerSession, lsname, kickedName, true);
player.QueuePacket(packet);
}
public void RequestWorldLinkshellChangeActive(Player player, string lsname)
{
SubPacket packet = LinkshellChangePacket.BuildPacket(player.playerSession, lsname);
player.QueuePacket(packet);
}
private void RequestWorldServerZoneChange(Player player, uint destinationZoneId, byte spawnType, float spawnX, float spawnY, float spawnZ, float spawnRotation)
{
ZoneConnection zc = Server.GetWorldConnection();
zc.RequestZoneChange(player.playerSession.id, destinationZoneId, spawnType, spawnX, spawnY, spawnZ, spawnRotation);
}
//World server sent a party member list synch packet to the zone server. Add and update players that may be a part of it.
public void PartyMemberListRecieved(PartySyncPacket syncPacket)
{
lock (currentPlayerParties)
{
Party group;
//If no members on this server, get out or clean
if (!currentPlayerParties.ContainsKey(syncPacket.partyGroupId) && syncPacket.memberActorIds.Length == 0)
return;
else if (!currentPlayerParties.ContainsKey(syncPacket.partyGroupId) && syncPacket.memberActorIds.Length == 0)
NoMembersInParty(currentPlayerParties[syncPacket.partyGroupId]);
//Get or create group
if (!currentPlayerParties.ContainsKey(syncPacket.partyGroupId))
{
group = new Party(syncPacket.partyGroupId, syncPacket.owner);
currentPlayerParties.Add(syncPacket.partyGroupId, group);
}
else
group = currentPlayerParties[syncPacket.partyGroupId];
group.SetLeader(syncPacket.owner);
group.members = syncPacket.memberActorIds.ToList();
//Add group to everyone
for (int i = 0; i < group.members.Count; i++ )
{
uint member = group.members[i];
Session session = Server.GetServer().GetSession(member);
if (session == null)
continue;
Player player = session.GetActor();
if (player == null)
continue;
player.SetParty(group);
}
}
}
//Player was removed from the party either due to leaving it or leaving the server. Remove if empty.
public void NoMembersInParty(Party party)
{
if (currentPlayerParties.ContainsKey(party.groupIndex))
currentPlayerParties.Remove(party.groupIndex);
}
public void CreateInvitePartyGroup(Player player, string name)
{
SubPacket invitePacket = PartyInvitePacket.BuildPacket(player.playerSession, name);
player.QueuePacket(invitePacket);
}
public void CreateInvitePartyGroup(Player player, uint actorId)
{
SubPacket invitePacket = PartyInvitePacket.BuildPacket(player.playerSession, actorId);
player.QueuePacket(invitePacket);
}
public void GroupInviteResult(Player player, uint groupType, uint result)
{
SubPacket groupInviteResultPacket = GroupInviteResultPacket.BuildPacket(player.playerSession, groupType, result);
player.QueuePacket(groupInviteResultPacket);
}
public void StartZoneThread()
{
mZoneTimer = new Timer(ZoneThreadLoop, null, 0, MILIS_LOOPTIME);
Program.Log.Info("Zone Loop has started");
}
public void ZoneThreadLoop(Object state)
{
lock (zoneList)
{
foreach (Area area in zoneList.Values)
area.Update(MILIS_LOOPTIME);
}
}
public Player GetPCInWorld(string name) public Player GetPCInWorld(string name)
{ {
foreach (Zone zone in zoneList.Values) if (Server.GetServer().GetSession(name) != null)
{ return Server.GetServer().GetSession(name).GetActor();
Player p = zone.FindPCInZone(name); else
if (p != null) return null;
return p; }
}
return null; public Player GetPCInWorld(uint charId)
{
if (Server.GetServer().GetSession(charId) != null)
return Server.GetServer().GetSession(charId).GetActor();
else
return null;
} }
public Actor GetActorInWorld(uint charId) public Actor GetActorInWorld(uint charId)
@ -670,13 +1041,13 @@ namespace FFXIVClassic_Map_Server
return null; return null;
} }
public Player GetPCInWorld(uint charId) public Actor GetActorInWorldByUniqueId(string uid)
{ {
foreach (Zone zone in zoneList.Values) foreach (Zone zone in zoneList.Values)
{ {
Player p = zone.FindPCInZone(charId); Actor a = zone.FindActorInZoneByUniqueID(uid);
if (p != null) if (a != null)
return p; return a;
} }
return null; return null;
} }
@ -688,6 +1059,14 @@ namespace FFXIVClassic_Map_Server
return zoneList[zoneId]; return zoneList[zoneId];
} }
public PrivateArea GetPrivateArea(uint zoneId, string privateArea, uint privateAreaType)
{
if (!zoneList.ContainsKey(zoneId))
return null;
return zoneList[zoneId].GetPrivateArea(privateArea, privateAreaType);
}
public WorldMaster GetActor() public WorldMaster GetActor()
{ {
return worldMaster; return worldMaster;
@ -702,16 +1081,18 @@ namespace FFXIVClassic_Map_Server
{ {
public uint zoneId; public uint zoneId;
public string privateAreaName; public string privateAreaName;
public int privateAreaType;
public byte spawnType; public byte spawnType;
public float spawnX; public float spawnX;
public float spawnY; public float spawnY;
public float spawnZ; public float spawnZ;
public float spawnRotation; public float spawnRotation;
public ZoneEntrance(uint zoneId, string privateAreaName, byte spawnType, float x, float y, float z, float rot) public ZoneEntrance(uint zoneId, string privateAreaName, int privateAreaType, byte spawnType, float x, float y, float z, float rot)
{ {
this.zoneId = zoneId; this.zoneId = zoneId;
this.privateAreaName = privateAreaName; this.privateAreaName = privateAreaName;
this.privateAreaType = privateAreaType;
this.spawnType = spawnType; this.spawnType = spawnType;
this.spawnX = x; this.spawnX = x;
this.spawnY = y; this.spawnY = y;

View File

@ -1,4 +1,4 @@
using FFXIVClassic_Map_Server.packets; 
using FFXIVClassic_Map_Server.actors; using FFXIVClassic_Map_Server.actors;
using FFXIVClassic_Map_Server.lua; using FFXIVClassic_Map_Server.lua;
using FFXIVClassic_Map_Server.packets.send.actor; using FFXIVClassic_Map_Server.packets.send.actor;
@ -7,6 +7,9 @@ using FFXIVClassic.Common;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using FFXIVClassic_Map_Server.actors.area; using FFXIVClassic_Map_Server.actors.area;
using System.Reflection;
using System.ComponentModel;
using FFXIVClassic_Map_Server.packets.send.actor.battle;
namespace FFXIVClassic_Map_Server.Actors namespace FFXIVClassic_Map_Server.Actors
{ {
@ -23,9 +26,11 @@ namespace FFXIVClassic_Map_Server.Actors
public float positionX, positionY, positionZ, rotation; public float positionX, positionY, positionZ, rotation;
public float oldPositionX, oldPositionY, oldPositionZ, oldRotation; public float oldPositionX, oldPositionY, oldPositionZ, oldRotation;
public ushort moveState, oldMoveState; public ushort moveState, oldMoveState;
public float[] moveSpeeds = new float[5]; public float[] moveSpeeds = new float[4];
public uint zoneId, zoneId2; public uint zoneId, zoneId2;
public string privateArea;
public uint privateAreaType;
public Area zone = null; public Area zone = null;
public Area zone2 = null; public Area zone2 = null;
public bool isZoning = false; public bool isZoning = false;
@ -53,69 +58,91 @@ namespace FFXIVClassic_Map_Server.Actors
this.moveSpeeds[0] = SetActorSpeedPacket.DEFAULT_STOP; this.moveSpeeds[0] = SetActorSpeedPacket.DEFAULT_STOP;
this.moveSpeeds[1] = SetActorSpeedPacket.DEFAULT_WALK; this.moveSpeeds[1] = SetActorSpeedPacket.DEFAULT_WALK;
this.moveSpeeds[2] = SetActorSpeedPacket.DEFAULT_RUN; this.moveSpeeds[2] = SetActorSpeedPacket.DEFAULT_RUN;
this.moveSpeeds[3] = SetActorSpeedPacket.DEFAULT_RUN; this.moveSpeeds[3] = SetActorSpeedPacket.DEFAULT_ACTIVE;
} }
public SubPacket CreateAddActorPacket(uint playerActorId, byte val) public void SetPushCircleRange(string triggerName, float size)
{ {
return AddActorPacket.BuildPacket(actorId, playerActorId, val); if (eventConditions == null || eventConditions.pushWithCircleEventConditions == null)
return;
foreach (EventList.PushCircleEventCondition condition in eventConditions.pushWithCircleEventConditions)
{
if (condition.conditionName.Equals(triggerName))
{
condition.radius = size;
break;
}
}
} }
public SubPacket CreateNamePacket(uint playerActorId) public SubPacket CreateAddActorPacket(byte val)
{ {
return SetActorNamePacket.BuildPacket(actorId, playerActorId, displayNameId, displayNameId == 0xFFFFFFFF | displayNameId == 0x0 ? customDisplayName : ""); return AddActorPacket.BuildPacket(actorId, val);
} }
public SubPacket CreateSpeedPacket(uint playerActorId) public SubPacket CreateNamePacket()
{ {
return SetActorSpeedPacket.BuildPacket(actorId, playerActorId, moveSpeeds[0], moveSpeeds[1], moveSpeeds[2]); return SetActorNamePacket.BuildPacket(actorId, displayNameId, displayNameId == 0xFFFFFFFF | displayNameId == 0x0 ? customDisplayName : "");
} }
public SubPacket CreateSpawnPositonPacket(uint playerActorId, uint spawnType) public SubPacket CreateSpeedPacket()
{ {
return SetActorSpeedPacket.BuildPacket(actorId, moveSpeeds[0], moveSpeeds[1], moveSpeeds[2], moveSpeeds[3]);
}
public SubPacket CreateSpawnPositonPacket(ushort spawnType)
{
return CreateSpawnPositonPacket(null, spawnType);
}
public SubPacket CreateSpawnPositonPacket(Player player, ushort spawnType)
{
//TODO: FIX THIS IF
uint playerActorId = player == null ? 0 : player.actorId; //Get Rid
SubPacket spawnPacket; SubPacket spawnPacket;
if (!spawnedFirstTime && playerActorId == actorId) if (!spawnedFirstTime && playerActorId == actorId)
spawnPacket = SetActorPositionPacket.BuildPacket(actorId, playerActorId, 0, positionX, positionY, positionZ, rotation, 0x1, false); spawnPacket = SetActorPositionPacket.BuildPacket(actorId, 0, positionX, positionY, positionZ, rotation, 0x1, false);
else if (playerActorId == actorId) else if (playerActorId == actorId)
spawnPacket = SetActorPositionPacket.BuildPacket(actorId, playerActorId, 0xFFFFFFFF, positionX, positionY, positionZ, rotation, spawnType, true); spawnPacket = SetActorPositionPacket.BuildPacket(actorId, 0xFFFFFFFF, positionX, positionY, positionZ, rotation, spawnType, true);
else else
{ {
if (this is Player) if (this is Player)
spawnPacket = SetActorPositionPacket.BuildPacket(actorId, playerActorId, 0, positionX, positionY, positionZ, rotation, spawnType, false); spawnPacket = SetActorPositionPacket.BuildPacket(actorId, 0, positionX, positionY, positionZ, rotation, spawnType, false);
else else
spawnPacket = SetActorPositionPacket.BuildPacket(actorId, playerActorId, actorId, positionX, positionY, positionZ, rotation, spawnType, false); spawnPacket = SetActorPositionPacket.BuildPacket(actorId, actorId, positionX, positionY, positionZ, rotation, spawnType, false);
} }
//return SetActorPositionPacket.BuildPacket(actorId, playerActorId, -211.895477f, 190.000000f, 29.651011f, 2.674819f, SetActorPositionPacket.SPAWNTYPE_PLAYERWAKE); //return SetActorPositionPacket.BuildPacket(actorId, -211.895477f, 190.000000f, 29.651011f, 2.674819f, SetActorPositionPacket.SPAWNTYPE_PLAYERWAKE);
spawnedFirstTime = true; spawnedFirstTime = true;
return spawnPacket; return spawnPacket;
} }
public SubPacket CreateSpawnTeleportPacket(uint playerActorId, uint spawnType) public SubPacket CreateSpawnTeleportPacket(ushort spawnType)
{ {
SubPacket spawnPacket; SubPacket spawnPacket;
spawnPacket = SetActorPositionPacket.BuildPacket(actorId, playerActorId, 0xFFFFFFFF, positionX, positionY, positionZ, rotation, spawnType, false); spawnPacket = SetActorPositionPacket.BuildPacket(actorId, 0xFFFFFFFF, positionX, positionY, positionZ, rotation, spawnType, false);
//return SetActorPositionPacket.BuildPacket(actorId, playerActorId, -211.895477f, 190.000000f, 29.651011f, 2.674819f, SetActorPositionPacket.SPAWNTYPE_PLAYERWAKE); //return SetActorPositionPacket.BuildPacket(actorId, -211.895477f, 190.000000f, 29.651011f, 2.674819f, SetActorPositionPacket.SPAWNTYPE_PLAYERWAKE);
//spawnPacket.DebugPrintSubPacket(); //spawnPacket.DebugPrintSubPacket();
return spawnPacket; return spawnPacket;
} }
public SubPacket CreatePositionUpdatePacket(uint playerActorId) public SubPacket CreatePositionUpdatePacket()
{ {
return MoveActorToPositionPacket.BuildPacket(actorId, playerActorId, positionX, positionY, positionZ, rotation, moveState); return MoveActorToPositionPacket.BuildPacket(actorId, positionX, positionY, positionZ, rotation, moveState);
} }
public SubPacket CreateStatePacket(uint playerActorID) public SubPacket CreateStatePacket()
{ {
return SetActorStatePacket.BuildPacket(actorId, playerActorID, currentMainState, currentSubState); return SetActorStatePacket.BuildPacket(actorId, currentMainState, currentSubState);
} }
public List<SubPacket> GetEventConditionPackets(uint playerActorId) public List<SubPacket> GetEventConditionPackets()
{ {
List<SubPacket> subpackets = new List<SubPacket>(); List<SubPacket> subpackets = new List<SubPacket>();
@ -126,126 +153,147 @@ namespace FFXIVClassic_Map_Server.Actors
if (eventConditions.talkEventConditions != null) if (eventConditions.talkEventConditions != null)
{ {
foreach (EventList.TalkEventCondition condition in eventConditions.talkEventConditions) foreach (EventList.TalkEventCondition condition in eventConditions.talkEventConditions)
subpackets.Add(SetTalkEventCondition.BuildPacket(playerActorId, actorId, condition)); subpackets.Add(SetTalkEventCondition.BuildPacket(actorId, condition));
} }
if (eventConditions.noticeEventConditions != null) if (eventConditions.noticeEventConditions != null)
{ {
foreach (EventList.NoticeEventCondition condition in eventConditions.noticeEventConditions) foreach (EventList.NoticeEventCondition condition in eventConditions.noticeEventConditions)
subpackets.Add(SetNoticeEventCondition.BuildPacket(playerActorId, actorId, condition)); subpackets.Add(SetNoticeEventCondition.BuildPacket(actorId, condition));
} }
if (eventConditions.emoteEventConditions != null) if (eventConditions.emoteEventConditions != null)
{ {
foreach (EventList.EmoteEventCondition condition in eventConditions.emoteEventConditions) foreach (EventList.EmoteEventCondition condition in eventConditions.emoteEventConditions)
subpackets.Add(SetEmoteEventCondition.BuildPacket(playerActorId, actorId, condition)); subpackets.Add(SetEmoteEventCondition.BuildPacket(actorId, condition));
} }
if (eventConditions.pushWithCircleEventConditions != null) if (eventConditions.pushWithCircleEventConditions != null)
{ {
foreach (EventList.PushCircleEventCondition condition in eventConditions.pushWithCircleEventConditions) foreach (EventList.PushCircleEventCondition condition in eventConditions.pushWithCircleEventConditions)
subpackets.Add(SetPushEventConditionWithCircle.BuildPacket(playerActorId, actorId, condition)); subpackets.Add(SetPushEventConditionWithCircle.BuildPacket(actorId, condition));
} }
if (eventConditions.pushWithFanEventConditions != null) if (eventConditions.pushWithFanEventConditions != null)
{ {
foreach (EventList.PushFanEventCondition condition in eventConditions.pushWithFanEventConditions) foreach (EventList.PushFanEventCondition condition in eventConditions.pushWithFanEventConditions)
subpackets.Add(SetPushEventConditionWithFan.BuildPacket(playerActorId, actorId, condition)); subpackets.Add(SetPushEventConditionWithFan.BuildPacket(actorId, condition));
} }
if (eventConditions.pushWithBoxEventConditions != null) if (eventConditions.pushWithBoxEventConditions != null)
{ {
foreach (EventList.PushBoxEventCondition condition in eventConditions.pushWithBoxEventConditions) foreach (EventList.PushBoxEventCondition condition in eventConditions.pushWithBoxEventConditions)
subpackets.Add(SetPushEventConditionWithTriggerBox.BuildPacket(playerActorId, actorId, condition)); subpackets.Add(SetPushEventConditionWithTriggerBox.BuildPacket(actorId, condition));
} }
return subpackets; return subpackets;
} }
public BasePacket GetSetEventStatusPackets(uint playerActorId) public List<SubPacket> GetSetEventStatusPackets()
{ {
List<SubPacket> subpackets = new List<SubPacket>(); List<SubPacket> subpackets = new List<SubPacket>();
//Return empty list //Return empty list
if (eventConditions == null) if (eventConditions == null)
return BasePacket.CreatePacket(subpackets, true, false); return subpackets;
if (eventConditions.talkEventConditions != null) if (eventConditions.talkEventConditions != null)
{ {
foreach (EventList.TalkEventCondition condition in eventConditions.talkEventConditions) foreach (EventList.TalkEventCondition condition in eventConditions.talkEventConditions)
subpackets.Add(SetEventStatus.BuildPacket(playerActorId, actorId, true, 1, condition.conditionName)); subpackets.Add(SetEventStatus.BuildPacket(actorId, true, 1, condition.conditionName));
} }
if (eventConditions.noticeEventConditions != null) if (eventConditions.noticeEventConditions != null)
{ {
foreach (EventList.NoticeEventCondition condition in eventConditions.noticeEventConditions) foreach (EventList.NoticeEventCondition condition in eventConditions.noticeEventConditions)
subpackets.Add(SetEventStatus.BuildPacket(playerActorId, actorId, true, 1, condition.conditionName)); subpackets.Add(SetEventStatus.BuildPacket(actorId, true, 1, condition.conditionName));
} }
if (eventConditions.emoteEventConditions != null) if (eventConditions.emoteEventConditions != null)
{ {
foreach (EventList.EmoteEventCondition condition in eventConditions.emoteEventConditions) foreach (EventList.EmoteEventCondition condition in eventConditions.emoteEventConditions)
subpackets.Add(SetEventStatus.BuildPacket(playerActorId, actorId, true, 3, condition.conditionName)); subpackets.Add(SetEventStatus.BuildPacket(actorId, true, 3, condition.conditionName));
} }
if (eventConditions.pushWithCircleEventConditions != null) if (eventConditions.pushWithCircleEventConditions != null)
{ {
foreach (EventList.PushCircleEventCondition condition in eventConditions.pushWithCircleEventConditions) foreach (EventList.PushCircleEventCondition condition in eventConditions.pushWithCircleEventConditions)
subpackets.Add(SetEventStatus.BuildPacket(playerActorId, actorId, true, 2, condition.conditionName)); subpackets.Add(SetEventStatus.BuildPacket(actorId, true, 2, condition.conditionName));
} }
if (eventConditions.pushWithFanEventConditions != null) if (eventConditions.pushWithFanEventConditions != null)
{ {
foreach (EventList.PushFanEventCondition condition in eventConditions.pushWithFanEventConditions) foreach (EventList.PushFanEventCondition condition in eventConditions.pushWithFanEventConditions)
subpackets.Add(SetEventStatus.BuildPacket(playerActorId, actorId, true, 2, condition.conditionName)); subpackets.Add(SetEventStatus.BuildPacket(actorId, true, 2, condition.conditionName));
} }
if (eventConditions.pushWithBoxEventConditions != null) if (eventConditions.pushWithBoxEventConditions != null)
{ {
foreach (EventList.PushBoxEventCondition condition in eventConditions.pushWithBoxEventConditions) foreach (EventList.PushBoxEventCondition condition in eventConditions.pushWithBoxEventConditions)
subpackets.Add(SetEventStatus.BuildPacket(playerActorId, actorId, true, 2, condition.conditionName)); subpackets.Add(SetEventStatus.BuildPacket(actorId, true, 2, condition.conditionName));
} }
return BasePacket.CreatePacket(subpackets, true, false); return subpackets;
} }
public SubPacket CreateIsZoneingPacket(uint playerActorId) public SubPacket CreateIsZoneingPacket()
{ {
return SetActorIsZoningPacket.BuildPacket(actorId, playerActorId, false); return SetActorIsZoningPacket.BuildPacket(actorId, false);
} }
public virtual SubPacket CreateScriptBindPacket(uint playerActorId) public virtual SubPacket CreateScriptBindPacket(Player player)
{ {
return ActorInstantiatePacket.BuildPacket(actorId, playerActorId, actorName, className, classParams); return ActorInstantiatePacket.BuildPacket(actorId, actorName, className, classParams);
} }
public virtual BasePacket GetSpawnPackets(uint playerActorId) public virtual SubPacket CreateScriptBindPacket()
{ {
return GetSpawnPackets(playerActorId, 0x1); return ActorInstantiatePacket.BuildPacket(actorId, actorName, className, classParams);
} }
public virtual BasePacket GetSpawnPackets(uint playerActorId, uint spawnType) public virtual List<SubPacket> GetSpawnPackets(Player player, ushort spawnType)
{ {
List<SubPacket> subpackets = new List<SubPacket>(); List<SubPacket> subpackets = new List<SubPacket>();
subpackets.Add(CreateAddActorPacket(playerActorId, 8)); subpackets.Add(CreateAddActorPacket(8));
subpackets.AddRange(GetEventConditionPackets(playerActorId)); subpackets.AddRange(GetEventConditionPackets());
subpackets.Add(CreateSpeedPacket(playerActorId)); subpackets.Add(CreateSpeedPacket());
subpackets.Add(CreateSpawnPositonPacket(playerActorId, spawnType)); subpackets.Add(CreateSpawnPositonPacket(player, spawnType));
subpackets.Add(CreateNamePacket(playerActorId)); subpackets.Add(CreateNamePacket());
subpackets.Add(CreateStatePacket(playerActorId)); subpackets.Add(CreateStatePacket());
subpackets.Add(CreateIsZoneingPacket(playerActorId)); subpackets.Add(CreateIsZoneingPacket());
subpackets.Add(CreateScriptBindPacket(playerActorId)); subpackets.Add(CreateScriptBindPacket(player));
return BasePacket.CreatePacket(subpackets, true, false); return subpackets;
} }
public virtual BasePacket GetInitPackets(uint playerActorId) public virtual List<SubPacket> GetSpawnPackets()
{ {
return GetSpawnPackets(0x1);
}
public virtual List<SubPacket> GetSpawnPackets(ushort spawnType)
{
List<SubPacket> subpackets = new List<SubPacket>();
subpackets.Add(CreateAddActorPacket(8));
subpackets.AddRange(GetEventConditionPackets());
subpackets.Add(CreateSpeedPacket());
subpackets.Add(CreateSpawnPositonPacket(null, spawnType));
subpackets.Add(CreateNamePacket());
subpackets.Add(CreateStatePacket());
subpackets.Add(CreateIsZoneingPacket());
subpackets.Add(CreateScriptBindPacket());
return subpackets;
}
public virtual List<SubPacket> GetInitPackets()
{
List<SubPacket> packets = new List<SubPacket>();
SetActorPropetyPacket initProperties = new SetActorPropetyPacket("/_init"); SetActorPropetyPacket initProperties = new SetActorPropetyPacket("/_init");
initProperties.AddByte(0xE14B0CA8, 1); initProperties.AddByte(0xE14B0CA8, 1);
initProperties.AddByte(0x2138FD71, 1); initProperties.AddByte(0x2138FD71, 1);
initProperties.AddByte(0xFBFBCFB1, 1); initProperties.AddByte(0xFBFBCFB1, 1);
initProperties.AddTarget(); initProperties.AddTarget();
return BasePacket.CreatePacket(initProperties.BuildPacket(playerActorId, actorId), true, false); packets.Add(initProperties.BuildPacket(actorId));
return packets;
} }
public override bool Equals(Object obj) public override bool Equals(Object obj)
@ -280,8 +328,8 @@ namespace FFXIVClassic_Map_Server.Actors
public void ChangeState(ushort newState) public void ChangeState(ushort newState)
{ {
currentMainState = newState; currentMainState = newState;
SubPacket ChangeStatePacket = SetActorStatePacket.BuildPacket(actorId, actorId, newState, currentSubState); SubPacket ChangeStatePacket = SetActorStatePacket.BuildPacket(actorId, newState, currentSubState);
SubPacket battleActionPacket = BattleAction1Packet.BuildPacket(actorId, actorId); SubPacket battleActionPacket = BattleActionX01Packet.BuildPacket(actorId, actorId, actorId, 0x72000062, 1, 0, 0x05209, 0, 0);
zone.BroadcastPacketAroundActor(this, ChangeStatePacket); zone.BroadcastPacketAroundActor(this, ChangeStatePacket);
zone.BroadcastPacketAroundActor(this, battleActionPacket); zone.BroadcastPacketAroundActor(this, battleActionPacket);
} }
@ -289,20 +337,24 @@ namespace FFXIVClassic_Map_Server.Actors
public void ChangeSpeed(int type, float value) public void ChangeSpeed(int type, float value)
{ {
moveSpeeds[type] = value; moveSpeeds[type] = value;
SubPacket ChangeSpeedPacket = SetActorSpeedPacket.BuildPacket(actorId, actorId, moveSpeeds[0], moveSpeeds[1], moveSpeeds[2]); SubPacket ChangeSpeedPacket = SetActorSpeedPacket.BuildPacket(actorId, moveSpeeds[0], moveSpeeds[1], moveSpeeds[2], moveSpeeds[3]);
zone.BroadcastPacketAroundActor(this, ChangeSpeedPacket); zone.BroadcastPacketAroundActor(this, ChangeSpeedPacket);
} }
public void ChangeSpeed(float speedStop, float speedWalk, float speedRun) public void ChangeSpeed(float speedStop, float speedWalk, float speedRun, float speedActive)
{ {
moveSpeeds[0] = speedStop; moveSpeeds[0] = speedStop;
moveSpeeds[1] = speedWalk; moveSpeeds[1] = speedWalk;
moveSpeeds[2] = speedRun; moveSpeeds[2] = speedRun;
moveSpeeds[3] = speedRun; moveSpeeds[3] = speedActive;
SubPacket ChangeSpeedPacket = SetActorSpeedPacket.BuildPacket(actorId, actorId, moveSpeeds[0], moveSpeeds[1], moveSpeeds[2]); SubPacket ChangeSpeedPacket = SetActorSpeedPacket.BuildPacket(actorId, moveSpeeds[0], moveSpeeds[1], moveSpeeds[2], moveSpeeds[3]);
zone.BroadcastPacketAroundActor(this, ChangeSpeedPacket); zone.BroadcastPacketAroundActor(this, ChangeSpeedPacket);
} }
public void Update(double deltaTime)
{
}
public void GenerateActorName(int actorNumber) public void GenerateActorName(int actorNumber)
{ {
//Format Class Name //Format Class Name
@ -345,11 +397,92 @@ namespace FFXIVClassic_Map_Server.Actors
uint zoneId = zone.actorId; uint zoneId = zone.actorId;
uint privLevel = 0; uint privLevel = 0;
if (zone is PrivateArea) if (zone is PrivateArea)
privLevel = ((PrivateArea)zone).GetPrivateAreaLevel(); privLevel = ((PrivateArea)zone).GetPrivateAreaType();
actorName = String.Format("{0}_{1}_{2}@{3:X3}{4:X2}", className, zoneName, classNumber, zoneId, privLevel); actorName = String.Format("{0}_{1}_{2}@{3:X3}{4:X2}", className, zoneName, classNumber, zoneId, privLevel);
} }
public bool SetWorkValue(Player player, string name, string uiFunc, object value)
{
string[] split = name.Split('.');
int arrayIndex = 0;
if (!(split[0].Equals("work") || split[0].Equals("charaWork") || split[0].Equals("playerWork") || split[0].Equals("npcWork")))
return false;
Object parentObj = null;
Object curObj = this;
for (int i = 0; i < split.Length; i++)
{
//For arrays
if (split[i].Contains("["))
{
if (split[i].LastIndexOf(']') - split[i].IndexOf('[') <= 0)
return false;
arrayIndex = Convert.ToInt32(split[i].Substring(split[i].IndexOf('[') + 1, split[i].LastIndexOf(']') - split[i].LastIndexOf('[') - 1));
split[i] = split[i].Substring(0, split[i].IndexOf('['));
}
FieldInfo field = curObj.GetType().GetField(split[i]);
if (field == null)
return false;
if (i == split.Length - 1)
parentObj = curObj;
curObj = field.GetValue(curObj);
if (curObj == null)
return false;
}
if (curObj == null)
return false;
else
{
//Array, we actually care whats inside
if (curObj.GetType().IsArray)
{
if (((Array)curObj).Length <= arrayIndex)
return false;
if (value.GetType() == ((Array)curObj).GetType().GetElementType() || TypeDescriptor.GetConverter(value.GetType()).CanConvertTo(((Array)curObj).GetType().GetElementType()))
{
if (value.GetType() == ((Array)curObj).GetType().GetElementType())
((Array)curObj).SetValue(value, arrayIndex);
else
((Array)curObj).SetValue(TypeDescriptor.GetConverter(value.GetType()).ConvertTo(value, curObj.GetType().GetElementType()), arrayIndex);
SetActorPropetyPacket changeProperty = new SetActorPropetyPacket(uiFunc);
changeProperty.AddProperty(this, name);
changeProperty.AddTarget();
SubPacket subpacket = changeProperty.BuildPacket(player.actorId);
player.playerSession.QueuePacket(subpacket);
subpacket.DebugPrintSubPacket();
return true;
}
}
else
{
if (value.GetType() == curObj.GetType() || TypeDescriptor.GetConverter(value.GetType()).CanConvertTo(curObj.GetType()))
{
if (value.GetType() == curObj.GetType())
parentObj.GetType().GetField(split[split.Length - 1]).SetValue(parentObj, value);
else
parentObj.GetType().GetField(split[split.Length-1]).SetValue(parentObj, TypeDescriptor.GetConverter(value.GetType()).ConvertTo(value, curObj.GetType()));
SetActorPropetyPacket changeProperty = new SetActorPropetyPacket(uiFunc);
changeProperty.AddProperty(this, name);
changeProperty.AddTarget();
SubPacket subpacket = changeProperty.BuildPacket(player.actorId);
player.playerSession.QueuePacket(subpacket);
subpacket.DebugPrintSubPacket();
return true;
}
}
return false;
}
}
public List<float> GetPos() public List<float> GetPos()
{ {
List<float> pos = new List<float>(); List<float> pos = new List<float>();
@ -376,7 +509,7 @@ namespace FFXIVClassic_Map_Server.Actors
rotation = rot; rotation = rot;
// todo: handle zone? // todo: handle zone?
zone.BroadcastPacketAroundActor(this, MoveActorToPositionPacket.BuildPacket(this.actorId, this.actorId, x, y, z, rot, moveState)); zone.BroadcastPacketAroundActor(this, MoveActorToPositionPacket.BuildPacket(actorId, x, y, z, rot, moveState));
} }
public Area GetZone() public Area GetZone()

View File

@ -1,6 +1,5 @@
using FFXIVClassic_Map_Server; using FFXIVClassic_Map_Server;
using FFXIVClassic.Common; using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.packets;
using FFXIVClassic_Map_Server.actors.area; using FFXIVClassic_Map_Server.actors.area;
using FFXIVClassic_Map_Server.actors.chara.npc; using FFXIVClassic_Map_Server.actors.chara.npc;
using FFXIVClassic_Map_Server.dataobjects; using FFXIVClassic_Map_Server.dataobjects;
@ -14,6 +13,8 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using FFXIVClassic_Map_Server.packets.send; using FFXIVClassic_Map_Server.packets.send;
using FFXIVClassic_Map_Server.actors.group;
using FFXIVClassic_Map_Server.actors.director;
namespace FFXIVClassic_Map_Server.Actors namespace FFXIVClassic_Map_Server.Actors
{ {
@ -28,17 +29,23 @@ namespace FFXIVClassic_Map_Server.Actors
protected string classPath; protected string classPath;
public int boundingGridSize = 50; public int boundingGridSize = 50;
public int minX = -1000, minY = -1000, maxX = 1000, maxY = 1000; public int minX = -5000, minY = -5000, maxX = 5000, maxY = 5000;
protected int numXBlocks, numYBlocks; protected int numXBlocks, numYBlocks;
protected int halfWidth, halfHeight; protected int halfWidth, halfHeight;
private Dictionary<uint, Director> currentDirectors = new Dictionary<uint, Director>();
private Object directorLock = new Object();
private uint directorIdCount = 0;
protected Director mWeatherDirector;
protected List<SpawnLocation> mSpawnLocations = new List<SpawnLocation>(); protected List<SpawnLocation> mSpawnLocations = new List<SpawnLocation>();
protected Dictionary<uint, Actor> mActorList = new Dictionary<uint, Actor>(); protected Dictionary<uint, Actor> mActorList = new Dictionary<uint, Actor>();
protected List<Actor>[,] mActorBlock; protected List<Actor>[,] mActorBlock;
LuaScript areaScript; LuaScript areaScript;
public Area(uint id, string zoneName, ushort regionId, string className, ushort bgmDay, ushort bgmNight, ushort bgmBattle, bool isIsolated, bool isInn, bool canRideChocobo, bool canStealth, bool isInstanceRaid) public Area(uint id, string zoneName, ushort regionId, string classPath, ushort bgmDay, ushort bgmNight, ushort bgmBattle, bool isIsolated, bool isInn, bool canRideChocobo, bool canStealth, bool isInstanceRaid)
: base(id) : base(id)
{ {
@ -56,9 +63,10 @@ namespace FFXIVClassic_Map_Server.Actors
this.displayNameId = 0; this.displayNameId = 0;
this.customDisplayName = "_areaMaster"; this.customDisplayName = "_areaMaster";
this.actorName = String.Format("_areaMaster@{0:X5}",id<<8); this.actorName = String.Format("_areaMaster@{0:X5}", id << 8);
this.className = className; this.classPath = classPath;
this.className = classPath.Substring(classPath.LastIndexOf("/") + 1);
numXBlocks = (maxX - minX) / boundingGridSize; numXBlocks = (maxX - minX) / boundingGridSize;
numYBlocks = (maxY - minY) / boundingGridSize; numYBlocks = (maxY - minY) / boundingGridSize;
@ -68,40 +76,42 @@ namespace FFXIVClassic_Map_Server.Actors
for (int y = 0; y < numYBlocks; y++) for (int y = 0; y < numYBlocks; y++)
{ {
for (int x = 0; x < numXBlocks; x++ ) for (int x = 0; x < numXBlocks; x++)
{ {
mActorBlock[x, y] = new List<Actor>(); mActorBlock[x, y] = new List<Actor>();
} }
} }
} }
public override SubPacket CreateScriptBindPacket(uint playerActorId) public override SubPacket CreateScriptBindPacket()
{ {
List<LuaParam> lParams; List<LuaParam> lParams;
lParams = LuaUtils.CreateLuaParamList(classPath, false, true, zoneName, "/Area/Zone/ZoneDefault", -1, (byte)1, true, false, false, false, false, false, false, false); lParams = LuaUtils.CreateLuaParamList(classPath, false, true, zoneName, "/Area/Zone/ZoneDefault", -1, (byte)1, true, false, false, false, false, false, false, false);
return ActorInstantiatePacket.BuildPacket(actorId, playerActorId, actorName, "ZoneDefault", lParams); return ActorInstantiatePacket.BuildPacket(actorId, actorName, "ZoneDefault", lParams);
} }
public override BasePacket GetSpawnPackets(uint playerActorId) public override List<SubPacket> GetSpawnPackets()
{ {
List<SubPacket> subpackets = new List<SubPacket>(); List<SubPacket> subpackets = new List<SubPacket>();
subpackets.Add(CreateAddActorPacket(playerActorId, 0)); subpackets.Add(CreateAddActorPacket(0));
subpackets.Add(CreateSpeedPacket(playerActorId)); subpackets.Add(CreateSpeedPacket());
subpackets.Add(CreateSpawnPositonPacket(playerActorId, 0x1)); subpackets.Add(CreateSpawnPositonPacket(0x1));
subpackets.Add(CreateNamePacket(playerActorId)); subpackets.Add(CreateNamePacket());
subpackets.Add(CreateStatePacket(playerActorId)); subpackets.Add(CreateStatePacket());
subpackets.Add(CreateIsZoneingPacket(playerActorId)); subpackets.Add(CreateIsZoneingPacket());
subpackets.Add(CreateScriptBindPacket(playerActorId)); subpackets.Add(CreateScriptBindPacket());
return BasePacket.CreatePacket(subpackets, true, false); return subpackets;
} }
#region Actor Management #region Actor Management
public void AddActorToZone(Actor actor) public void AddActorToZone(Actor actor)
{ {
if (!mActorList.ContainsKey(actor.actorId)) lock (mActorList)
mActorList.Add(actor.actorId, actor); {
if (!mActorList.ContainsKey(actor.actorId))
mActorList.Add(actor.actorId, actor);
}
int gridX = (int)actor.positionX / boundingGridSize; int gridX = (int)actor.positionX / boundingGridSize;
int gridY = (int)actor.positionZ / boundingGridSize; int gridY = (int)actor.positionZ / boundingGridSize;
@ -125,7 +135,8 @@ namespace FFXIVClassic_Map_Server.Actors
public void RemoveActorFromZone(Actor actor) public void RemoveActorFromZone(Actor actor)
{ {
mActorList.Remove(actor.actorId); lock (mActorList)
mActorList.Remove(actor.actorId);
int gridX = (int)actor.positionX / boundingGridSize; int gridX = (int)actor.positionX / boundingGridSize;
int gridY = (int)actor.positionZ / boundingGridSize; int gridY = (int)actor.positionZ / boundingGridSize;
@ -214,11 +225,14 @@ namespace FFXIVClassic_Map_Server.Actors
List<Actor> result = new List<Actor>(); List<Actor> result = new List<Actor>();
for (int gx = gridX - checkDistance; gx <= gridX + checkDistance; gx++) lock (mActorBlock)
{ {
for (int gy = gridY - checkDistance; gy <= gridY + checkDistance; gy++) for (int gx = gridX - checkDistance; gx <= gridX + checkDistance; gx++)
{ {
result.AddRange(mActorBlock[gx, gy]); for (int gy = gridY - checkDistance; gy <= gridY + checkDistance; gy++)
{
result.AddRange(mActorBlock[gx, gy]);
}
} }
} }
@ -257,11 +271,14 @@ namespace FFXIVClassic_Map_Server.Actors
List<Actor> result = new List<Actor>(); List<Actor> result = new List<Actor>();
for (int gy = ((gridY - checkDistance) < 0 ? 0 : (gridY - checkDistance)); gy <= ((gridY + checkDistance) >= numYBlocks ? numYBlocks - 1 : (gridY + checkDistance)); gy++) lock (mActorBlock)
{ {
for (int gx = ((gridX - checkDistance) < 0 ? 0 : (gridX - checkDistance)); gx <= ((gridX + checkDistance) >= numXBlocks ? numXBlocks - 1 : (gridX + checkDistance)); gx++) for (int gy = ((gridY - checkDistance) < 0 ? 0 : (gridY - checkDistance)); gy <= ((gridY + checkDistance) >= numYBlocks ? numYBlocks - 1 : (gridY + checkDistance)); gy++)
{ {
result.AddRange(mActorBlock[gx, gy]); for (int gx = ((gridX - checkDistance) < 0 ? 0 : (gridX - checkDistance)); gx <= ((gridX + checkDistance) >= numXBlocks ? numXBlocks - 1 : (gridX + checkDistance)); gx++)
{
result.AddRange(mActorBlock[gx, gy]);
}
} }
} }
@ -280,46 +297,83 @@ namespace FFXIVClassic_Map_Server.Actors
#endregion #endregion
public Actor FindActorInZone(uint id) public Actor FindActorInArea(uint id)
{ {
if (!mActorList.ContainsKey(id)) lock (mActorList)
return null; {
return mActorList[id]; if (!mActorList.ContainsKey(id))
return null;
return mActorList[id];
}
} }
public Player FindPCInZone(string name) public Actor FindActorInZoneByUniqueID(string uniqueId)
{ {
foreach (Actor a in mActorList.Values) lock (mActorList)
{ {
if (a is Player) foreach (Actor a in mActorList.Values)
{ {
if (((Player)a).customDisplayName.ToLower().Equals(name.ToLower())) if (a is Npc)
return (Player)a; {
if (((Npc)a).GetUniqueId().ToLower().Equals(uniqueId))
return a;
}
} }
} }
return null; return null;
} }
public Player FindPCInZone(string name)
{
lock (mActorList)
{
foreach (Actor a in mActorList.Values)
{
if (a is Player)
{
if (((Player)a).customDisplayName.ToLower().Equals(name.ToLower()))
return (Player)a;
}
}
return null;
}
}
public Player FindPCInZone(uint id) public Player FindPCInZone(uint id)
{ {
if (!mActorList.ContainsKey(id)) lock (mActorList)
return null; {
return (Player)mActorList[id]; if (!mActorList.ContainsKey(id))
return null;
return (Player)mActorList[id];
}
} }
public void Clear() public void Clear()
{ {
//Clear All lock (mActorList)
mActorList.Clear();
for (int y = 0; y < numYBlocks; y++)
{ {
for (int x = 0; x < numXBlocks; x++) //Clear All
mActorList.Clear();
lock (mActorBlock)
{ {
mActorBlock[x, y].Clear(); for (int y = 0; y < numYBlocks; y++)
{
for (int x = 0; x < numXBlocks; x++)
{
mActorBlock[x, y].Clear();
}
}
} }
} }
} }
public void BroadcastPacketsAroundActor(Actor actor, List<SubPacket> packets)
{
foreach (SubPacket packet in packets)
BroadcastPacketAroundActor(actor, packet);
}
public void BroadcastPacketAroundActor(Actor actor, SubPacket packet) public void BroadcastPacketAroundActor(Actor actor, SubPacket packet)
{ {
if (isIsolated) if (isIsolated)
@ -333,7 +387,7 @@ namespace FFXIVClassic_Map_Server.Actors
if (isIsolated && packet.header.sourceId != a.actorId) if (isIsolated && packet.header.sourceId != a.actorId)
continue; continue;
SubPacket clonedPacket = new SubPacket(packet, actor.actorId); SubPacket clonedPacket = new SubPacket(packet, a.actorId);
Player p = (Player)a; Player p = (Player)a;
p.QueuePacket(clonedPacket); p.QueuePacket(clonedPacket);
} }
@ -347,31 +401,192 @@ namespace FFXIVClassic_Map_Server.Actors
if (actorClass == null) if (actorClass == null)
return; return;
Npc npc = new Npc(mActorList.Count + 1, actorClass, location.uniqueId, actorId, location.x, location.y, location.z, location.rot, location.state, location.animId, null); uint zoneId;
if (this is PrivateArea)
zoneId = ((PrivateArea)this).GetParentZone().actorId;
else
zoneId = actorId;
Npc npc = new Npc(mActorList.Count + 1, actorClass, location.uniqueId, this, location.x, location.y, location.z, location.rot, location.state, location.animId, null);
npc.LoadEventConditions(actorClass.eventConditions); npc.LoadEventConditions(actorClass.eventConditions);
AddActorToZone(npc); AddActorToZone(npc);
} }
public Npc SpawnActor(uint classId, string uniqueId, float x, float y, float z, float rot = 0, ushort state = 0, uint animId = 0)
{
ActorClass actorClass = Server.GetWorldManager().GetActorClass(classId);
if (actorClass == null)
return null;
uint zoneId;
if (this is PrivateArea)
zoneId = ((PrivateArea)this).GetParentZone().actorId;
else
zoneId = actorId;
Npc npc = new Npc(mActorList.Count + 1, actorClass, uniqueId, this, x, y, z, rot, state, animId, null);
npc.LoadEventConditions(actorClass.eventConditions);
AddActorToZone(npc);
return npc;
}
public Npc SpawnActor(uint classId, string uniqueId, float x, float y, float z, uint regionId, uint layoutId)
{
ActorClass actorClass = Server.GetWorldManager().GetActorClass(classId);
if (actorClass == null)
return null;
uint zoneId;
if (this is PrivateArea)
zoneId = ((PrivateArea)this).GetParentZone().actorId;
else
zoneId = actorId;
Npc npc = new Npc(mActorList.Count + 1, actorClass, uniqueId, this, x, y, z, 0, regionId, layoutId);
npc.LoadEventConditions(actorClass.eventConditions);
AddActorToZone(npc);
return npc;
}
public void DespawnActor(string uniqueId)
{
RemoveActorFromZone(FindActorInZoneByUniqueID(uniqueId));
}
public void DespawnActor(Actor actor)
{
RemoveActorFromZone(actor);
}
public Director GetWeatherDirector()
{
return mWeatherDirector;
}
public void ChangeWeather(ushort weather, ushort transitionTime, Player player, bool zoneWide = false) public void ChangeWeather(ushort weather, ushort transitionTime, Player player, bool zoneWide = false)
{ {
weatherNormal = weather; weatherNormal = weather;
if (player != null && !zoneWide) if (player != null && !zoneWide)
{ {
player.QueuePacket(BasePacket.CreatePacket(SetWeatherPacket.BuildPacket(player.actorId, weather, transitionTime), true, false)); player.QueuePacket(SetWeatherPacket.BuildPacket(player.actorId, weather, transitionTime));
} }
if (zoneWide) if (zoneWide)
{ {
foreach (var actor in mActorList) lock (mActorList)
{ {
if (actor.Value is Player) foreach (var actor in mActorList)
{ {
player = ((Player)actor.Value); if (actor.Value is Player)
player.QueuePacket(BasePacket.CreatePacket(SetWeatherPacket.BuildPacket(player.actorId, weather, transitionTime), true, false)); {
player = ((Player)actor.Value);
player.QueuePacket(SetWeatherPacket.BuildPacket(player.actorId, weather, transitionTime));
}
} }
} }
} }
} }
public Director CreateDirector(string path, bool hasContentGroup, params object[] args)
{
lock (directorLock)
{
Director director = new Director(directorIdCount, this, path, hasContentGroup, args);
currentDirectors.Add(director.actorId, director);
directorIdCount++;
return director;
}
}
public Director CreateGuildleveDirector(uint glid, byte difficulty, Player owner, params object[] args)
{
String directorScriptPath = "";
uint type = Server.GetGuildleveGamedata(glid).plateId;
if (glid == 10801 || glid == 12401 || glid == 11601)
directorScriptPath = "Guildleve/PrivateGLBattleTutorial";
else
{
switch (type)
{
case 20021:
directorScriptPath = "Guildleve/PrivateGLBattleSweepNormal";
break;
case 20022:
directorScriptPath = "Guildleve/PrivateGLBattleChaseNormal";
break;
case 20023:
directorScriptPath = "Guildleve/PrivateGLBattleOrbNormal";
break;
case 20024:
directorScriptPath = "Guildleve/PrivateGLBattleHuntNormal";
break;
case 20025:
directorScriptPath = "Guildleve/PrivateGLBattleGatherNormal";
break;
case 20026:
directorScriptPath = "Guildleve/PrivateGLBattleRoundNormal";
break;
case 20027:
directorScriptPath = "Guildleve/PrivateGLBattleSurviveNormal";
break;
case 20028:
directorScriptPath = "Guildleve/PrivateGLBattleDetectNormal";
break;
}
}
lock (directorLock)
{
GuildleveDirector director = new GuildleveDirector(directorIdCount, this, directorScriptPath, glid, difficulty, owner, args);
currentDirectors.Add(director.actorId, director);
directorIdCount++;
return director;
}
}
public void DeleteDirector(uint id)
{
lock (directorLock)
{
if (currentDirectors.ContainsKey(id))
{
if (!currentDirectors[id].IsDeleted())
currentDirectors[id].EndDirector();
currentDirectors.Remove(id);
}
}
}
public Director GetDirectorById(uint id)
{
if (currentDirectors.ContainsKey(id))
return currentDirectors[id];
return null;
}
public void Update(double deltaTime)
{
lock (mActorList)
{
foreach (Actor a in mActorList.Values)
a.Update(deltaTime);
}
}
} }
} }

View File

@ -1,4 +1,5 @@
using FFXIVClassic_Map_Server.packets; 
using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.Actors; using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.lua; using FFXIVClassic_Map_Server.lua;
using FFXIVClassic_Map_Server.packets.send.actor; using FFXIVClassic_Map_Server.packets.send.actor;
@ -14,14 +15,15 @@ namespace FFXIVClassic_Map_Server.actors.area
{ {
private Zone parentZone; private Zone parentZone;
private string privateAreaName; private string privateAreaName;
private uint privateAreaLevel; private uint privateAreaType;
public PrivateArea(Zone parent, uint id, string className, string privateAreaName, uint privateAreaLevel, ushort bgmDay, ushort bgmNight, ushort bgmBattle) public PrivateArea(Zone parent, uint id, string classPath, string privateAreaName, uint privateAreaType, ushort bgmDay, ushort bgmNight, ushort bgmBattle)
: base(id, parent.zoneName, parent.regionId, className, bgmDay, bgmNight, bgmBattle, parent.isIsolated, parent.isInn, parent.canRideChocobo, parent.canStealth, true) : base(id, parent.zoneName, parent.regionId, classPath, bgmDay, bgmNight, bgmBattle, parent.isIsolated, parent.isInn, parent.canRideChocobo, parent.canStealth, true)
{ {
this.parentZone = parent; this.parentZone = parent;
this.zoneName = parent.zoneName;
this.privateAreaName = privateAreaName; this.privateAreaName = privateAreaName;
this.privateAreaLevel = privateAreaLevel; this.privateAreaType = privateAreaType;
} }
public string GetPrivateAreaName() public string GetPrivateAreaName()
@ -29,9 +31,9 @@ namespace FFXIVClassic_Map_Server.actors.area
return privateAreaName; return privateAreaName;
} }
public uint GetPrivateAreaLevel() public uint GetPrivateAreaType()
{ {
return privateAreaLevel; return privateAreaType;
} }
public Zone GetParentZone() public Zone GetParentZone()
@ -39,18 +41,17 @@ namespace FFXIVClassic_Map_Server.actors.area
return parentZone; return parentZone;
} }
public override SubPacket CreateScriptBindPacket(uint playerActorId) public override SubPacket CreateScriptBindPacket()
{ {
List<LuaParam> lParams; List<LuaParam> lParams;
string path = className; string path = className;
if (className.ToLower().Contains("content")) string realClassName = className.Substring(className.LastIndexOf("/") + 1);
path = "Content/" + className;
lParams = LuaUtils.CreateLuaParamList("/Area/PrivateArea/" + path, false, true, zoneName, privateAreaName, 0x9E, canRideChocobo ? (byte)1 : (byte)0, canStealth, isInn, false, false, false, false, false, false); lParams = LuaUtils.CreateLuaParamList(classPath, false, true, zoneName, privateAreaName, privateAreaType, canRideChocobo ? (byte)1 : (byte)0, canStealth, isInn, false, false, false, false, false, false);
ActorInstantiatePacket.BuildPacket(actorId, playerActorId, actorName, className, lParams).DebugPrintSubPacket(); ActorInstantiatePacket.BuildPacket(actorId, actorName, realClassName, lParams).DebugPrintSubPacket();
return ActorInstantiatePacket.BuildPacket(actorId, playerActorId, actorName, className, lParams); return ActorInstantiatePacket.BuildPacket(actorId, actorName, realClassName, lParams);
} }

View File

@ -0,0 +1,57 @@
using FFXIVClassic_Map_Server.actors.director;
using FFXIVClassic_Map_Server.actors.group;
using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.lua;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_Map_Server.actors.area
{
class PrivateAreaContent : PrivateArea
{
private Director currentDirector;
private bool isContentFinished = false;
public static PrivateAreaContent CreateContentArea(String scriptPath)
{
return null;
}
public PrivateAreaContent(Zone parent, string classPath, string privateAreaName, uint privateAreaType, Director director, Player contentStarter) //TODO: Make it a list
: base(parent, parent.actorId, classPath, privateAreaName, privateAreaType, 0, 0, 0)
{
currentDirector = director;
LuaEngine.GetInstance().CallLuaFunction(contentStarter, this, "onCreate", false, currentDirector);
}
public Director GetContentDirector()
{
return currentDirector;
}
public void ContentFinished()
{
isContentFinished = true;
}
public void CheckDestroy()
{
if (isContentFinished)
{
bool noPlayersLeft = true;
foreach (Actor a in mActorList.Values)
{
if (a is Player)
noPlayersLeft = false;
}
if (noPlayersLeft)
GetParentZone().DeleteContentArea(this);
}
}
}
}

View File

@ -1,6 +1,6 @@
using FFXIVClassic_Map_Server; using FFXIVClassic_Map_Server;
using FFXIVClassic.Common; using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.packets;
using FFXIVClassic_Map_Server.actors.chara.npc; using FFXIVClassic_Map_Server.actors.chara.npc;
using FFXIVClassic_Map_Server.Actors; using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.lua; using FFXIVClassic_Map_Server.lua;
@ -10,15 +10,18 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using FFXIVClassic_Map_Server.actors.director;
namespace FFXIVClassic_Map_Server.actors.area namespace FFXIVClassic_Map_Server.actors.area
{ {
class Zone : Area class Zone : Area
{ {
Dictionary<string, Dictionary<uint, PrivateArea>> privateAreas = new Dictionary<string, Dictionary<uint, PrivateArea>>(); Dictionary<string, Dictionary<uint, PrivateArea>> privateAreas = new Dictionary<string, Dictionary<uint, PrivateArea>>();
Dictionary<string, List<PrivateAreaContent>> contentAreas = new Dictionary<string, List<PrivateAreaContent>>();
Object contentAreasLock = new Object();
public Zone(uint id, string zoneName, ushort regionId, string className, ushort bgmDay, ushort bgmNight, ushort bgmBattle, bool isIsolated, bool isInn, bool canRideChocobo, bool canStealth, bool isInstanceRaid) public Zone(uint id, string zoneName, ushort regionId, string classPath, ushort bgmDay, ushort bgmNight, ushort bgmBattle, bool isIsolated, bool isInn, bool canRideChocobo, bool canStealth, bool isInstanceRaid)
: base(id, zoneName, regionId, className, bgmDay, bgmNight, bgmBattle, isIsolated, isInn, canRideChocobo, canStealth, isInstanceRaid) : base(id, zoneName, regionId, classPath, bgmDay, bgmNight, bgmBattle, isIsolated, isInn, canRideChocobo, canStealth, isInstanceRaid)
{ {
} }
@ -26,11 +29,11 @@ namespace FFXIVClassic_Map_Server.actors.area
public void AddPrivateArea(PrivateArea pa) public void AddPrivateArea(PrivateArea pa)
{ {
if (privateAreas.ContainsKey(pa.GetPrivateAreaName())) if (privateAreas.ContainsKey(pa.GetPrivateAreaName()))
privateAreas[pa.GetPrivateAreaName()][0] = pa; privateAreas[pa.GetPrivateAreaName()][pa.GetPrivateAreaType()] = pa;
else else
{ {
privateAreas[pa.GetPrivateAreaName()] = new Dictionary<uint, PrivateArea>(); privateAreas[pa.GetPrivateAreaName()] = new Dictionary<uint, PrivateArea>();
privateAreas[pa.GetPrivateAreaName()][0] = pa; privateAreas[pa.GetPrivateAreaName()][pa.GetPrivateAreaType()] = pa;
} }
} }
@ -48,13 +51,13 @@ namespace FFXIVClassic_Map_Server.actors.area
return null; return null;
} }
public override SubPacket CreateScriptBindPacket(uint playerActorId) public override SubPacket CreateScriptBindPacket()
{ {
bool isEntranceDesion = false; bool isEntranceDesion = false;
List<LuaParam> lParams; List<LuaParam> lParams;
lParams = LuaUtils.CreateLuaParamList("/Area/Zone/" + className, false, true, zoneName, "", -1, canRideChocobo ? (byte)1 : (byte)0, canStealth, isInn, false, false, false, true, isInstanceRaid, isEntranceDesion); lParams = LuaUtils.CreateLuaParamList(classPath, false, true, zoneName, "", -1, canRideChocobo ? (byte)1 : (byte)0, canStealth, isInn, false, false, false, true, isInstanceRaid, isEntranceDesion);
return ActorInstantiatePacket.BuildPacket(actorId, playerActorId, actorName, className, lParams); return ActorInstantiatePacket.BuildPacket(actorId, actorName, className, lParams);
} }
public void AddSpawnLocation(SpawnLocation spawn) public void AddSpawnLocation(SpawnLocation spawn)
@ -92,5 +95,49 @@ namespace FFXIVClassic_Map_Server.actors.area
} }
} }
public Actor FindActorInZone(uint id)
{
if (!mActorList.ContainsKey(id))
{
foreach(Dictionary<uint, PrivateArea> paList in privateAreas.Values)
{
foreach(PrivateArea pa in paList.Values)
{
Actor actor = pa.FindActorInArea(id);
if (actor != null)
return actor;
}
}
return null;
}
else
return mActorList[id];
}
public PrivateAreaContent CreateContentArea(Player starterPlayer, string areaClassPath, string contentScript, string areaName, string directorName, params object[] args)
{
lock (contentAreasLock)
{
Director director = CreateDirector(directorName, true, args);
if (director == null)
return null;
if (!contentAreas.ContainsKey(areaName))
contentAreas.Add(areaName, new List<PrivateAreaContent>());
PrivateAreaContent contentArea = new PrivateAreaContent(this, classPath, areaName, 1, director, starterPlayer);
contentAreas[areaName].Add(contentArea);
return contentArea;
}
}
public void DeleteContentArea(PrivateAreaContent area)
{
if (contentAreas.ContainsKey(area.GetPrivateAreaName()))
{
contentAreas[area.GetPrivateAreaName()].Remove(area);
}
}
} }
} }

View File

@ -1,6 +1,9 @@
using FFXIVClassic_Map_Server.packets; 
using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.actors.group;
using FFXIVClassic_Map_Server.Actors.Chara; using FFXIVClassic_Map_Server.Actors.Chara;
using FFXIVClassic_Map_Server.packets.send.actor; using FFXIVClassic_Map_Server.packets.send.actor;
using FFXIVClassic_Map_Server.utils;
namespace FFXIVClassic_Map_Server.Actors namespace FFXIVClassic_Map_Server.Actors
{ {
@ -35,6 +38,8 @@ namespace FFXIVClassic_Map_Server.Actors
public const int L_INDEXFINGER = 26; public const int L_INDEXFINGER = 26;
public const int UNKNOWN = 27; public const int UNKNOWN = 27;
public bool isStatic = false;
public uint modelId; public uint modelId;
public uint[] appearanceIds = new uint[28]; public uint[] appearanceIds = new uint[28];
@ -48,6 +53,9 @@ namespace FFXIVClassic_Map_Server.Actors
public Work work = new Work(); public Work work = new Work();
public CharaWork charaWork = new CharaWork(); public CharaWork charaWork = new CharaWork();
public Group currentParty = null;
public ContentGroup currentContentGroup = null;
public Character(uint actorID) : base(actorID) public Character(uint actorID) : base(actorID)
{ {
//Init timer array to "notimer" //Init timer array to "notimer"
@ -55,30 +63,56 @@ namespace FFXIVClassic_Map_Server.Actors
charaWork.statusShownTime[i] = 0xFFFFFFFF; charaWork.statusShownTime[i] = 0xFFFFFFFF;
} }
public SubPacket CreateAppearancePacket(uint playerActorId) public SubPacket CreateAppearancePacket()
{ {
SetActorAppearancePacket setappearance = new SetActorAppearancePacket(modelId, appearanceIds); SetActorAppearancePacket setappearance = new SetActorAppearancePacket(modelId, appearanceIds);
return setappearance.BuildPacket(actorId, playerActorId); return setappearance.BuildPacket(actorId);
} }
public SubPacket CreateInitStatusPacket(uint playerActorId) public SubPacket CreateInitStatusPacket()
{ {
return (SetActorStatusAllPacket.BuildPacket(actorId, playerActorId, charaWork.status)); return (SetActorStatusAllPacket.BuildPacket(actorId, charaWork.status));
} }
public SubPacket CreateSetActorIconPacket(uint playerActorId) public SubPacket CreateSetActorIconPacket()
{ {
return SetActorIconPacket.BuildPacket(actorId, playerActorId, currentActorIcon); return SetActorIconPacket.BuildPacket(actorId, currentActorIcon);
} }
public SubPacket CreateIdleAnimationPacket(uint playerActorId) public SubPacket CreateIdleAnimationPacket()
{ {
return SetActorIdleAnimationPacket.BuildPacket(actorId, playerActorId, animationId); return SetActorSubStatPacket.BuildPacket(actorId, 0, 0, 0, 0, 0, 0, animationId);
} }
public void SetQuestGraphic(Player player, int graphicNum) public void SetQuestGraphic(Player player, int graphicNum)
{ {
player.QueuePacket(SetActorQuestGraphicPacket.BuildPacket(player.actorId, actorId, graphicNum)); player.QueuePacket(SetActorQuestGraphicPacket.BuildPacket(actorId, graphicNum));
}
public void SetCurrentContentGroup(ContentGroup group)
{
if (group != null)
charaWork.currentContentGroup = group.GetTypeId();
else
charaWork.currentContentGroup = 0;
currentContentGroup = group;
ActorPropertyPacketUtil propPacketUtil = new ActorPropertyPacketUtil("charaWork/currentContentGroup", this);
propPacketUtil.AddProperty("charaWork.currentContentGroup");
zone.BroadcastPacketsAroundActor(this, propPacketUtil.Done());
}
public void PlayAnimation(uint animId, bool onlySelf = false)
{
if (onlySelf)
{
if (this is Player)
((Player)this).QueuePacket(PlayAnimationOnActorPacket.BuildPacket(actorId, animId));
}
else
zone.BroadcastPacketAroundActor(this, PlayAnimationOnActorPacket.BuildPacket(actorId, animId));
} }
} }

View File

@ -8,6 +8,6 @@
public bool betacheck = false; public bool betacheck = false;
public bool[] event_achieve_aetheryte = new bool[512]; public bool[] event_achieve_aetheryte = new bool[128];
} }
} }

View File

@ -14,13 +14,21 @@ namespace FFXIVClassic_Map_Server.actors.chara.npc
public readonly uint propertyFlags; public readonly uint propertyFlags;
public readonly string eventConditions; public readonly string eventConditions;
public ActorClass(uint id, string classPath, uint nameId, uint propertyFlags, string eventConditions) public readonly ushort pushCommand;
public readonly ushort pushCommandSub;
public readonly byte pushCommandPriority;
public ActorClass(uint id, string classPath, uint nameId, uint propertyFlags, string eventConditions, ushort pushCommand, ushort pushCommandSub, byte pushCommandPriority)
{ {
this.actorClassId = id; this.actorClassId = id;
this.classPath = classPath; this.classPath = classPath;
this.displayNameId = nameId; this.displayNameId = nameId;
this.propertyFlags = propertyFlags; this.propertyFlags = propertyFlags;
this.eventConditions = eventConditions; this.eventConditions = eventConditions;
this.pushCommand = pushCommand;
this.pushCommandSub = pushCommandSub;
this.pushCommandPriority = pushCommandPriority;
} }
} }
} }

View File

@ -1,10 +1,10 @@
using FFXIVClassic.Common; using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.actors; using FFXIVClassic_Map_Server.actors;
using FFXIVClassic_Map_Server.actors.area;
using FFXIVClassic_Map_Server.actors.chara.npc; using FFXIVClassic_Map_Server.actors.chara.npc;
using FFXIVClassic_Map_Server.Actors.Chara; using FFXIVClassic_Map_Server.Actors.Chara;
using FFXIVClassic_Map_Server.dataobjects; using FFXIVClassic_Map_Server.dataobjects;
using FFXIVClassic_Map_Server.lua; using FFXIVClassic_Map_Server.lua;
using FFXIVClassic_Map_Server.packets;
using FFXIVClassic_Map_Server.packets.receive.events; using FFXIVClassic_Map_Server.packets.receive.events;
using FFXIVClassic_Map_Server.packets.send.actor; using FFXIVClassic_Map_Server.packets.send.actor;
using FFXIVClassic_Map_Server.utils; using FFXIVClassic_Map_Server.utils;
@ -25,15 +25,19 @@ namespace FFXIVClassic_Map_Server.Actors
private uint actorClassId; private uint actorClassId;
private string uniqueIdentifier; private string uniqueIdentifier;
private bool isMapObj = false;
private uint layout, instance;
public NpcWork npcWork = new NpcWork(); public NpcWork npcWork = new NpcWork();
public Npc(int actorNumber, ActorClass actorClass, string uniqueId, uint zoneId, float posX, float posY, float posZ, float rot, ushort actorState, uint animationId, string customDisplayName) public Npc(int actorNumber, ActorClass actorClass, string uniqueId, Area spawnedArea, float posX, float posY, float posZ, float rot, ushort actorState, uint animationId, string customDisplayName)
: base((4 << 28 | zoneId << 19 | (uint)actorNumber)) : base((4 << 28 | spawnedArea.actorId << 19 | (uint)actorNumber))
{ {
this.positionX = posX; this.positionX = posX;
this.positionY = posY; this.positionY = posY;
this.positionZ = posZ; this.positionZ = posZ;
this.rotation = rot; this.rotation = rot;
this.currentMainState = actorState;
this.animationId = animationId; this.animationId = animationId;
this.displayNameId = actorClass.displayNameId; this.displayNameId = actorClass.displayNameId;
@ -41,8 +45,8 @@ namespace FFXIVClassic_Map_Server.Actors
this.uniqueIdentifier = uniqueId; this.uniqueIdentifier = uniqueId;
this.zoneId = zoneId; this.zoneId = spawnedArea.actorId;
this.zone = Server.GetWorldManager().GetZone(zoneId); this.zone = spawnedArea;
this.actorClassId = actorClass.actorClassId; this.actorClassId = actorClass.actorClassId;
@ -63,38 +67,93 @@ namespace FFXIVClassic_Map_Server.Actors
for (int i = 0; i < 32; i++ ) for (int i = 0; i < 32; i++ )
charaWork.property[i] = (byte)(((int)actorClass.propertyFlags >> i) & 1); charaWork.property[i] = (byte)(((int)actorClass.propertyFlags >> i) & 1);
if (className.Equals("JellyfishScenarioLimsaLv00")) npcWork.pushCommand = actorClass.pushCommand;
{ npcWork.pushCommandSub = actorClass.pushCommandSub;
charaWork.property[2] = 1; npcWork.pushCommandPriority = actorClass.pushCommandPriority;
npcWork.hateType = 1;
}
npcWork.pushCommand = 0x271D; if (actorClassId == 1080078 || actorClassId == 1080079 || actorClassId == 1080080 || (actorClassId >= 1080123 && actorClassId <= 1080135) || (actorClassId >= 5000001 && actorClassId <= 5000090) || (actorClassId >= 5900001 && actorClassId <= 5900038))
npcWork.pushCommandPriority = 1; {
isMapObj = true;
List<LuaParam> lParams = LuaEngine.GetInstance().CallLuaFunctionForReturn(null, this, "init", false);
if (lParams == null || lParams.Count < 6)
isMapObj = false;
else
{
layout = (uint)(Int32)lParams[4].value;
instance = (uint)(Int32)lParams[5].value;
isStatic = true;
}
}
GenerateActorName((int)actorNumber); GenerateActorName((int)actorNumber);
} }
public SubPacket CreateAddActorPacket(uint playerActorId) public Npc(int actorNumber, ActorClass actorClass, string uniqueId, Area spawnedArea, float posX, float posY, float posZ, float rot, uint layout, uint instance)
: base((4 << 28 | spawnedArea.actorId << 19 | (uint)actorNumber))
{ {
return AddActorPacket.BuildPacket(actorId, playerActorId, 8); this.positionX = posX;
this.positionY = posY;
this.positionZ = posZ;
this.rotation = rot;
this.currentMainState = 0;
this.animationId = 0;
this.displayNameId = actorClass.displayNameId;
this.uniqueIdentifier = uniqueId;
this.zoneId = spawnedArea.actorId;
this.zone = spawnedArea;
this.actorClassId = actorClass.actorClassId;
LoadNpcAppearance(actorClass.actorClassId);
this.classPath = actorClass.classPath;
className = classPath.Substring(classPath.LastIndexOf("/") + 1);
for (int i = 0; i < 32; i++)
charaWork.property[i] = (byte)(((int)actorClass.propertyFlags >> i) & 1);
npcWork.pushCommand = actorClass.pushCommand;
npcWork.pushCommandSub = actorClass.pushCommandSub;
npcWork.pushCommandPriority = actorClass.pushCommandPriority;
this.isMapObj = true;
this.layout = layout;
this.instance = instance;
GenerateActorName((int)actorNumber);
}
public SubPacket CreateAddActorPacket()
{
return AddActorPacket.BuildPacket(actorId, 8);
} }
// actorClassId, [], [], numBattleCommon, [battleCommon], numEventCommon, [eventCommon], args for either initForBattle/initForEvent // actorClassId, [], [], numBattleCommon, [battleCommon], numEventCommon, [eventCommon], args for either initForBattle/initForEvent
public override SubPacket CreateScriptBindPacket(uint playerActorId) public override SubPacket CreateScriptBindPacket(Player player)
{ {
List<LuaParam> lParams; List<LuaParam> lParams;
Player player = Server.GetWorldManager().GetPCInWorld(playerActorId); lParams = LuaEngine.GetInstance().CallLuaFunctionForReturn(player, this, "init", false);
lParams = DoActorInit(player);
if (lParams != null && lParams.Count >= 3 && lParams[2].typeID == 0 && (int)lParams[2].value == 0)
isStatic = true;
else
{
// charaWork.property[2] = 1;
// npcWork.hateType = 1;
}
if (lParams == null) if (lParams == null)
{ {
string classPathFake = "/Chara/Npc/Populace/PopulaceStandard"; string classPathFake = "/Chara/Npc/Populace/PopulaceStandard";
string classNameFake = "PopulaceStandard"; string classNameFake = "PopulaceStandard";
lParams = LuaUtils.CreateLuaParamList(classPathFake, false, false, false, false, false, 0xF47F6, false, false, 0, 0); lParams = LuaUtils.CreateLuaParamList(classPathFake, false, false, false, false, false, 0xF47F6, false, false, 0, 0);
//ActorInstantiatePacket.BuildPacket(actorId, playerActorId, actorName, classNameFake, lParams).DebugPrintSubPacket(); isStatic = true;
return ActorInstantiatePacket.BuildPacket(actorId, playerActorId, actorName, classNameFake, lParams); //ActorInstantiatePacket.BuildPacket(actorId, actorName, classNameFake, lParams).DebugPrintSubPacket();
return ActorInstantiatePacket.BuildPacket(actorId, actorName, classNameFake, lParams);
} }
else else
{ {
@ -107,32 +166,40 @@ namespace FFXIVClassic_Map_Server.Actors
lParams.Insert(6, new LuaParam(0, (int)actorClassId)); lParams.Insert(6, new LuaParam(0, (int)actorClassId));
} }
//ActorInstantiatePacket.BuildPacket(actorId, playerActorId, actorName, className, lParams).DebugPrintSubPacket(); //ActorInstantiatePacket.BuildPacket(actorId, actorName, className, lParams).DebugPrintSubPacket();
return ActorInstantiatePacket.BuildPacket(actorId, playerActorId, actorName, className, lParams); return ActorInstantiatePacket.BuildPacket(actorId, actorName, className, lParams);
} }
public override BasePacket GetSpawnPackets(uint playerActorId, uint spawnType) public override List<SubPacket> GetSpawnPackets(Player player, ushort spawnType)
{ {
List<SubPacket> subpackets = new List<SubPacket>(); List<SubPacket> subpackets = new List<SubPacket>();
subpackets.Add(CreateAddActorPacket(playerActorId)); subpackets.Add(CreateAddActorPacket());
subpackets.AddRange(GetEventConditionPackets(playerActorId)); subpackets.AddRange(GetEventConditionPackets());
subpackets.Add(CreateSpeedPacket(playerActorId)); subpackets.Add(CreateSpeedPacket());
subpackets.Add(CreateSpawnPositonPacket(playerActorId, 0x0)); subpackets.Add(CreateSpawnPositonPacket(0x0));
subpackets.Add(CreateAppearancePacket(playerActorId));
subpackets.Add(CreateNamePacket(playerActorId));
subpackets.Add(CreateStatePacket(playerActorId));
subpackets.Add(CreateIdleAnimationPacket(playerActorId));
subpackets.Add(CreateInitStatusPacket(playerActorId));
subpackets.Add(CreateSetActorIconPacket(playerActorId));
subpackets.Add(CreateIsZoneingPacket(playerActorId));
subpackets.Add(CreateScriptBindPacket(playerActorId));
return BasePacket.CreatePacket(subpackets, true, false); if (isMapObj)
subpackets.Add(SetActorBGPropertiesPacket.BuildPacket(actorId, instance, layout));
else
subpackets.Add(CreateAppearancePacket());
subpackets.Add(CreateNamePacket());
subpackets.Add(CreateStatePacket());
subpackets.Add(CreateIdleAnimationPacket());
subpackets.Add(CreateInitStatusPacket());
subpackets.Add(CreateSetActorIconPacket());
subpackets.Add(CreateIsZoneingPacket());
subpackets.Add(CreateScriptBindPacket(player));
return subpackets;
} }
public override BasePacket GetInitPackets(uint playerActorId) public override List<SubPacket> GetInitPackets()
{ {
ActorPropertyPacketUtil propPacketUtil = new ActorPropertyPacketUtil("/_init", this, playerActorId); ActorPropertyPacketUtil propPacketUtil = new ActorPropertyPacketUtil("/_init", this);
//Potential
propPacketUtil.AddProperty("charaWork.battleSave.potencial");
//Properties //Properties
for (int i = 0; i < charaWork.property.Length; i++) for (int i = 0; i < charaWork.property.Length; i++)
@ -174,10 +241,16 @@ namespace FFXIVClassic_Map_Server.Actors
} }
propPacketUtil.AddProperty("npcWork.hateType"); propPacketUtil.AddProperty("npcWork.hateType");
propPacketUtil.AddProperty("npcWork.pushCommand");
propPacketUtil.AddProperty("npcWork.pushCommandPriority");
return BasePacket.CreatePacket(propPacketUtil.Done(), true, false); if (npcWork.pushCommand != 0)
{
propPacketUtil.AddProperty("npcWork.pushCommand");
if (npcWork.pushCommandSub != 0)
propPacketUtil.AddProperty("npcWork.pushCommandSub");
propPacketUtil.AddProperty("npcWork.pushCommandPriority");
}
return propPacketUtil.Done();
} }
public string GetUniqueId() public string GetUniqueId()
@ -190,6 +263,12 @@ namespace FFXIVClassic_Map_Server.Actors
return actorClassId; return actorClassId;
} }
public void ChangeNpcAppearance(uint id)
{
LoadNpcAppearance(id);
zone.BroadcastPacketAroundActor(this, CreateAppearancePacket());
}
public void LoadNpcAppearance(uint id) public void LoadNpcAppearance(uint id)
{ {
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))) 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)))
@ -298,118 +377,33 @@ namespace FFXIVClassic_Map_Server.Actors
this.eventConditions = conditions; this.eventConditions = conditions;
} }
public List<LuaParam> DoActorInit(Player player) public void DoOnActorSpawn(Player player)
{ {
LuaScript parent = null, child = null; LuaEngine.GetInstance().CallLuaFunction(player, this, "onSpawn", true);
if (File.Exists("./scripts/base/" + classPath + ".lua"))
parent = LuaEngine.LoadScript("./scripts/base/" + classPath + ".lua");
if (File.Exists(String.Format("./scripts/unique/{0}/{1}/{2}.lua", zone.zoneName, className, uniqueIdentifier)))
child = LuaEngine.LoadScript(String.Format("./scripts/unique/{0}/{1}/{2}.lua", zone.zoneName, className, uniqueIdentifier));
if (parent == null && child == null)
{
LuaEngine.SendError(player, String.Format("ERROR: Could not find script for actor {0}.", GetName()));
return null;
}
DynValue result;
if (child != null && child.Globals["init"] != null)
result = child.Call(child.Globals["init"], this);
else if (parent != null && parent.Globals["init"] != null)
result = parent.Call(parent.Globals["init"], this);
else
return null;
List<LuaParam> lparams = LuaUtils.CreateLuaParamList(result);
return lparams;
} }
public Coroutine GetEventStartCoroutine(Player player) public void PlayMapObjAnimation(Player player, string animationName)
{ {
LuaScript parent = null, child = null; player.QueuePacket(PlayBGAnimation.BuildPacket(actorId, animationName));
if (File.Exists("./scripts/base/" + classPath + ".lua"))
parent = LuaEngine.LoadScript("./scripts/base/" + classPath + ".lua");
if (File.Exists(String.Format("./scripts/unique/{0}/{1}/{2}.lua", zone.zoneName, className, uniqueIdentifier)))
child = LuaEngine.LoadScript(String.Format("./scripts/unique/{0}/{1}/{2}.lua", zone.zoneName, className, uniqueIdentifier));
if (parent == null && child == null)
{
LuaEngine.SendError(player, String.Format("ERROR: Could not find script for actor {0}.", GetName()));
return null;
}
//Run Script
Coroutine coroutine;
if (child != null && !child.Globals.Get("onEventStarted").IsNil())
coroutine = child.CreateCoroutine(child.Globals["onEventStarted"]).Coroutine;
else if (parent.Globals.Get("onEventStarted") != null && !parent.Globals.Get("onEventStarted").IsNil())
coroutine = parent.CreateCoroutine(parent.Globals["onEventStarted"]).Coroutine;
else
return null;
return coroutine;
} }
public void DoEventUpdate(Player player, EventUpdatePacket eventUpdate) public void Despawn()
{ {
LuaScript parent = null, child = null; zone.DespawnActor(this);
if (File.Exists("./scripts/base/" + classPath + ".lua"))
parent = LuaEngine.LoadScript("./scripts/base/" + classPath + ".lua");
if (File.Exists(String.Format("./scripts/unique/{0}/{1}/{2}.lua", zone.zoneName, className, uniqueIdentifier)))
child = LuaEngine.LoadScript(String.Format("./scripts/unique/{0}/{1}/{2}.lua", zone.zoneName, className, uniqueIdentifier));
if (parent == null && child == null)
{
//LuaEngine.SendError(player, String.Format("ERROR: Could not find script for actor {0}.", GetName()));
return;
}
//Have to do this to combine LuaParams
List<Object> objects = new List<Object>();
objects.Add(player);
objects.Add(this);
objects.Add(eventUpdate.val2);
objects.AddRange(LuaUtils.CreateLuaParamObjectList(eventUpdate.luaParams));
//Run Script
DynValue result;
if (child != null && !child.Globals.Get("onEventUpdate").IsNil())
result = child.Call(child.Globals["onEventUpdate"], objects.ToArray());
else if (!parent.Globals.Get("onEventUpdate").IsNil())
result = parent.Call(parent.Globals["onEventUpdate"], objects.ToArray());
else
return;
} }
internal void DoOnActorSpawn(Player player) public void Update(double deltaTime)
{ {
LuaScript parent = null, child = null; LuaEngine.GetInstance().CallLuaFunction(null, this, "onUpdate", true, deltaTime);
if (File.Exists("./scripts/base/" + classPath + ".lua"))
parent = LuaEngine.LoadScript("./scripts/base/" + classPath + ".lua");
if (File.Exists(String.Format("./scripts/unique/{0}/{1}/{2}.lua", zone.zoneName, className, uniqueIdentifier)))
child = LuaEngine.LoadScript(String.Format("./scripts/unique/{0}/{1}/{2}.lua", zone.zoneName, className, uniqueIdentifier));
if (parent == null && child == null)
{
//LuaEngine.SendError(player, String.Format("ERROR: Could not find script for actor {0}.", GetName()));
return;
}
//Run Script
if (child != null && child.Globals["onSpawn"] != null)
child.Call(child.Globals["onSpawn"], player, this);
else if (parent != null && parent.Globals["onSpawn"] != null)
parent.Call(parent.Globals["onSpawn"], player, this);
else
return;
} }
//A party member list packet came, set the party
/* public void SetParty(MonsterPartyGroup group)
{
if (group is MonsterPartyGroup)
currentParty = group;
}
*/
} }
} }

View File

@ -2,9 +2,9 @@
{ {
class NpcWork class NpcWork
{ {
public short pushCommand; public ushort pushCommand;
public int pushCommandSub; public int pushCommandSub;
public byte pushCommandPriority; public byte pushCommandPriority;
public byte hateType; public byte hateType = 1;
} }
} }

View File

@ -1,7 +1,6 @@
using FFXIVClassic_Map_Server.Actors; using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.dataobjects; using FFXIVClassic_Map_Server.dataobjects;
using FFXIVClassic_Map_Server.packets.send.actor.inventory; using FFXIVClassic_Map_Server.packets.send.actor.inventory;
using FFXIVClassic_Map_Server.packets.send.Actor.inventory;
using System.Collections.Generic; using System.Collections.Generic;
namespace FFXIVClassic_Map_Server.actors.chara.player namespace FFXIVClassic_Map_Server.actors.chara.player
@ -64,24 +63,24 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
} }
} }
toPlayer.QueuePacket(InventorySetBeginPacket.BuildPacket(owner.actorId, toPlayer.actorId, 0x23, Inventory.EQUIPMENT_OTHERPLAYER)); toPlayer.QueuePacket(InventorySetBeginPacket.BuildPacket(owner.actorId, 0x23, Inventory.EQUIPMENT_OTHERPLAYER));
int currentIndex = 0; int currentIndex = 0;
while (true) while (true)
{ {
if (items.Count - currentIndex >= 16) if (items.Count - currentIndex >= 16)
toPlayer.QueuePacket(InventoryListX16Packet.BuildPacket(owner.actorId, toPlayer.actorId, items, ref currentIndex)); toPlayer.QueuePacket(InventoryListX16Packet.BuildPacket(owner.actorId, items, ref currentIndex));
else if (items.Count - currentIndex > 1) else if (items.Count - currentIndex > 1)
toPlayer.QueuePacket(InventoryListX08Packet.BuildPacket(owner.actorId, toPlayer.actorId, items, ref currentIndex)); toPlayer.QueuePacket(InventoryListX08Packet.BuildPacket(owner.actorId, items, ref currentIndex));
else if (items.Count - currentIndex == 1) else if (items.Count - currentIndex == 1)
{ {
toPlayer.QueuePacket(InventoryListX01Packet.BuildPacket(owner.actorId, toPlayer.actorId, items[currentIndex])); toPlayer.QueuePacket(InventoryListX01Packet.BuildPacket(owner.actorId, items[currentIndex]));
currentIndex++; currentIndex++;
} }
else else
break; break;
} }
toPlayer.QueuePacket(InventorySetEndPacket.BuildPacket(owner.actorId, toPlayer.actorId)); toPlayer.QueuePacket(InventorySetEndPacket.BuildPacket(owner.actorId));
} }
public void SendFullEquipment(bool DoClear) public void SendFullEquipment(bool DoClear)

View File

@ -1,8 +1,8 @@
using FFXIVClassic_Map_Server.packets; 
using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.Actors; using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.dataobjects; using FFXIVClassic_Map_Server.dataobjects;
using FFXIVClassic_Map_Server.packets.send.actor.inventory; using FFXIVClassic_Map_Server.packets.send.actor.inventory;
using FFXIVClassic_Map_Server.packets.send.Actor.inventory;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -102,7 +102,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
if (!IsSpaceForAdd(itemId, quantity)) if (!IsSpaceForAdd(itemId, quantity))
return false; return false;
Item gItem = Server.GetItemGamedata(itemId); ItemData gItem = Server.GetItemGamedata(itemId);
List<ushort> slotsToUpdate = new List<ushort>(); List<ushort> slotsToUpdate = new List<ushort>();
List<SubPacket> addItemPackets = new List<SubPacket>(); List<SubPacket> addItemPackets = new List<SubPacket>();
@ -185,7 +185,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
//New item that spilled over //New item that spilled over
for (int i = 0; i < itemId.Length; i++) for (int i = 0; i < itemId.Length; i++)
{ {
Item gItem = Server.GetItemGamedata(itemId[i]); ItemData gItem = Server.GetItemGamedata(itemId[i]);
InventoryItem addedItem = Database.AddItem(owner, itemId[i], 1, (byte)1, gItem.isExclusive ? (byte)0x3 : (byte)0x0, gItem.durability, inventoryCode); InventoryItem addedItem = Database.AddItem(owner, itemId[i], 1, (byte)1, gItem.isExclusive ? (byte)0x3 : (byte)0x0, gItem.durability, inventoryCode);
list.Add(addedItem); list.Add(addedItem);
} }
@ -272,7 +272,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
owner.QueuePacket(InventoryEndChangePacket.BuildPacket(owner.actorId)); owner.QueuePacket(InventoryEndChangePacket.BuildPacket(owner.actorId));
} }
public void RemoveItem(ulong itemDBId) public void RemoveItemByUniqueId(ulong itemDBId)
{ {
ushort slot = 0; ushort slot = 0;
InventoryItem toDelete = null; InventoryItem toDelete = null;
@ -314,7 +314,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
} }
public void RemoveItem(ushort slot) public void RemoveItemAtSlot(ushort slot)
{ {
if (slot >= list.Count) if (slot >= list.Count)
return; return;
@ -467,7 +467,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
for (int i = 0; i < list.Count; i++) for (int i = 0; i < list.Count; i++)
{ {
InventoryItem item = list[i]; InventoryItem item = list[i];
Item gItem = Server.GetItemGamedata(item.itemId); ItemData gItem = Server.GetItemGamedata(item.itemId);
if (item.itemId == itemId && item.quantity < gItem.maxStack) if (item.itemId == itemId && item.quantity < gItem.maxStack)
{ {
quantityCount -= (gItem.maxStack - item.quantity); quantityCount -= (gItem.maxStack - item.quantity);

File diff suppressed because it is too large Load Diff

View File

@ -18,8 +18,8 @@
public bool isContentsCommand; public bool isContentsCommand;
public int castCommandClient; public uint castCommandClient;
public int castEndClient; public uint castEndClient;
public int[] comboNextCommandId = new int[2]; public int[] comboNextCommandId = new int[2];
public float comboCostBonusRate; public float comboCostBonusRate;

View File

@ -1,4 +1,4 @@
using FFXIVClassic_Map_Server.packets; using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.lua; using FFXIVClassic_Map_Server.lua;
using FFXIVClassic_Map_Server.packets.send.actor; using FFXIVClassic_Map_Server.packets.send.actor;
using System.Collections.Generic; using System.Collections.Generic;
@ -18,24 +18,24 @@ namespace FFXIVClassic_Map_Server.Actors
this.className = "Debug"; this.className = "Debug";
} }
public override SubPacket CreateScriptBindPacket(uint playerActorId) public override SubPacket CreateScriptBindPacket()
{ {
List<LuaParam> lParams; List<LuaParam> lParams;
lParams = LuaUtils.CreateLuaParamList("/System/Debug.prog", false, false, false, false, true, 0xC51F, true, true); lParams = LuaUtils.CreateLuaParamList("/System/Debug.prog", false, false, false, false, true, 0xC51F, true, true);
return ActorInstantiatePacket.BuildPacket(actorId, playerActorId, actorName, className, lParams); return ActorInstantiatePacket.BuildPacket(actorId, actorName, className, lParams);
} }
public override BasePacket GetSpawnPackets(uint playerActorId) public override List<SubPacket> GetSpawnPackets()
{ {
List<SubPacket> subpackets = new List<SubPacket>(); List<SubPacket> subpackets = new List<SubPacket>();
subpackets.Add(CreateAddActorPacket(playerActorId, 0)); subpackets.Add(CreateAddActorPacket(0));
subpackets.Add(CreateSpeedPacket(playerActorId)); subpackets.Add(CreateSpeedPacket());
subpackets.Add(CreateSpawnPositonPacket(playerActorId, 0x1)); subpackets.Add(CreateSpawnPositonPacket(0x1));
subpackets.Add(CreateNamePacket(playerActorId)); subpackets.Add(CreateNamePacket());
subpackets.Add(CreateStatePacket(playerActorId)); subpackets.Add(CreateStatePacket());
subpackets.Add(CreateIsZoneingPacket(playerActorId)); subpackets.Add(CreateIsZoneingPacket());
subpackets.Add(CreateScriptBindPacket(playerActorId)); subpackets.Add(CreateScriptBindPacket());
return BasePacket.CreatePacket(subpackets, true, false); return subpackets;
} }
} }

View File

@ -1,50 +1,321 @@
using FFXIVClassic_Map_Server.packets; 
using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.actors.area;
using FFXIVClassic_Map_Server.actors.group;
using FFXIVClassic_Map_Server.Actors; using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.lua; using FFXIVClassic_Map_Server.lua;
using FFXIVClassic_Map_Server.packets.send.actor; using FFXIVClassic_Map_Server.packets.send.actor;
using MoonSharp.Interpreter;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
namespace FFXIVClassic_Map_Server.actors.director namespace FFXIVClassic_Map_Server.actors.director
{ {
class Director : Actor class Director : Actor
{ {
Player owner; private uint directorId;
private string directorScriptPath;
private List<Actor> members = new List<Actor>();
protected ContentGroup contentGroup;
private bool isCreated = false;
private bool isDeleted = false;
private bool isDeleting = false;
public Director(Player owner, uint id) : base(id) private Script directorScript;
private Coroutine currentCoroutine;
public Director(uint id, Area zone, string directorPath, bool hasContentGroup, params object[] args)
: base((6 << 28 | zone.actorId << 19 | (uint)id))
{ {
this.owner = owner; directorId = id;
this.zone = zone;
this.zoneId = zone.actorId;
directorScriptPath = directorPath;
LoadLuaScript();
if (hasContentGroup)
contentGroup = Server.GetWorldManager().CreateContentGroup(this, GetMembers());
eventConditions = new EventList();
eventConditions.noticeEventConditions = new List<EventList.NoticeEventCondition>();
eventConditions.noticeEventConditions.Add(new EventList.NoticeEventCondition("noticeEvent", 0xE,0x0));
eventConditions.noticeEventConditions.Add(new EventList.NoticeEventCondition("noticeRequest", 0x0, 0x1));
eventConditions.noticeEventConditions.Add(new EventList.NoticeEventCondition("reqForChild", 0x0, 0x1));
} }
public virtual BasePacket GetSpawnPackets(uint playerActorId, uint spawnType) public override SubPacket CreateScriptBindPacket()
{
List<LuaParam> actualLParams = new List<LuaParam>();
actualLParams.Insert(0, new LuaParam(2, classPath));
actualLParams.Insert(1, new LuaParam(4, 4));
actualLParams.Insert(2, new LuaParam(4, 4));
actualLParams.Insert(3, new LuaParam(4, 4));
actualLParams.Insert(4, new LuaParam(4, 4));
actualLParams.Insert(5, new LuaParam(4, 4));
List<LuaParam> lparams = LuaEngine.GetInstance().CallLuaFunctionForReturn(null, this, "init", false);
for (int i = 1; i < lparams.Count; i++)
actualLParams.Add(lparams[i]);
return ActorInstantiatePacket.BuildPacket(actorId, actorName, className, actualLParams);
}
public override List<SubPacket> GetSpawnPackets(ushort spawnType = 1)
{ {
List<SubPacket> subpackets = new List<SubPacket>(); List<SubPacket> subpackets = new List<SubPacket>();
subpackets.Add(CreateAddActorPacket(playerActorId, 0)); subpackets.Add(CreateAddActorPacket(0));
subpackets.AddRange(GetEventConditionPackets(playerActorId)); subpackets.AddRange(GetEventConditionPackets());
subpackets.Add(CreateSpeedPacket(playerActorId)); subpackets.Add(CreateSpeedPacket());
subpackets.Add(CreateSpawnPositonPacket(playerActorId, 0)); subpackets.Add(CreateSpawnPositonPacket(0));
subpackets.Add(CreateNamePacket(playerActorId)); subpackets.Add(CreateNamePacket());
subpackets.Add(CreateStatePacket(playerActorId)); subpackets.Add(CreateStatePacket());
subpackets.Add(CreateIsZoneingPacket(playerActorId)); subpackets.Add(CreateIsZoneingPacket());
subpackets.Add(CreateScriptBindPacket(playerActorId)); subpackets.Add(CreateScriptBindPacket());
return BasePacket.CreatePacket(subpackets, true, false); return subpackets;
} }
public override BasePacket GetInitPackets(uint playerActorId) public override List<SubPacket> GetInitPackets()
{ {
List<SubPacket> subpackets = new List<SubPacket>();
SetActorPropetyPacket initProperties = new SetActorPropetyPacket("/_init"); SetActorPropetyPacket initProperties = new SetActorPropetyPacket("/_init");
initProperties.AddTarget(); initProperties.AddTarget();
return BasePacket.CreatePacket(initProperties.BuildPacket(playerActorId, actorId), true, false); subpackets.Add(initProperties.BuildPacket(actorId));
return subpackets;
} }
public void OnTalked(Npc npc) public void OnTalkEvent(Player player, Npc npc)
{ {
LuaEngine.DoDirectorOnTalked(this, owner, npc); LuaEngine.GetInstance().CallLuaFunction(player, this, "onTalkEvent", false, npc);
} }
public void OnCommand(Command command) public void OnCommandEvent(Player player, Command command)
{ {
LuaEngine.DoDirectorOnCommand(this, owner, command); LuaEngine.GetInstance().CallLuaFunction(player, this, "onCommandEvent", false, command);
} }
public void StartDirector(bool spawnImmediate, params object[] args)
{
object[] args2 = new object[args.Length + 1];
args2[0] = this;
Array.Copy(args, 0, args2, 1, args.Length);
List<LuaParam> lparams = CallLuaScript("init", args2);
if (lparams.Count >= 1 && lparams[0].value is string)
{
classPath = (string)lparams[0].value;
className = classPath.Substring(classPath.LastIndexOf("/") + 1);
GenerateActorName((int)directorId);
isCreated = true;
}
if (isCreated && spawnImmediate)
{
if (contentGroup != null)
contentGroup.Start();
foreach (Player p in GetPlayerMembers())
{
p.QueuePackets(GetSpawnPackets());
p.QueuePackets(GetInitPackets());
}
}
if (this is GuildleveDirector)
{
((GuildleveDirector)this).LoadGuildleve();
}
StartCoroutine("main", this);
}
public void StartContentGroup()
{
if (contentGroup != null)
contentGroup.Start();
}
public void EndDirector()
{
isDeleting = true;
if (contentGroup != null)
contentGroup.DeleteGroup();
if (this is GuildleveDirector)
((GuildleveDirector)this).EndGuildleveDirector();
List<Actor> players = GetPlayerMembers();
foreach (Actor player in players)
((Player)player).RemoveDirector(this);
members.Clear();
isDeleted = true;
Server.GetWorldManager().GetZone(zoneId).DeleteDirector(actorId);
}
public void AddMember(Actor actor)
{
if (!members.Contains(actor))
{
members.Add(actor);
if (contentGroup != null)
contentGroup.AddMember(actor);
}
}
public void RemoveMember(Actor actor)
{
if (members.Contains(actor))
members.Remove(actor);
if (contentGroup != null)
contentGroup.RemoveMember(actor.actorId);
if (GetPlayerMembers().Count == 0 && !isDeleting)
EndDirector();
}
public List<Actor> GetMembers()
{
return members;
}
public List<Actor> GetPlayerMembers()
{
return members.FindAll(s => s is Player);
}
public List<Actor> GetNpcMembers()
{
return members.FindAll(s => s is Npc);
}
public bool IsCreated()
{
return isCreated;
}
public bool IsDeleted()
{
return isDeleted;
}
public bool HasContentGroup()
{
return contentGroup != null;
}
public ContentGroup GetContentGroup()
{
return contentGroup;
}
public void GenerateActorName(int actorNumber)
{
//Format Class Name
string className = this.className;
className = Char.ToLowerInvariant(className[0]) + className.Substring(1);
//Format Zone Name
string zoneName = zone.zoneName.Replace("Field", "Fld")
.Replace("Dungeon", "Dgn")
.Replace("Town", "Twn")
.Replace("Battle", "Btl")
.Replace("Test", "Tes")
.Replace("Event", "Evt")
.Replace("Ship", "Shp")
.Replace("Office", "Ofc");
if (zone is PrivateArea)
{
//Check if "normal"
zoneName = zoneName.Remove(zoneName.Length - 1, 1) + "P";
}
zoneName = Char.ToLowerInvariant(zoneName[0]) + zoneName.Substring(1);
try
{
className = className.Substring(0, 20 - zoneName.Length);
}
catch (ArgumentOutOfRangeException e)
{ }
//Convert actor number to base 63
string classNumber = Utils.ToStringBase63(actorNumber);
//Get stuff after @
uint zoneId = zone.actorId;
uint privLevel = 0;
if (zone is PrivateArea)
privLevel = ((PrivateArea)zone).GetPrivateAreaType();
actorName = String.Format("{0}_{1}_{2}@{3:X3}{4:X2}", className, zoneName, classNumber, zoneId, privLevel);
}
public string GetScriptPath()
{
return directorScriptPath;
}
private void LoadLuaScript()
{
string luaPath = String.Format(LuaEngine.FILEPATH_DIRECTORS, GetScriptPath());
directorScript = LuaEngine.LoadScript(luaPath);
if (directorScript == null)
Program.Log.Error("Could not find script for director {0}.", GetName());
}
private List<LuaParam> CallLuaScript(string funcName, params object[] args)
{
if (directorScript != null)
{
if (!directorScript.Globals.Get(funcName).IsNil())
{
DynValue result = directorScript.Call(directorScript.Globals[funcName], args);
List<LuaParam> lparams = LuaUtils.CreateLuaParamList(result);
return lparams;
}
else
Program.Log.Error("Could not find script for director {0}.", GetName());
}
return null;
}
private List<LuaParam> StartCoroutine(string funcName, params object[] args)
{
if (directorScript != null)
{
if (!directorScript.Globals.Get(funcName).IsNil())
{
currentCoroutine = directorScript.CreateCoroutine(directorScript.Globals[funcName]).Coroutine;
DynValue value = currentCoroutine.Resume(args);
LuaEngine.GetInstance().ResolveResume(null, currentCoroutine, value);
}
else
Program.Log.Error("Could not find script for director {0}.", GetName());
}
return null;
}
public void OnEventStart(Player player, object[] args)
{
object[] args2 = new object[args.Length + (player == null ? 1 : 2)];
Array.Copy(args, 0, args2, (player == null ? 1 : 2), args.Length);
if (player != null)
{
args2[0] = player;
args2[1] = this;
}
else
args2[0] = this;
Coroutine coroutine = directorScript.CreateCoroutine(directorScript.Globals["onEventStarted"]).Coroutine;
DynValue value = coroutine.Resume(args2);
LuaEngine.GetInstance().ResolveResume(player, coroutine, value);
}
} }
} }

View File

@ -0,0 +1,256 @@
using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.actors.area;
using FFXIVClassic_Map_Server.actors.director.Work;
using FFXIVClassic_Map_Server.actors.group;
using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.dataobjects;
using FFXIVClassic_Map_Server.utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_Map_Server.actors.director
{
class GuildleveDirector : Director
{
public uint guildleveId;
public Player guildleveOwner;
public byte selectedDifficulty;
public GuildleveData guildleveData;
public GuildleveWork guildleveWork = new GuildleveWork();
public bool isEnded = false;
public uint completionTime = 0;
public GuildleveDirector(uint id, Area zone, string directorPath, uint guildleveId, byte selectedDifficulty, Player guildleveOwner, params object[] args)
: base(id, zone, directorPath, true, args)
{
this.guildleveId = guildleveId;
this.selectedDifficulty = selectedDifficulty;
this.guildleveData = Server.GetGuildleveGamedata(guildleveId);
this.guildleveOwner = guildleveOwner;
guildleveWork.aimNum[0] = guildleveData.aimNum[0];
guildleveWork.aimNum[1] = guildleveData.aimNum[1];
guildleveWork.aimNum[2] = guildleveData.aimNum[2];
guildleveWork.aimNum[3] = guildleveData.aimNum[3];
if (guildleveWork.aimNum[0] != 0)
guildleveWork.uiState[0] = 1;
if (guildleveWork.aimNum[1] != 0)
guildleveWork.uiState[1] = 1;
if (guildleveWork.aimNum[2] != 0)
guildleveWork.uiState[2] = 1;
if (guildleveWork.aimNum[3] != 0)
guildleveWork.uiState[3] = 1;
guildleveWork.aimNumNow[0] = guildleveWork.aimNumNow[1] = guildleveWork.aimNumNow[2] = guildleveWork.aimNumNow[3] = 0;
}
public void LoadGuildleve()
{
}
public void StartGuildleve()
{
foreach (Actor p in GetPlayerMembers())
{
Player player = (Player) p;
//Set music
if (guildleveData.location == 1)
player.ChangeMusic(22);
else if (guildleveData.location == 2)
player.ChangeMusic(14);
else if (guildleveData.location == 3)
player.ChangeMusic(26);
else if (guildleveData.location == 4)
player.ChangeMusic(16);
//Show Start Messages
player.SendGameMessage(Server.GetWorldManager().GetActor(), 50022, 0x20, guildleveId, selectedDifficulty);
player.SendDataPacket("attention", Server.GetWorldManager().GetActor(), "", 50022, guildleveId, selectedDifficulty);
player.SendGameMessage(Server.GetWorldManager().GetActor(), 50026, 0x20, (object)(int)guildleveData.timeLimit);
}
guildleveWork.startTime = Utils.UnixTimeStampUTC();
ActorPropertyPacketUtil propertyBuilder = new ActorPropertyPacketUtil("guildleveWork/start", this);
propertyBuilder.AddProperty("guildleveWork.startTime");
SendPacketsToPlayers(propertyBuilder.Done());
}
public void EndGuildleve(bool wasCompleted)
{
if (isEnded)
return;
isEnded = true;
completionTime = Utils.UnixTimeStampUTC() - guildleveWork.startTime;
if (wasCompleted)
{
foreach (Actor a in GetPlayerMembers())
{
Player player = (Player)a;
player.MarkGuildleve(guildleveId, true, true);
player.PlayAnimation(0x02000002, true);
player.ChangeMusic(81);
player.SendGameMessage(Server.GetWorldManager().GetActor(), 50023, 0x20, (object)(int)guildleveId);
player.SendDataPacket("attention", Server.GetWorldManager().GetActor(), "", 50023, (object)(int)guildleveId);
}
}
foreach (Actor a in GetNpcMembers())
{
Npc npc = (Npc)a;
npc.Despawn();
RemoveMember(a);
}
guildleveWork.startTime = 0;
guildleveWork.signal = -1;
ActorPropertyPacketUtil propertyBuilder = new ActorPropertyPacketUtil("guildleveWork/signal", this);
propertyBuilder.AddProperty("guildleveWork.signal");
propertyBuilder.NewTarget("guildleveWork/start");
propertyBuilder.AddProperty("guildleveWork.startTime");
SendPacketsToPlayers(propertyBuilder.Done());
if (wasCompleted)
{
Npc aetheryteNode = zone.SpawnActor(1200040, String.Format("{0}:warpExit", guildleveOwner.actorName), guildleveOwner.positionX, guildleveOwner.positionY, guildleveOwner.positionZ);
AddMember(aetheryteNode);
foreach (Actor a in GetPlayerMembers())
{
Player player = (Player)a;
player.SendGameMessage(Server.GetWorldManager().GetActor(), 50029, 0x20);
player.SendGameMessage(Server.GetWorldManager().GetActor(), 50032, 0x20);
}
}
}
public void AbandonGuildleve()
{
foreach (Actor p in GetPlayerMembers())
{
Player player = (Player)p;
player.SendGameMessage(Server.GetWorldManager().GetActor(), 50147, 0x20, (object)guildleveId);
player.MarkGuildleve(guildleveId, true, false);
}
EndGuildleve(false);
EndDirector();
}
//Delete ContentGroup, change music back
public void EndGuildleveDirector()
{
foreach (Actor p in GetPlayerMembers())
{
Player player = (Player)p;
player.ChangeMusic(player.GetZone().bgmDay);
}
}
public void SyncAllInfo()
{
ActorPropertyPacketUtil propertyBuilder = new ActorPropertyPacketUtil("guildleveWork/infoVariable", this);
if (guildleveWork.aimNum[0] != 0)
propertyBuilder.AddProperty("guildleveWork.aimNum[0]");
if (guildleveWork.aimNum[1] != 0)
propertyBuilder.AddProperty("guildleveWork.aimNum[1]");
if (guildleveWork.aimNum[2] != 0)
propertyBuilder.AddProperty("guildleveWork.aimNum[2]");
if (guildleveWork.aimNum[3] != 0)
propertyBuilder.AddProperty("guildleveWork.aimNum[3]");
if (guildleveWork.aimNumNow[0] != 0)
propertyBuilder.AddProperty("guildleveWork.aimNumNow[0]");
if (guildleveWork.aimNumNow[1] != 0)
propertyBuilder.AddProperty("guildleveWork.aimNumNow[1]");
if (guildleveWork.aimNumNow[2] != 0)
propertyBuilder.AddProperty("guildleveWork.aimNumNow[2]");
if (guildleveWork.aimNumNow[3] != 0)
propertyBuilder.AddProperty("guildleveWork.aimNumNow[3]");
if (guildleveWork.uiState[0] != 0)
propertyBuilder.AddProperty("guildleveWork.uiState[0]");
if (guildleveWork.uiState[1] != 0)
propertyBuilder.AddProperty("guildleveWork.uiState[1]");
if (guildleveWork.uiState[2] != 0)
propertyBuilder.AddProperty("guildleveWork.uiState[2]");
if (guildleveWork.uiState[3] != 0)
propertyBuilder.AddProperty("guildleveWork.uiState[3]");
SendPacketsToPlayers(propertyBuilder.Done());
}
public void UpdateAimNumNow(int index, sbyte value)
{
guildleveWork.aimNumNow[index] = value;
ActorPropertyPacketUtil propertyBuilder = new ActorPropertyPacketUtil("guildleveWork/infoVariable", this);
propertyBuilder.AddProperty(String.Format("guildleveWork.aimNumNow[{0}]", index));
SendPacketsToPlayers(propertyBuilder.Done());
}
public void UpdateUiState(int index, sbyte value)
{
guildleveWork.uiState[index] = value;
ActorPropertyPacketUtil propertyBuilder = new ActorPropertyPacketUtil("guildleveWork/infoVariable", this);
propertyBuilder.AddProperty(String.Format("guildleveWork.uiState[{0}]", index));
SendPacketsToPlayers(propertyBuilder.Done());
}
public void UpdateMarkers(int markerIndex, float x, float y, float z)
{
guildleveWork.markerX[markerIndex] = x;
guildleveWork.markerY[markerIndex] = y;
guildleveWork.markerZ[markerIndex] = z;
ActorPropertyPacketUtil propertyBuilder = new ActorPropertyPacketUtil("guildleveWork/marker", this);
propertyBuilder.AddProperty(String.Format("guildleveWork.markerX[{0}]", markerIndex));
propertyBuilder.AddProperty(String.Format("guildleveWork.markerY[{0}]", markerIndex));
propertyBuilder.AddProperty(String.Format("guildleveWork.markerZ[{0}]", markerIndex));
SendPacketsToPlayers(propertyBuilder.Done());
}
public void SendPacketsToPlayers(List<SubPacket> packets)
{
List<Actor> players = GetPlayerMembers();
foreach (Actor p in players)
{
((Player)p).QueuePackets(packets);
}
}
public static uint GlBorderIconIDToAnimID(uint iconId)
{
return iconId - 20000;
}
public static uint GlPlateIconIDToAnimID(uint iconId)
{
return iconId - 20020;
}
public static uint GetGLStartAnimationFromSheet(uint border, uint plate, bool isBoost)
{
return GetGLStartAnimation(GlBorderIconIDToAnimID(border), GlPlateIconIDToAnimID(plate), isBoost);
}
public static uint GetGLStartAnimation(uint border, uint plate, bool isBoost)
{
uint borderBits = border;
uint plateBits = plate << 7;
uint boostBits = isBoost ? (uint)0x8000 : (uint) 0;
return 0x0B000000 | boostBits | plateBits | borderBits;
}
}
}

View File

@ -1,40 +0,0 @@
using FFXIVClassic_Map_Server.packets;
using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.lua;
using FFXIVClassic_Map_Server.packets.send.actor;
using System;
using System.Collections.Generic;
namespace FFXIVClassic_Map_Server.actors.director
{
class OpeningDirector : Director
{
public OpeningDirector(Player player, uint id) : base(player, id)
{
this.displayNameId = 0;
this.customDisplayName = String.Format("openingDire_{0}_{1}", player.zone.zoneName, "04");
this.actorName = String.Format("openingDire_{0}_{1}@{2:x3}{3:x2}", player.zone.zoneName, "04", player.zoneId, 0);
this.actorName = this.actorName.Replace("Battle", "Btl");
this.className = "OpeningDirector";
this.eventConditions = new EventList();
List<EventList.NoticeEventCondition> noticeEventList = new List<EventList.NoticeEventCondition>();
noticeEventList.Add(new EventList.NoticeEventCondition("noticeEvent", 0xE, 0x0));
noticeEventList.Add(new EventList.NoticeEventCondition("noticeRequest", 0x0, 0x1));
this.eventConditions.noticeEventConditions = noticeEventList;
}
public override SubPacket CreateScriptBindPacket(uint playerActorId)
{
List<LuaParam> lParams;
lParams = LuaUtils.CreateLuaParamList("/Director/OpeningDirector", false, false, false, false, 0x13881);
return ActorInstantiatePacket.BuildPacket(actorId, playerActorId, actorName, className, lParams);
}
}
}

View File

@ -1,48 +0,0 @@
using FFXIVClassic_Map_Server.packets;
using FFXIVClassic_Map_Server.actors.director;
using FFXIVClassic_Map_Server.lua;
using FFXIVClassic_Map_Server.packets.send.actor;
using System;
using System.Collections.Generic;
namespace FFXIVClassic_Map_Server.Actors
{
class WeatherDirector : Director
{
private uint weatherId;
public WeatherDirector(Player player, uint weatherId)
: base(player, 0x5FF80003)
{
this.weatherId = weatherId;
this.displayNameId = 0;
this.customDisplayName = String.Format("weatherDire_{0}_{1}", player.zone.zoneName, "07");
this.actorName = String.Format("weatherDire_{0}_{1}@{2:x3}{3:x2}", player.zone.zoneName, "04", player.zoneId, 0);
this.className = "Debug";
}
public override SubPacket CreateScriptBindPacket(uint playerActorId)
{
List<LuaParam> lParams;
lParams = LuaUtils.CreateLuaParamList("/Director/Weather/WeatherDirector", false, false, false, false, weatherId);
return ActorInstantiatePacket.BuildPacket(actorId, playerActorId, actorName, className, lParams);
}
public override BasePacket GetSpawnPackets(uint playerActorId)
{
List<SubPacket> subpackets = new List<SubPacket>();
subpackets.Add(CreateAddActorPacket(playerActorId, 0));
subpackets.Add(CreateSpeedPacket(playerActorId));
subpackets.Add(CreateSpawnPositonPacket(playerActorId, 0x1));
subpackets.Add(CreateNamePacket(playerActorId));
subpackets.Add(CreateStatePacket(playerActorId));
subpackets.Add(CreateIsZoneingPacket(playerActorId));
subpackets.Add(CreateScriptBindPacket(playerActorId));
return BasePacket.CreatePacket(subpackets, true, false);
}
}
}

View File

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_Map_Server.actors.director.Work
{
class GuildleveWork
{
public uint startTime = 0;
public sbyte[] aimNum = new sbyte[4];
public sbyte[] aimNumNow = new sbyte[4];
public sbyte[] uiState = new sbyte[4];
public float[] markerX = new float[3];
public float[] markerY = new float[3];
public float[] markerZ = new float[3];
public sbyte signal;
}
}

View File

@ -1,37 +0,0 @@
using FFXIVClassic_Map_Server.packets;
using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.lua;
using FFXIVClassic_Map_Server.packets.send.actor;
using System.Collections.Generic;
namespace FFXIVClassic_Map_Server.actors.director
{
class QuestDirectorMan0g001 : Director
{
public QuestDirectorMan0g001(Player player, uint id)
: base(player, id)
{
this.displayNameId = 0;
this.customDisplayName = "questDirect_fst0Btl03_01";
this.actorName = "questDirect_fst0Btl03_01@0A615";
this.className = "QuestDirectorMan0g001";
this.eventConditions = new EventList();
List<EventList.NoticeEventCondition> noticeEventList = new List<EventList.NoticeEventCondition>();
noticeEventList.Add(new EventList.NoticeEventCondition("noticeEvent", 0xE, 0x0));
noticeEventList.Add(new EventList.NoticeEventCondition("noticeRequest", 0x0, 0x1));
this.eventConditions.noticeEventConditions = noticeEventList;
}
public override SubPacket CreateScriptBindPacket(uint playerActorId)
{
List<LuaParam> lParams;
lParams = LuaUtils.CreateLuaParamList("/Director/Quest/QuestDirectorMan0g001", false, false, false, false, false, 0x753A);
return ActorInstantiatePacket.BuildPacket(actorId, playerActorId, actorName, className, lParams);
}
}
}

View File

@ -1,37 +0,0 @@
using FFXIVClassic_Map_Server.packets;
using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.lua;
using FFXIVClassic_Map_Server.packets.send.actor;
using System.Collections.Generic;
namespace FFXIVClassic_Map_Server.actors.director
{
class QuestDirectorMan0l001 : Director
{
public QuestDirectorMan0l001(Player player, uint id)
: base(player, id)
{
this.displayNameId = 0;
this.customDisplayName = "questDirect_ocn0Btl02_01";
this.actorName = "questDirect_ocn0Btl02_01@0C196";
this.className = "QuestDirectorMan0l001";
this.eventConditions = new EventList();
List<EventList.NoticeEventCondition> noticeEventList = new List<EventList.NoticeEventCondition>();
noticeEventList.Add(new EventList.NoticeEventCondition("noticeEvent", 0xE, 0x0));
noticeEventList.Add(new EventList.NoticeEventCondition("noticeRequest", 0x0, 0x1));
this.eventConditions.noticeEventConditions = noticeEventList;
}
public override SubPacket CreateScriptBindPacket(uint playerActorId)
{
List<LuaParam> lParams;
lParams = LuaUtils.CreateLuaParamList("/Director/Quest/QuestDirectorMan0l001", false, false, false, false, false, 0x7532);
return ActorInstantiatePacket.BuildPacket(actorId, playerActorId, actorName, className, lParams);
}
}
}

View File

@ -1,37 +0,0 @@
using FFXIVClassic_Map_Server.packets;
using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.lua;
using FFXIVClassic_Map_Server.packets.send.actor;
using System.Collections.Generic;
namespace FFXIVClassic_Map_Server.actors.director
{
class QuestDirectorMan0u001 : Director
{
public QuestDirectorMan0u001(Player player, uint id)
: base(player, id)
{
this.displayNameId = 0;
this.customDisplayName = "questDirect_wil0Btl01_01";
this.actorName = "questDirect_wil0Btl01_01@0A615";
this.className = "QuestDirectorMan0u001";
this.eventConditions = new EventList();
List<EventList.NoticeEventCondition> noticeEventList = new List<EventList.NoticeEventCondition>();
noticeEventList.Add(new EventList.NoticeEventCondition("noticeEvent", 0xE, 0x0));
noticeEventList.Add(new EventList.NoticeEventCondition("noticeRequest", 0x0, 0x1));
this.eventConditions.noticeEventConditions = noticeEventList;
}
public override SubPacket CreateScriptBindPacket(uint playerActorId)
{
List<LuaParam> lParams;
lParams = LuaUtils.CreateLuaParamList("/Director/Quest/QuestDirectorMan0u001", false, false, false, false, false, 0x757F);
return ActorInstantiatePacket.BuildPacket(actorId, playerActorId, actorName, className, lParams);
}
}
}

View File

@ -0,0 +1,173 @@
using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.actors.director;
using FFXIVClassic_Map_Server.actors.group.Work;
using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.dataobjects;
using FFXIVClassic_Map_Server.packets.send.group;
using FFXIVClassic_Map_Server.packets.send.groups;
using FFXIVClassic_Map_Server.utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_Map_Server.actors.group
{
class ContentGroup : Group
{
public ContentGroupWork contentGroupWork = new ContentGroupWork();
private Director director;
private List<uint> members = new List<uint>();
private bool isStarted = false;
public ContentGroup(ulong groupIndex, Director director, uint[] initialMembers) : base(groupIndex)
{
if (initialMembers != null)
{
for (int i = 0; i < initialMembers.Length; i++)
{
Session s = Server.GetServer().GetSession(initialMembers[i]);
if (s != null)
s.GetActor().SetCurrentContentGroup(this);
members.Add(initialMembers[i]);
}
}
this.director = director;
contentGroupWork._globalTemp.director = (ulong)director.actorId << 32;
}
public void Start()
{
isStarted = true;
SendGroupPacketsAll(members);
}
public void AddMember(Actor actor)
{
if (actor == null)
return;
members.Add(actor.actorId);
if (actor is Character)
((Character)actor).SetCurrentContentGroup(this);
if (isStarted)
SendGroupPacketsAll(members);
}
public void RemoveMember(uint memberId)
{
members.Remove(memberId);
if (isStarted)
SendGroupPacketsAll(members);
CheckDestroy();
}
public override List<GroupMember> BuildMemberList(uint id)
{
List<GroupMember> groupMembers = new List<GroupMember>();
groupMembers.Add(new GroupMember(id, -1, 0, false, true, ""));
foreach (uint charaId in members)
{
if (charaId != id)
groupMembers.Add(new GroupMember(charaId, -1, 0, false, true, ""));
}
return groupMembers;
}
public override int GetMemberCount()
{
return members.Count;
}
public override void SendInitWorkValues(Session session)
{
SynchGroupWorkValuesPacket groupWork = new SynchGroupWorkValuesPacket(groupIndex);
groupWork.addProperty(this, "contentGroupWork._globalTemp.director");
groupWork.addByte(Utils.MurmurHash2("contentGroupWork.property[0]", 0), 1);
groupWork.setTarget("/_init");
SubPacket test = groupWork.buildPacket(session.id, session.id);
test.DebugPrintSubPacket();
session.QueuePacket(test);
}
public override void SendGroupPackets(Session session)
{
ulong time = Utils.MilisUnixTimeStampUTC();
List<GroupMember> members = BuildMemberList(session.id);
session.QueuePacket(GroupHeaderPacket.buildPacket(session.id, session.GetActor().zoneId, time, this));
session.QueuePacket(GroupMembersBeginPacket.buildPacket(session.id, session.GetActor().zoneId, time, this));
int currentIndex = 0;
while (true)
{
if (GetMemberCount() - currentIndex >= 64)
session.QueuePacket(ContentMembersX64Packet.buildPacket(session.id, session.GetActor().zoneId, time, members, ref currentIndex));
else if (GetMemberCount() - currentIndex >= 32)
session.QueuePacket(ContentMembersX32Packet.buildPacket(session.id, session.GetActor().zoneId, time, members, ref currentIndex));
else if (GetMemberCount() - currentIndex >= 16)
session.QueuePacket(ContentMembersX16Packet.buildPacket(session.id, session.GetActor().zoneId, time, members, ref currentIndex));
else if (GetMemberCount() - currentIndex > 0)
session.QueuePacket(ContentMembersX08Packet.buildPacket(session.id, session.GetActor().zoneId, time, members, ref currentIndex));
else
break;
}
session.QueuePacket(GroupMembersEndPacket.buildPacket(session.id, session.GetActor().zoneId, time, this));
}
public override uint GetTypeId()
{
return Group.ContentGroup_SimpleContentGroup24B;
}
public void SendAll()
{
SendGroupPacketsAll(members);
}
public void DeleteGroup()
{
SendDeletePackets(members);
for (int i = 0; i < members.Count; i++)
{
Session s = Server.GetServer().GetSession(members[i]);
if (s != null)
s.GetActor().SetCurrentContentGroup(null);
Actor a = director.GetZone().FindActorInArea(members[i]);
if (a is Npc)
((Npc)a).Despawn();
members.Remove(members[i]);
i--;
}
Server.GetWorldManager().DeleteContentGroup(groupIndex);
}
public void CheckDestroy()
{
bool foundSession = false;
foreach (uint memberId in members)
{
Session session = Server.GetServer().GetSession(memberId);
if (session != null)
{
foundSession = true;
break;
}
}
if (!foundSession)
DeleteGroup();
}
}
}

View File

@ -0,0 +1,29 @@
using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.actors.director;
using FFXIVClassic_Map_Server.actors.group.Work;
using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.dataobjects;
using FFXIVClassic_Map_Server.packets.send.group;
using FFXIVClassic_Map_Server.packets.send.groups;
using FFXIVClassic_Map_Server.utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_Map_Server.actors.group
{
class GLContentGroup : ContentGroup
{
public GLContentGroup(ulong groupIndex, Director director, uint[] initialMembers)
: base(groupIndex, director, initialMembers)
{
}
public override uint GetTypeId()
{
return Group.ContentGroup_GuildleveGroup;
}
}
}

View File

@ -0,0 +1,157 @@
using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.dataobjects;
using FFXIVClassic_Map_Server.packets.send.group;
using FFXIVClassic_Map_Server.packets.send.groups;
using System;
using System.Collections.Generic;
namespace FFXIVClassic_Map_Server.actors.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 BazaarBuyItemRelationGroup = 50009;
public const uint RetainerGroup = 80001;
public const uint MonsterPartyGroup = 10002;
public const uint ContentGroup_GuildleveGroup = 30001;
public const uint ContentGroup_PublicPopGroup = 30002;
public const uint ContentGroup_SimpleContentGroup24A = 30003;
public const uint ContentGroup_SimpleContentGroup32A = 30004;
public const uint ContentGroup_SimpleContentGroup128 = 30005;
public const uint ContentGroup_SimpleContentGroup24B = 30006;
public const uint ContentGroup_SimpleContentGroup32B = 30007;
public const uint ContentGroup_RetainerAccessGroup = 30008;
public const uint ContentGroup_SimpleContentGroup99999 = 30009;
public const uint ContentGroup_SimpleContentGroup512 = 30010;
public const uint ContentGroup_SimpleContentGroup64A = 30011;
public const uint ContentGroup_SimpleContentGroup64B = 30012;
public const uint ContentGroup_SimpleContentGroup64C = 30013;
public const uint ContentGroup_SimpleContentGroup64D = 30014;
public const uint ContentGroup_SimpleContentGroup64E = 30015;
public const uint ContentGroup_SimpleContentGroup64F = 30016;
public const uint ContentGroup_SimpleContentGroup64G = 30017;
public const uint ContentGroup_SimpleContentGroup24C = 30018;
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[] ids)
{
for (int i = 0; i < ids.Length; i++)
{
Session session = Server.GetServer().GetSession(ids[i]);
if (session != null)
SendGroupPackets(session);
}
}
public void SendGroupPacketsAll(List<uint> ids)
{
for (int i = 0; i < ids.Count; i++)
{
Session session = Server.GetServer().GetSession(ids[i]);
if (session != null)
SendGroupPackets(session);
}
}
public void SendDeletePackets(params uint[] ids)
{
for (int i = 0; i < ids.Length; i++)
{
Session session = Server.GetServer().GetSession(ids[i]);
if (session != null)
SendDeletePacket(session);
}
}
public void SendDeletePackets(List<uint> ids)
{
for (int i = 0; i < ids.Count; i++)
{
Session session = Server.GetServer().GetSession(ids[i]);
if (session != null)
SendDeletePacket(session);
}
}
public virtual void SendGroupPackets(Session session)
{
ulong time = Utils.MilisUnixTimeStampUTC();
List<GroupMember> members = BuildMemberList(session.id);
session.QueuePacket(GroupHeaderPacket.buildPacket(session.id, session.GetActor().zoneId, time, this));
session.QueuePacket(GroupMembersBeginPacket.buildPacket(session.id, session.GetActor().zoneId, time, this));
int currentIndex = 0;
while (true)
{
if (GetMemberCount() - currentIndex >= 64)
session.QueuePacket(GroupMembersX64Packet.buildPacket(session.id, session.GetActor().zoneId, time, members, ref currentIndex));
else if (GetMemberCount() - currentIndex >= 32)
session.QueuePacket(GroupMembersX32Packet.buildPacket(session.id, session.GetActor().zoneId, time, members, ref currentIndex));
else if (GetMemberCount() - currentIndex >= 16)
session.QueuePacket(GroupMembersX16Packet.buildPacket(session.id, session.GetActor().zoneId, time, members, ref currentIndex));
else if (GetMemberCount() - currentIndex > 0)
session.QueuePacket(GroupMembersX08Packet.buildPacket(session.id, session.GetActor().zoneId, time, members, ref currentIndex));
else
break;
}
session.QueuePacket(GroupMembersEndPacket.buildPacket(session.id, session.GetActor().zoneId, time, this));
}
public void SendDeletePacket(Session session)
{
if (session != null)
session.QueuePacket(DeleteGroupPacket.buildPacket(session.id, this));
}
public virtual void SendInitWorkValues(Session session)
{
}
}
}

View File

@ -0,0 +1,63 @@
using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.dataobjects;
using FFXIVClassic_Map_Server.packets.send.group;
using FFXIVClassic_Map_Server.packets.send.groups;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_Map_Server.actors.group
{
class MonsterParty : Group
{
private List<uint> monsterMembers = new List<uint>();
public MonsterParty(ulong groupIndex, uint[] initialMonsterMembers)
: base(groupIndex)
{
for (int i = 0; i < initialMonsterMembers.Length; i++)
monsterMembers.Add(initialMonsterMembers[i]);
}
public void AddMember(uint memberId)
{
monsterMembers.Add(memberId);
SendGroupPacketsAll(monsterMembers);
}
public void RemoveMember(uint memberId)
{
monsterMembers.Remove(memberId);
SendGroupPacketsAll(monsterMembers);
}
public override List<GroupMember> BuildMemberList(uint id)
{
List<GroupMember> groupMembers = new List<GroupMember>();
groupMembers.Add(new GroupMember(id, -1, 0, false, true, Server.GetWorldManager().GetActorInWorld(id).customDisplayName));
foreach (uint charaId in monsterMembers)
{
if (charaId != id)
groupMembers.Add(new GroupMember(charaId, -1, 0, false, true, Server.GetWorldManager().GetActorInWorld(charaId).customDisplayName));
}
return groupMembers;
}
public override void SendInitWorkValues(Session session)
{
SynchGroupWorkValuesPacket groupWork = new SynchGroupWorkValuesPacket(groupIndex);
groupWork.setTarget("/_init");
SubPacket test = groupWork.buildPacket(session.id, session.id);
session.QueuePacket(test);
}
public override uint GetTypeId()
{
return Group.MonsterPartyGroup;
}
}
}

View File

@ -0,0 +1,74 @@
using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.actors.group.Work;
using FFXIVClassic_Map_Server.dataobjects;
using FFXIVClassic_Map_Server.packets.send.group;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_Map_Server.actors.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 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.GetWorldManager().GetActorInWorld(members[i]).customDisplayName.Equals(name))
{
return members[i];
}
}
return 0;
}
public bool IsInParty(uint charaId)
{
return members.Contains(charaId);
}
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.GetWorldManager().GetActorInWorld(id).customDisplayName));
foreach (uint charaId in members)
{
if (charaId != id)
groupMembers.Add(new GroupMember(charaId, -1, 0, false, true, Server.GetWorldManager().GetActorInWorld(charaId).customDisplayName));
}
return groupMembers;
}
}
}

View File

@ -0,0 +1,77 @@
using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.actors.group.Work;
using FFXIVClassic_Map_Server.dataobjects;
using FFXIVClassic_Map_Server.packets.send.group;
using FFXIVClassic_Map_Server.packets.send.groups;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_Map_Server.actors.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.GetWorldManager().GetActorInWorld(hostId).customDisplayName));
groupMembers.Add(new GroupMember(charaOther, -1, 0, false, Server.GetServer().GetSession(charaOther) != null, Server.GetWorldManager().GetActorInWorld(charaOther).customDisplayName));
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.id, session.id);
test.DebugPrintSubPacket();
session.QueuePacket(test);
}
}
}

View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace FFXIVClassic_Map_Server.actors.group.Work
{
class ContentGroupWork
{
public GlobalTemp _globalTemp = new GlobalTemp();
public bool[] property = new bool[32];
}
}

View File

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace FFXIVClassic_Map_Server.actors.group.Work
{
class GlobalTemp
{
public ulong director;
}
}

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_Map_Server.actors.group.Work
{
class GroupGlobalSave
{
public ulong master;
public ushort[] crestIcon = new ushort[4];
public byte rank = 1;
}
}

View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_Map_Server.actors.group.Work
{
class GroupGlobalTemp
{
public ulong owner;
//For content group
public ulong director;
//For relation group
public ulong host;
public uint variableCommand;
}
}

View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_Map_Server.actors.group.Work
{
class GroupMemberSave
{
//For LS
public byte rank;
//For Retainers
public byte cdIDOffset;
public ushort placeName;
public byte conditions;
public byte level;
}
}

View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_Map_Server.actors.group.Work
{
class PartyWork
{
public GroupGlobalTemp _globalTemp = new GroupGlobalTemp();
}
}

View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_Map_Server.actors.group.Work
{
class RelationWork
{
public GroupGlobalTemp _globalTemp = new GroupGlobalTemp();
}
}

View File

@ -1,4 +1,5 @@
using FFXIVClassic.Common; using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.lua;
using Newtonsoft.Json; using Newtonsoft.Json;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -8,7 +9,7 @@ namespace FFXIVClassic_Map_Server.Actors
class Quest : Actor class Quest : Actor
{ {
private Player owner; private Player owner;
private int currentPhase = 0; private uint currentPhase = 0;
private uint questFlags = 0; private uint questFlags = 0;
private Dictionary<string, Object> questData = new Dictionary<string, object>(); private Dictionary<string, Object> questData = new Dictionary<string, object>();
@ -18,7 +19,7 @@ namespace FFXIVClassic_Map_Server.Actors
actorName = name; actorName = name;
} }
public Quest(Player owner, uint actorID, string name, string questDataJson, uint questFlags) public Quest(Player owner, uint actorID, string name, string questDataJson, uint questFlags, uint currentPhase)
: base(actorID) : base(actorID)
{ {
this.owner = owner; this.owner = owner;
@ -32,6 +33,8 @@ namespace FFXIVClassic_Map_Server.Actors
if (questData == null) if (questData == null)
questData = new Dictionary<string, object>(); questData = new Dictionary<string, object>();
this.currentPhase = currentPhase;
} }
public void SetQuestData(string dataName, object data) public void SetQuestData(string dataName, object data)
@ -41,6 +44,11 @@ namespace FFXIVClassic_Map_Server.Actors
//Inform update //Inform update
} }
public uint GetQuestId()
{
return actorId & 0xFFFFF;
}
public object GetQuestData(string dataName) public object GetQuestData(string dataName)
{ {
if (questData.ContainsKey(dataName)) if (questData.ContainsKey(dataName))
@ -54,11 +62,6 @@ namespace FFXIVClassic_Map_Server.Actors
questData.Clear(); questData.Clear();
} }
public uint GetQuestId()
{
return actorId;
}
public void ClearQuestFlags() public void ClearQuestFlags()
{ {
questFlags = 0; questFlags = 0;
@ -79,7 +82,7 @@ namespace FFXIVClassic_Map_Server.Actors
else else
questFlags &= (uint)~(1 << bitIndex); questFlags &= (uint)~(1 << bitIndex);
//Inform update DoCompletionCheck();
} }
public bool GetQuestFlag(int bitIndex) public bool GetQuestFlag(int bitIndex)
@ -93,14 +96,18 @@ namespace FFXIVClassic_Map_Server.Actors
return (questFlags & (1 << bitIndex)) == (1 << bitIndex); return (questFlags & (1 << bitIndex)) == (1 << bitIndex);
} }
public int GetPhase() public uint GetPhase()
{ {
return currentPhase; return currentPhase;
} }
public void NextPhase() public void NextPhase(uint phaseNumber)
{ {
currentPhase++; currentPhase = phaseNumber;
owner.SendGameMessage(Server.GetWorldManager().GetActor(), 25116, 0x20, (object)GetQuestId());
SaveData();
DoCompletionCheck();
} }
public uint GetQuestFlags() public uint GetQuestFlags()
@ -118,5 +125,21 @@ namespace FFXIVClassic_Map_Server.Actors
Database.SaveQuest(owner, this); Database.SaveQuest(owner, this);
} }
public void DoCompletionCheck()
{
List<LuaParam> returned = LuaEngine.GetInstance().CallLuaFunctionForReturn(owner, this, "isObjectivesComplete", true);
if (returned != null && returned.Count >= 1 && returned[0].typeID == 3)
{
owner.SendDataPacket("attention", Server.GetWorldManager().GetActor(), "", 25225, (object)GetQuestId());
owner.SendGameMessage(Server.GetWorldManager().GetActor(), 25225, 0x20, (object)GetQuestId());
}
}
public void DoAbandon()
{
LuaEngine.GetInstance().CallLuaFunctionForReturn(owner, this, "onAbandonQuest", true);
owner.SendGameMessage(owner, Server.GetWorldManager().GetActor(), 25236, 0x20, (object)GetQuestId());
}
} }
} }

View File

@ -1,4 +1,5 @@
using FFXIVClassic_Map_Server.packets; 
using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.lua; using FFXIVClassic_Map_Server.lua;
using FFXIVClassic_Map_Server.packets.send.actor; using FFXIVClassic_Map_Server.packets.send.actor;
using System.Collections.Generic; using System.Collections.Generic;
@ -16,24 +17,24 @@ namespace FFXIVClassic_Map_Server.Actors
this.className = "WorldMaster"; this.className = "WorldMaster";
} }
public override SubPacket CreateScriptBindPacket(uint playerActorId) public override SubPacket CreateScriptBindPacket()
{ {
List<LuaParam> lParams; List<LuaParam> lParams;
lParams = LuaUtils.CreateLuaParamList("/World/WorldMaster_event", false, false, false, false, false, null); lParams = LuaUtils.CreateLuaParamList("/World/WorldMaster_event", false, false, false, false, false, null);
return ActorInstantiatePacket.BuildPacket(actorId, playerActorId, actorName, className, lParams); return ActorInstantiatePacket.BuildPacket(actorId, actorName, className, lParams);
} }
public override BasePacket GetSpawnPackets(uint playerActorId) public override List<SubPacket> GetSpawnPackets()
{ {
List<SubPacket> subpackets = new List<SubPacket>(); List<SubPacket> subpackets = new List<SubPacket>();
subpackets.Add(CreateAddActorPacket(playerActorId, 0)); subpackets.Add(CreateAddActorPacket(0));
subpackets.Add(CreateSpeedPacket(playerActorId)); subpackets.Add(CreateSpeedPacket());
subpackets.Add(CreateSpawnPositonPacket(playerActorId, 0x1)); subpackets.Add(CreateSpawnPositonPacket(0x1));
subpackets.Add(CreateNamePacket(playerActorId)); subpackets.Add(CreateNamePacket());
subpackets.Add(CreateStatePacket(playerActorId)); subpackets.Add(CreateStatePacket());
subpackets.Add(CreateIsZoneingPacket(playerActorId)); subpackets.Add(CreateIsZoneingPacket());
subpackets.Add(CreateScriptBindPacket(playerActorId)); subpackets.Add(CreateScriptBindPacket());
return BasePacket.CreatePacket(subpackets, true, false); return subpackets;
} }
} }
} }

View File

@ -0,0 +1,61 @@
using MySql.Data.MySqlClient;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_Map_Server.dataobjects
{
class GuildleveData
{
public readonly uint id;
public readonly uint classType;
public readonly uint location;
public readonly ushort factionCreditRequired;
public readonly ushort level;
public readonly uint aetheryte;
public readonly uint plateId;
public readonly uint borderId;
public readonly uint objective;
public readonly byte timeLimit;
public readonly uint skill;
public readonly byte favorCount;
public readonly sbyte[] aimNum = new sbyte[4];
public readonly uint[] itemTarget = new uint[4];
public readonly uint[] mobTarget = new uint[4];
public GuildleveData(MySqlDataReader reader)
{
id = reader.GetUInt32("id");
classType = reader.GetUInt32("classType");
location = reader.GetUInt32("location");
factionCreditRequired = reader.GetUInt16("factionCreditRequired");
level = reader.GetUInt16("level");
aetheryte = reader.GetUInt32("aetheryte");
plateId = reader.GetUInt32("plateId");
borderId = reader.GetUInt32("borderId");
objective = reader.GetUInt32("objective");
timeLimit = reader.GetByte("timeLimit");
skill = reader.GetUInt32("skill");
favorCount = reader.GetByte("favorCount");
aimNum[0] = reader.GetSByte("aimNum1");
aimNum[1] = reader.GetSByte("aimNum2");
aimNum[2] = reader.GetSByte("aimNum3");
aimNum[3] = reader.GetSByte("aimNum4");
itemTarget[0] = reader.GetUInt32("item1");
itemTarget[1] = reader.GetUInt32("item2");
itemTarget[2] = reader.GetUInt32("item3");
itemTarget[3] = reader.GetUInt32("item4");
mobTarget[0] = reader.GetUInt32("mob1");
mobTarget[1] = reader.GetUInt32("mob2");
mobTarget[2] = reader.GetUInt32("mob3");
mobTarget[3] = reader.GetUInt32("mob4");
}
}
}

View File

@ -30,7 +30,7 @@ namespace FFXIVClassic_Map_Server.dataobjects
this.quantity = 1; this.quantity = 1;
this.slot = slot; this.slot = slot;
Item gItem = Server.GetItemGamedata(itemId); ItemData gItem = Server.GetItemGamedata(itemId);
itemType = gItem.isExclusive ? (byte)0x3 : (byte)0x0; itemType = gItem.isExclusive ? (byte)0x3 : (byte)0x0;
} }

View File

@ -3,7 +3,7 @@ using System;
namespace FFXIVClassic_Map_Server.dataobjects namespace FFXIVClassic_Map_Server.dataobjects
{ {
class Item class ItemData
{ {
//Basic //Basic
public readonly uint catalogID; public readonly uint catalogID;
@ -39,7 +39,7 @@ namespace FFXIVClassic_Map_Server.dataobjects
public readonly int repairLevel; public readonly int repairLevel;
public readonly int repairLicense; public readonly int repairLicense;
public Item(MySqlDataReader reader) public ItemData(MySqlDataReader reader)
{ {
catalogID = reader.GetUInt32("catalogID"); catalogID = reader.GetUInt32("catalogID");
name = reader.GetString("name"); name = reader.GetString("name");
@ -50,6 +50,8 @@ namespace FFXIVClassic_Map_Server.dataobjects
isExclusive = reader.GetBoolean("isExclusive"); isExclusive = reader.GetBoolean("isExclusive");
durability = reader.GetInt32("durability"); durability = reader.GetInt32("durability");
sellPrice = reader.GetInt32("sellPrice");
icon = reader.GetInt32("icon"); icon = reader.GetInt32("icon");
kind = reader.GetInt32("kind"); kind = reader.GetInt32("kind");
rarity = reader.GetInt32("rarity"); rarity = reader.GetInt32("rarity");
@ -387,7 +389,7 @@ namespace FFXIVClassic_Map_Server.dataobjects
} }
class EquipmentItem : Item class EquipmentItem : ItemData
{ {
//graphics //graphics
public readonly uint graphicsWeaponId; public readonly uint graphicsWeaponId;
@ -467,6 +469,11 @@ namespace FFXIVClassic_Map_Server.dataobjects
class WeaponItem : EquipmentItem class WeaponItem : EquipmentItem
{ {
//extra graphics
public readonly uint graphicsOffhandWeaponId;
public readonly uint graphicsOffhandEquipmentId;
public readonly uint graphicsOffhandVariantId;
//weapon sheet //weapon sheet
public readonly short attack; public readonly short attack;
public readonly short magicAttack; public readonly short magicAttack;
@ -497,6 +504,13 @@ namespace FFXIVClassic_Map_Server.dataobjects
public WeaponItem(MySqlDataReader reader) public WeaponItem(MySqlDataReader reader)
: base(reader) : base(reader)
{ {
if (!reader.IsDBNull(reader.GetOrdinal("offHandWeaponId")) && !reader.IsDBNull(reader.GetOrdinal("offHandEquipmentId")) && !reader.IsDBNull(reader.GetOrdinal("offHandVarientId")))
{
graphicsOffhandWeaponId = reader.GetUInt32("offHandWeaponId");
graphicsOffhandEquipmentId = reader.GetUInt32("offHandEquipmentId");
graphicsOffhandVariantId = reader.GetUInt32("offHandVarientId");
}
attack = reader.GetInt16("attack"); attack = reader.GetInt16("attack");
magicAttack = reader.GetInt16("magicAttack"); magicAttack = reader.GetInt16("magicAttack");
craftProcessing = reader.GetInt16("craftProcessing"); craftProcessing = reader.GetInt16("craftProcessing");

View File

@ -1,6 +1,6 @@
using FFXIVClassic_Map_Server; using FFXIVClassic_Map_Server;
using FFXIVClassic.Common; using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.packets;
using FFXIVClassic_Map_Server.Actors; using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.lua; using FFXIVClassic_Map_Server.lua;
using FFXIVClassic_Map_Server.packets.send.actor; using FFXIVClassic_Map_Server.packets.send.actor;
@ -12,66 +12,34 @@ using System.Threading.Tasks;
namespace FFXIVClassic_Map_Server.dataobjects namespace FFXIVClassic_Map_Server.dataobjects
{ {
class ConnectedPlayer class Session
{ {
public uint actorID = 0; public uint id = 0;
Player playerActor; Player playerActor;
public List<Actor> actorInstanceList = new List<Actor>(); public List<Actor> actorInstanceList = new List<Actor>();
public uint languageCode = 1; public uint languageCode = 1;
private ClientConnection zoneConnection;
private ClientConnection chatConnection;
private uint lastPingPacket = Utils.UnixTimeStampUTC(); private uint lastPingPacket = Utils.UnixTimeStampUTC();
public bool isUpdatesLocked = true;
public string errorMessage = ""; public string errorMessage = "";
public ConnectedPlayer(uint actorId) public Session(uint sessionId)
{ {
this.actorID = actorId; this.id = sessionId;
playerActor = new Player(this, actorId); playerActor = new Player(this, sessionId);
actorInstanceList.Add(playerActor);
} }
public void SetConnection(int type, ClientConnection conn) public void QueuePacket(List<SubPacket> packets)
{ {
conn.connType = type; foreach (SubPacket s in packets)
switch (type) QueuePacket(s);
{
case BasePacket.TYPE_ZONE:
zoneConnection = conn;
break;
case BasePacket.TYPE_CHAT:
chatConnection = conn;
break;
}
} }
public bool IsClientConnectionsReady() public void QueuePacket(SubPacket subPacket)
{ {
return (zoneConnection != null && chatConnection != null); subPacket.SetTargetId(id);
} Server.GetWorldConnection().QueuePacket(subPacket);
public void Disconnect()
{
zoneConnection.Disconnect();
chatConnection.Disconnect();
}
public bool IsDisconnected()
{
return (!zoneConnection.IsConnected() && !chatConnection.IsConnected());
}
public void QueuePacket(BasePacket basePacket)
{
zoneConnection.QueuePacket(basePacket);
}
public void QueuePacket(SubPacket subPacket, bool isAuthed, bool isEncrypted)
{
zoneConnection.QueuePacket(subPacket, isAuthed, isEncrypted);
} }
public Player GetActor() public Player GetActor()
@ -98,6 +66,9 @@ namespace FFXIVClassic_Map_Server.dataobjects
public void UpdatePlayerActorPosition(float x, float y, float z, float rot, ushort moveState) public void UpdatePlayerActorPosition(float x, float y, float z, float rot, ushort moveState)
{ {
if (isUpdatesLocked)
return;
playerActor.oldPositionX = playerActor.positionX; playerActor.oldPositionX = playerActor.positionX;
playerActor.oldPositionY = playerActor.positionY; playerActor.oldPositionY = playerActor.positionY;
playerActor.oldPositionZ = playerActor.positionZ; playerActor.oldPositionZ = playerActor.positionZ;
@ -109,12 +80,15 @@ namespace FFXIVClassic_Map_Server.dataobjects
playerActor.rotation = rot; playerActor.rotation = rot;
playerActor.moveState = moveState; playerActor.moveState = moveState;
GetActor().zone.UpdateActorPosition(GetActor()); GetActor().GetZone().UpdateActorPosition(GetActor());
} }
long lastMilis = 0;
public void UpdateInstance(List<Actor> list) public void UpdateInstance(List<Actor> list)
{ {
if (isUpdatesLocked)
return;
List<BasePacket> basePackets = new List<BasePacket>(); List<BasePacket> basePackets = new List<BasePacket>();
List<SubPacket> RemoveActorSubpackets = new List<SubPacket>(); List<SubPacket> RemoveActorSubpackets = new List<SubPacket>();
List<SubPacket> posUpdateSubpackets = new List<SubPacket>(); List<SubPacket> posUpdateSubpackets = new List<SubPacket>();
@ -124,7 +98,7 @@ namespace FFXIVClassic_Map_Server.dataobjects
{ {
if (!list.Contains(actorInstanceList[i])) if (!list.Contains(actorInstanceList[i]))
{ {
GetActor().QueuePacket(RemoveActorPacket.BuildPacket(playerActor.actorId, actorInstanceList[i].actorId)); QueuePacket(RemoveActorPacket.BuildPacket(actorInstanceList[i].actorId));
actorInstanceList.RemoveAt(i); actorInstanceList.RemoveAt(i);
} }
} }
@ -139,13 +113,18 @@ namespace FFXIVClassic_Map_Server.dataobjects
if (actorInstanceList.Contains(actor)) if (actorInstanceList.Contains(actor))
{ {
GetActor().QueuePacket(actor.CreatePositionUpdatePacket(playerActor.actorId)); //Don't send for static characters (npcs)
if (actor is Character && ((Character)actor).isStatic)
continue;
QueuePacket(actor.CreatePositionUpdatePacket());
} }
else else
{ {
GetActor().QueuePacket(actor.GetSpawnPackets(playerActor.actorId, 1)); QueuePacket(actor.GetSpawnPackets(playerActor, 1));
GetActor().QueuePacket(actor.GetInitPackets(playerActor.actorId));
GetActor().QueuePacket(actor.GetSetEventStatusPackets(playerActor.actorId)); QueuePacket(actor.GetInitPackets());
QueuePacket(actor.GetSetEventStatusPackets());
actorInstanceList.Add(actor); actorInstanceList.Add(actor);
if (actor is Npc) if (actor is Npc)
@ -163,5 +142,10 @@ namespace FFXIVClassic_Map_Server.dataobjects
actorInstanceList.Clear(); actorInstanceList.Clear();
} }
public void LockUpdates(bool f)
{
isUpdatesLocked = f;
}
} }
} }

View File

@ -0,0 +1,67 @@
using System;
using System.Net.Sockets;
using FFXIVClassic.Common;
using System.Collections.Concurrent;
using System.Net;
using System.Collections.Generic;
using FFXIVClassic_Map_Server.packets.WorldPackets.Send;
namespace FFXIVClassic_Map_Server.dataobjects
{
class ZoneConnection
{
//Connection stuff
public Socket socket;
public byte[] buffer;
private BlockingCollection<SubPacket> SendPacketQueue = new BlockingCollection<SubPacket>(1000);
public int lastPartialSize = 0;
public void QueuePacket(SubPacket subpacket)
{
SendPacketQueue.Add(subpacket);
}
public void FlushQueuedSendPackets()
{
if (!socket.Connected)
return;
while (SendPacketQueue.Count > 0)
{
SubPacket packet = SendPacketQueue.Take();
byte[] packetBytes = packet.GetBytes();
try
{
socket.Send(packetBytes);
}
catch (Exception e)
{ Program.Log.Error("Weird case, socket was d/ced: {0}", e); }
}
}
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);
}
public void RequestZoneChange(uint sessionId, uint destinationZoneId, byte spawnType, float spawnX, float spawnY, float spawnZ, float spawnRotation)
{
WorldRequestZoneChangePacket.BuildPacket(sessionId, destinationZoneId, spawnType, spawnX, spawnY, spawnZ, spawnRotation).DebugPrintSubPacket();
QueuePacket(WorldRequestZoneChangePacket.BuildPacket(sessionId, destinationZoneId, spawnType, spawnX, spawnY, spawnZ, spawnRotation));
}
}
}

View File

@ -1,4 +1,4 @@
using FFXIVClassic_Map_Server.packets; 
using FFXIVClassic_Map_Server.actors.director; using FFXIVClassic_Map_Server.actors.director;
using FFXIVClassic_Map_Server.Actors; using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.dataobjects; using FFXIVClassic_Map_Server.dataobjects;
@ -13,200 +13,425 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Diagnostics; using System.Diagnostics;
using FFXIVClassic_Map_Server.lua; using FFXIVClassic_Map_Server.lua;
using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.actors.area;
using System.Threading;
namespace FFXIVClassic_Map_Server.lua namespace FFXIVClassic_Map_Server.lua
{ {
class LuaEngine class LuaEngine
{ {
const string FILEPATH_PLAYER = "./scripts/player.lua"; public const string FILEPATH_PLAYER = "./scripts/player.lua";
const string FILEPATH_ZONE = "./scripts/zones/{0}/zone.lua"; public const string FILEPATH_ZONE = "./scripts/unique/{0}/zone.lua";
const string FILEPATH_COMMANDS = "./scripts/commands/{0}.lua"; public const string FILEPATH_CONTENT = "./scripts/content/{0}.lua";
const string FILEPATH_DIRECTORS = "./scripts/directors/{0}.lua"; public const string FILEPATH_COMMANDS = "./scripts/commands/{0}.lua";
const string FILEPATH_NPCS = "./scripts/zones/{0}/npcs/{1}.lua"; public const string FILEPATH_DIRECTORS = "./scripts/directors/{0}.lua";
public const string FILEPATH_NPCS = "./scripts/unique/{0}/{1}/{2}.lua";
public const string FILEPATH_QUEST = "./scripts/quests/{0}/{1}.lua";
public LuaEngine() private static LuaEngine mThisEngine;
private Dictionary<Coroutine, ulong> mSleepingOnTime = new Dictionary<Coroutine, ulong>();
private Dictionary<string, List<Coroutine>> mSleepingOnSignal = new Dictionary<string, List<Coroutine>>();
private Dictionary<uint, Coroutine> mSleepingOnPlayerEvent = new Dictionary<uint, Coroutine>();
private Timer luaTimer;
private LuaEngine()
{ {
UserData.RegistrationPolicy = InteropRegistrationPolicy.Automatic; UserData.RegistrationPolicy = InteropRegistrationPolicy.Automatic;
luaTimer = new Timer(new TimerCallback(PulseSleepingOnTime),
null, TimeSpan.Zero, TimeSpan.FromMilliseconds(50));
} }
public static List<LuaParam> DoActorInstantiate(Player player, Actor target) public static LuaEngine GetInstance()
{ {
string luaPath; if (mThisEngine == null)
mThisEngine = new LuaEngine();
if (target is Npc) return mThisEngine;
}
public void AddWaitCoroutine(Coroutine coroutine, float seconds)
{
ulong time = Utils.MilisUnixTimeStampUTC() + (ulong)(seconds * 1000);
mSleepingOnTime.Add(coroutine, time);
}
public void AddWaitSignalCoroutine(Coroutine coroutine, string signal)
{
if (!mSleepingOnSignal.ContainsKey(signal))
mSleepingOnSignal.Add(signal, new List<Coroutine>());
mSleepingOnSignal[signal].Add(coroutine);
}
public void AddWaitEventCoroutine(Player player, Coroutine coroutine)
{
if (!mSleepingOnPlayerEvent.ContainsKey(player.actorId))
mSleepingOnPlayerEvent.Add(player.actorId, coroutine);
}
public void PulseSleepingOnTime(object state)
{
ulong currentTime = Utils.MilisUnixTimeStampUTC();
List<Coroutine> mToAwake = new List<Coroutine>();
foreach (KeyValuePair<Coroutine, ulong> entry in mSleepingOnTime)
{ {
luaPath = String.Format(FILEPATH_NPCS, target.zoneId, target.GetName()); if (entry.Value <= currentTime)
if (File.Exists(luaPath)) mToAwake.Add(entry.Key);
}
foreach (Coroutine key in mToAwake)
{
mSleepingOnTime.Remove(key);
DynValue value = key.Resume();
ResolveResume(null, key, value);
}
}
public void OnSignal(string signal)
{
List<Coroutine> mToAwake = new List<Coroutine>();
if (mSleepingOnSignal.ContainsKey(signal))
{
mToAwake.AddRange(mSleepingOnSignal[signal]);
mSleepingOnSignal.Remove(signal);
}
foreach (Coroutine key in mToAwake)
{
DynValue value = key.Resume();
ResolveResume(null, key, value);
}
}
public void OnEventUpdate(Player player, List<LuaParam> args)
{
if (mSleepingOnPlayerEvent.ContainsKey(player.actorId))
{
try
{ {
LuaScript script = LoadScript(luaPath); Coroutine coroutine = mSleepingOnPlayerEvent[player.actorId];
mSleepingOnPlayerEvent.Remove(player.actorId);
DynValue value = coroutine.Resume(LuaUtils.CreateLuaParamObjectList(args));
ResolveResume(player, coroutine, value);
}
catch (ScriptRuntimeException e)
{
LuaEngine.SendError(player, String.Format("OnEventUpdated: {0}", e.DecoratedMessage));
player.EndEvent();
}
}
else
player.EndEvent();
}
if (script == null) private static string GetScriptPath(Actor target)
return null; {
if (target is Player)
{
return String.Format(FILEPATH_PLAYER);
}
else if (target is Npc)
{
return null;
}
else if (target is Command)
{
return String.Format(FILEPATH_COMMANDS, target.GetName());
}
else if (target is Director)
{
return String.Format(FILEPATH_DIRECTORS, ((Director)target).GetScriptPath());
}
else if (target is PrivateAreaContent)
{
return String.Format(FILEPATH_CONTENT, ((PrivateAreaContent)target).GetPrivateAreaName());
}
else if (target is Area)
{
return String.Format(FILEPATH_ZONE, ((Area)target).zoneName);
}
else if (target is Quest)
{
string initial = ((Quest)target).actorName.Substring(0, 3);
string questName = ((Quest)target).actorName;
return String.Format(FILEPATH_QUEST, initial, questName);
}
else
return "";
}
DynValue result = script.Call(script.Globals["init"], target); private List<LuaParam> CallLuaFunctionNpcForReturn(Player player, Npc target, string funcName, bool optional, params object[] args)
{
object[] args2 = new object[args.Length + (player == null ? 1 : 2)];
Array.Copy(args, 0, args2, (player == null ? 1 : 2), args.Length);
if (player != null)
{
args2[0] = player;
args2[1] = target;
}
else
args2[0] = target;
LuaScript parent = null, child = null;
if (File.Exists("./scripts/base/" + target.classPath + ".lua"))
parent = LuaEngine.LoadScript("./scripts/base/" + target.classPath + ".lua");
Area area = target.zone;
if (area is PrivateArea)
{
if (File.Exists(String.Format("./scripts/unique/{0}/privatearea/{1}_{2}/{3}/{4}.lua", area.zoneName, ((PrivateArea)area).GetPrivateAreaName(), ((PrivateArea)area).GetPrivateAreaType(), target.className, target.GetUniqueId())))
child = LuaEngine.LoadScript(String.Format("./scripts/unique/{0}/privatearea/{1}_{2}/{3}/{4}.lua", area.zoneName, ((PrivateArea)area).GetPrivateAreaName(), ((PrivateArea)area).GetPrivateAreaType(), target.className, target.GetUniqueId()));
}
else
{
if (File.Exists(String.Format("./scripts/unique/{0}/{1}/{2}.lua", area.zoneName, target.className, target.GetUniqueId())))
child = LuaEngine.LoadScript(String.Format("./scripts/unique/{0}/{1}/{2}.lua", area.zoneName, target.className, target.GetUniqueId()));
}
if (parent == null && child == null)
{
LuaEngine.SendError(player, String.Format("ERROR: Could not find script for actor {0}.", target.GetName()));
}
//Run Script
DynValue result;
if (child != null && child.Globals[funcName] != null)
result = child.Call(child.Globals[funcName], args2);
else if (parent != null && parent.Globals[funcName] != null)
result = parent.Call(parent.Globals[funcName], args2);
else
return null;
List<LuaParam> lparams = LuaUtils.CreateLuaParamList(result);
return lparams;
}
private void CallLuaFunctionNpc(Player player, Npc target, string funcName, bool optional, params object[] args)
{
object[] args2 = new object[args.Length + (player == null ? 1:2)];
Array.Copy(args, 0, args2, (player == null ? 1 : 2), args.Length);
if (player != null)
{
args2[0] = player;
args2[1] = target;
}
else
args2[0] = target;
LuaScript parent = null, child = null;
if (File.Exists("./scripts/base/" + target.classPath + ".lua"))
parent = LuaEngine.LoadScript("./scripts/base/" + target.classPath + ".lua");
Area area = target.zone;
if (area is PrivateArea)
{
if (File.Exists(String.Format("./scripts/unique/{0}/privatearea/{1}_{2}/{3}/{4}.lua", area.zoneName, ((PrivateArea)area).GetPrivateAreaName(), ((PrivateArea)area).GetPrivateAreaType(), target.className, target.GetUniqueId())))
child = LuaEngine.LoadScript(String.Format("./scripts/unique/{0}/privatearea/{1}_{2}/{3}/{4}.lua", area.zoneName, ((PrivateArea)area).GetPrivateAreaName(), ((PrivateArea)area).GetPrivateAreaType(), target.className, target.GetUniqueId()));
}
else
{
if (File.Exists(String.Format("./scripts/unique/{0}/{1}/{2}.lua", area.zoneName, target.className, target.GetUniqueId())))
child = LuaEngine.LoadScript(String.Format("./scripts/unique/{0}/{1}/{2}.lua", area.zoneName, target.className, target.GetUniqueId()));
}
if (parent == null && child == null)
{
LuaEngine.SendError(player, String.Format("Could not find script for actor {0}.", target.GetName()));
return;
}
//Run Script
Coroutine coroutine = null;
if (child != null && !child.Globals.Get(funcName).IsNil())
coroutine = child.CreateCoroutine(child.Globals[funcName]).Coroutine;
else if (parent != null && parent.Globals.Get(funcName) != null && !parent.Globals.Get(funcName).IsNil())
coroutine = parent.CreateCoroutine(parent.Globals[funcName]).Coroutine;
if (coroutine != null)
{
try
{
DynValue value = coroutine.Resume(args2);
ResolveResume(player, coroutine, value);
}
catch (ScriptRuntimeException e)
{
SendError(player, e.DecoratedMessage);
}
}
}
public List<LuaParam> CallLuaFunctionForReturn(Player player, Actor target, string funcName, bool optional, params object[] args)
{
//Need a seperate case for NPCs cause that child/parent thing.
if (target is Npc)
return CallLuaFunctionNpcForReturn(player, (Npc)target, funcName, optional, args);
object[] args2 = new object[args.Length + (player == null ? 1 : 2)];
Array.Copy(args, 0, args2, (player == null ? 1 : 2), args.Length);
if (player != null)
{
args2[0] = player;
args2[1] = target;
}
else
args2[0] = target;
string luaPath = GetScriptPath(target);
LuaScript script = LoadScript(luaPath);
if (script != null)
{
if (!script.Globals.Get(funcName).IsNil())
{
//Run Script
DynValue result = script.Call(script.Globals[funcName], args2);
List<LuaParam> lparams = LuaUtils.CreateLuaParamList(result); List<LuaParam> lparams = LuaUtils.CreateLuaParamList(result);
return lparams; return lparams;
} }
else else
{ {
SendError(player, String.Format("ERROR: Could not find script for actor {0}.", target.GetName())); if (!optional)
return null; SendError(player, String.Format("Could not find function '{0}' for actor {1}.", funcName, target.GetName()));
} }
} }
else
{
if (!optional)
SendError(player, String.Format("Could not find script for actor {0}.", target.GetName()));
}
return null; return null;
} }
public static Coroutine DoActorOnEventStarted(Player player, Actor target, EventStartPacket eventStart) public List<LuaParam> CallLuaFunctionForReturn(string path, string funcName, bool optional, params object[] args)
{ {
string luaPath; string luaPath = path;
LuaScript script = LoadScript(luaPath);
if (target is Command) if (script != null)
{ {
luaPath = String.Format(FILEPATH_COMMANDS, target.GetName()); if (!script.Globals.Get(funcName).IsNil())
{
//Run Script
DynValue result = script.Call(script.Globals[funcName], args);
List<LuaParam> lparams = LuaUtils.CreateLuaParamList(result);
return lparams;
}
} }
else if (target is Director) return null;
{
luaPath = String.Format(FILEPATH_DIRECTORS, target.GetName());
}
else
luaPath = String.Format(FILEPATH_NPCS, target.zoneId, target.GetName());
if (File.Exists(luaPath))
{
LuaScript script = LoadScript(luaPath);
if (script == null)
return null;
if (!script.Globals.Get("onEventStarted").IsNil())
return script.CreateCoroutine(script.Globals["onEventStarted"]).Coroutine;
else
return null;
}
else
{
SendError(player, String.Format("ERROR: Could not find script for actor {0}.", target.GetName()));
return null;
}
} }
public static void DoActorOnSpawn(Player player, Npc target) public void CallLuaFunction(Player player, Actor target, string funcName, bool optional, params object[] args)
{
string luaPath = String.Format(FILEPATH_NPCS, target.zoneId, target.GetName());
if (File.Exists(luaPath))
{
LuaScript script = LoadScript(luaPath);
if (script == null)
return;
//Run Script
if (!script.Globals.Get("onSpawn").IsNil())
script.Call(script.Globals["onSpawn"], player, target);
}
else
{
SendError(player, String.Format("ERROR: Could not find script for actor {0}.", target.GetName()));
}
}
public static void DoActorOnEventUpdated(Player player, Actor target, EventUpdatePacket eventUpdate)
{ {
//Need a seperate case for NPCs cause that child/parent thing.
if (target is Npc) if (target is Npc)
{ {
((Npc)target).DoEventUpdate(player, eventUpdate); CallLuaFunctionNpc(player, (Npc)target, funcName, optional, args);
return; return;
} }
string luaPath; object[] args2 = new object[args.Length + 2];
Array.Copy(args, 0, args2, 2, args.Length);
args2[0] = player;
args2[1] = target;
if (target is Command) string luaPath = GetScriptPath(target);
luaPath = String.Format(FILEPATH_COMMANDS, target.GetName()); LuaScript script = LoadScript(luaPath);
else if (target is Director) if (script != null)
luaPath = String.Format(FILEPATH_DIRECTORS, target.GetName());
else
luaPath = String.Format(FILEPATH_NPCS, target.zoneId, target.GetName());
if (File.Exists(luaPath))
{ {
LuaScript script = LoadScript(luaPath); if (!script.Globals.Get(funcName).IsNil())
{
if (script == null) Coroutine coroutine = script.CreateCoroutine(script.Globals[funcName]).Coroutine;
return; DynValue value = coroutine.Resume(args2);
ResolveResume(player, coroutine, value);
//Have to Do this to combine LuaParams }
List<Object> objects = new List<Object>(); else
objects.Add(player); {
objects.Add(target); if (!optional)
objects.Add(eventUpdate.val2); SendError(player, String.Format("Could not find function '{0}' for actor {1}.", funcName, target.GetName()));
objects.AddRange(LuaUtils.CreateLuaParamObjectList(eventUpdate.luaParams)); }
//Run Script
if (!script.Globals.Get("onEventUpdate").IsNil())
script.Call(script.Globals["onEventUpdate"], objects.ToArray());
} }
else else
{ {
SendError(player, String.Format("ERROR: Could not find script for actor {0}.", target.GetName())); if (!(target is Area) && !optional)
SendError(player, String.Format("Could not find script for actor {0}.", target.GetName()));
} }
} }
public static void OnZoneIn(Player player) public void EventStarted(Player player, Actor target, EventStartPacket eventStart)
{ {
string luaPath = String.Format(FILEPATH_ZONE, player.GetZone().actorId); List<LuaParam> lparams = eventStart.luaParams;
lparams.Insert(0, new LuaParam(2, eventStart.triggerName));
if (File.Exists(luaPath)) if (mSleepingOnPlayerEvent.ContainsKey(player.actorId))
{ {
LuaScript script = LoadScript(luaPath); Coroutine coroutine = mSleepingOnPlayerEvent[player.actorId];
mSleepingOnPlayerEvent.Remove(player.actorId);
if (script == null) try{
return; DynValue value = coroutine.Resume();
ResolveResume(null, coroutine, value);
//Run Script }
if (!script.Globals.Get("onZoneIn").IsNil()) catch (ScriptRuntimeException e)
script.Call(script.Globals["onZoneIn"], player); {
LuaEngine.SendError(player, String.Format("OnEventStarted: {0}", e.DecoratedMessage));
player.EndEvent();
}
}
else
{
if (target is Director)
((Director)target).OnEventStart(player, LuaUtils.CreateLuaParamObjectList(lparams));
else
CallLuaFunction(player, target, "onEventStarted", false, LuaUtils.CreateLuaParamObjectList(lparams));
} }
} }
public static void OnBeginLogin(Player player) public DynValue ResolveResume(Player player, Coroutine coroutine, DynValue value)
{ {
if (File.Exists(FILEPATH_PLAYER)) if (value == null || value.IsVoid())
return value;
if (player != null && value.String != null && value.String.Equals("_WAIT_EVENT"))
{ {
LuaScript script = LoadScript(FILEPATH_PLAYER); GetInstance().AddWaitEventCoroutine(player, coroutine);
if (script == null)
return;
//Run Script
if (!script.Globals.Get("onBeginLogin").IsNil())
script.Call(script.Globals["onBeginLogin"], player);
} }
} else if (value.Tuple != null && value.Tuple.Length >= 1 && value.Tuple[0].String != null)
public static void OnLogin(Player player)
{
if (File.Exists(FILEPATH_PLAYER))
{ {
LuaScript script = LoadScript(FILEPATH_PLAYER); switch (value.Tuple[0].String)
{
if (script == null) case "_WAIT_TIME":
return; GetInstance().AddWaitCoroutine(coroutine, (float)value.Tuple[1].Number);
break;
//Run Script case "_WAIT_SIGNAL":
if (!script.Globals.Get("onLogin").IsNil()) GetInstance().AddWaitSignalCoroutine(coroutine, (string)value.Tuple[1].String);
script.Call(script.Globals["onLogin"], player); break;
case "_WAIT_EVENT":
GetInstance().AddWaitEventCoroutine((Player)value.Tuple[1].UserData.Object, coroutine);
break;
default:
return value;
}
} }
return value;
} }
#region RunGMCommand #region RunGMCommand
public static void RunGMCommand(Player player, String cmd, string[] param, bool help = false) public static void RunGMCommand(Player player, String cmd, string[] param, bool help = false)
{ {
bool playerNull = player == null;
if (playerNull && param.Length >= 3)
player = Server.GetWorldManager().GetPCInWorld(param[1] + " " + param[2]);
// load from scripts/commands/gm/ directory // load from scripts/commands/gm/ directory
var path = String.Format("./scripts/commands/gm/{0}.lua", cmd.ToString().ToLower()); var path = String.Format("./scripts/commands/gm/{0}.lua", cmd.ToLower());
// check if the file exists // check if the file exists
if (File.Exists(path)) if (File.Exists(path))
@ -290,7 +515,7 @@ namespace FFXIVClassic_Map_Server.lua
// we'll push our lua params here // we'll push our lua params here
List<object> LuaParam = new List<object>(); List<object> LuaParam = new List<object>();
var i = 0; var i = playerNull ? 2 : 0;
for (; i < parameters.Length; ++i) for (; i < parameters.Length; ++i)
{ {
try try
@ -326,10 +551,14 @@ namespace FFXIVClassic_Map_Server.lua
// the script can double check the player exists, we'll push them anyways // the script can double check the player exists, we'll push them anyways
LuaParam.Insert(0, player); LuaParam.Insert(0, player);
// push the arg count too // push the arg count too
LuaParam.Insert(1, i); LuaParam.Insert(1, i - (playerNull ? 2 : 0));
// run the script // run the script
script.Call(script.Globals["onTrigger"], LuaParam.ToArray()); //script.Call(script.Globals["onTrigger"], LuaParam.ToArray());
Coroutine coroutine = script.CreateCoroutine(script.Globals["onTrigger"]).Coroutine;
DynValue value = coroutine.Resume(LuaParam.ToArray());
GetInstance().ResolveResume(player, coroutine, value);
return; return;
} }
} }
@ -338,17 +567,20 @@ namespace FFXIVClassic_Map_Server.lua
} }
#endregion #endregion
public static LuaScript LoadScript(string filename) public static LuaScript LoadScript(string path)
{ {
if (!File.Exists(path))
return null;
LuaScript script = LoadGlobals(); LuaScript script = LoadGlobals();
try try
{ {
script.DoFile(filename); script.DoFile(path);
} }
catch (SyntaxErrorException e) catch (SyntaxErrorException e)
{ {
Program.Log.Error("LUAERROR: {0}.", e.DecoratedMessage); Program.Log.Error("{0}.", e.DecoratedMessage);
return null; return null;
} }
return script; return script;
@ -362,8 +594,11 @@ namespace FFXIVClassic_Map_Server.lua
((FileSystemScriptLoader)script.Options.ScriptLoader).ModulePaths = FileSystemScriptLoader.UnpackStringPaths("./scripts/?;./scripts/?.lua"); ((FileSystemScriptLoader)script.Options.ScriptLoader).ModulePaths = FileSystemScriptLoader.UnpackStringPaths("./scripts/?;./scripts/?.lua");
script.Globals["GetWorldManager"] = (Func<WorldManager>)Server.GetWorldManager; script.Globals["GetWorldManager"] = (Func<WorldManager>)Server.GetWorldManager;
script.Globals["GetStaticActor"] = (Func<string, Actor>)Server.GetStaticActors; script.Globals["GetStaticActor"] = (Func<string, Actor>)Server.GetStaticActors;
script.Globals["GetStaticActorById"] = (Func<uint, Actor>)Server.GetStaticActors;
script.Globals["GetWorldMaster"] = (Func<Actor>)Server.GetWorldManager().GetActor; script.Globals["GetWorldMaster"] = (Func<Actor>)Server.GetWorldManager().GetActor;
script.Globals["GetItemGamedata"] = (Func<uint, Item>)Server.GetItemGamedata; script.Globals["GetItemGamedata"] = (Func<uint, ItemData>)Server.GetItemGamedata;
script.Globals["GetGuildleveGamedata"] = (Func<uint, GuildleveData>)Server.GetGuildleveGamedata;
script.Globals["GetLuaInstance"] = (Func<LuaEngine>)LuaEngine.GetInstance;
script.Options.DebugPrint = s => { Program.Log.Debug(s); }; script.Options.DebugPrint = s => { Program.Log.Debug(s); };
return script; return script;
@ -371,53 +606,14 @@ namespace FFXIVClassic_Map_Server.lua
public static void SendError(Player player, string message) public static void SendError(Player player, string message)
{ {
message = "[LuaError] " + message;
if (player == null)
return;
List<SubPacket> SendError = new List<SubPacket>(); List<SubPacket> SendError = new List<SubPacket>();
SendError.Add(EndEventPacket.BuildPacket(player.actorId, player.currentEventOwner, player.currentEventName));
player.SendMessage(SendMessagePacket.MESSAGE_TYPE_SYSTEM_ERROR, "", message); player.SendMessage(SendMessagePacket.MESSAGE_TYPE_SYSTEM_ERROR, "", message);
player.playerSession.QueuePacket(BasePacket.CreatePacket(SendError, true, false)); player.QueuePacket(EndEventPacket.BuildPacket(player.actorId, player.currentEventOwner, player.currentEventName));
} }
internal static void DoDirectorOnTalked(Director director, Player player, Npc npc)
{
string luaPath = String.Format(FILEPATH_DIRECTORS, director.GetName());
if (File.Exists(luaPath))
{
LuaScript script = LoadScript(luaPath);
if (script == null)
return;
//Run Script
if (!script.Globals.Get("onTalked").IsNil())
script.Call(script.Globals["onTalked"], player, npc);
}
else
{
SendError(player, String.Format("ERROR: Could not find script for director {0}.", director.GetName()));
}
}
internal static void DoDirectorOnCommand(Director director, Player player, Command command)
{
string luaPath = String.Format(FILEPATH_DIRECTORS, director.GetName());
if (File.Exists(luaPath))
{
LuaScript script = LoadScript(luaPath);
if (script == null)
return;
//Run Script
if (!script.Globals.Get("onCommand").IsNil())
script.Call(script.Globals["onCommand"], player, command);
}
else
{
SendError(player, String.Format("ERROR: Could not find script for director {0}.", director.GetName()));
}
}
} }
} }

View File

@ -1,16 +0,0 @@
namespace FFXIVClassic_Map_Server.lua
{
class LuaEvent
{
public static void GetStep()
{
}
public static void GetParam()
{
}
}
}

View File

@ -1,19 +0,0 @@
using FFXIVClassic_Map_Server.Actors;
using MoonSharp.Interpreter;
namespace FFXIVClassic_Map_Server.lua
{
[MoonSharpUserData]
class LuaNpc
{
private Npc npc;
public LuaNpc(Npc npc)
{
this.npc = npc;
}
}
}

View File

@ -1,75 +0,0 @@
using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.packets.send;
using MoonSharp.Interpreter;
using System.Collections.Generic;
namespace FFXIVClassic_Map_Server.lua
{
[MoonSharpUserData]
class LuaPlayer
{
private Player player;
public LuaPlayer(Player player)
{
this.player = player;
}
public void SetMusic(ushort musicID, ushort playMode)
{
player.playerSession.QueuePacket(SetMusicPacket.BuildPacket(player.actorId, musicID, playMode), true, false);
}
public void SetWeather(ushort weatherID)
{
player.playerSession.QueuePacket(SetWeatherPacket.BuildPacket(player.actorId, weatherID, 1), true, false);
}
public void IssueChocobo(int appearanceId, string name)
{
player.IssueChocobo((byte) appearanceId, name);
}
public void GetParameter(string paramName)
{
}
public void SetParameter(string paramName, object value, string uiToRefresh)
{
}
public void GetAttributePoints()
{
}
public void SetAttributePoints(int str, int vit, int dex, int inte, int min, int pie)
{
}
public void Logout()
{
player.playerSession.QueuePacket(LogoutPacket.BuildPacket(player.actorId), true, false);
}
public void QuitGame()
{
player.playerSession.QueuePacket(QuitPacket.BuildPacket(player.actorId), true, false);
}
public void RunEvent(string functionName, params object[] parameters)
{
List<LuaParam> lParams = LuaUtils.CreateLuaParamList(parameters);
// player.playerSession.QueuePacket(RunEventFunctionPacket.BuildPacket(player.actorId, player.eventCurrentOwner, player.eventCurrentStarter, functionName, lParams), true, false);
}
public void EndEvent()
{
// player.playerSession.QueuePacket(EndEventPacket.BuildPacket(player.actorId, player.eventCurrentOwner, player.eventCurrentStarter), true, false);
}
}
}

View File

@ -253,6 +253,9 @@ namespace FFXIVClassic_Map_Server
{ {
List<LuaParam> luaParams = new List<LuaParam>(); List<LuaParam> luaParams = new List<LuaParam>();
if (fromScript == null)
return luaParams;
if (fromScript.Type == DataType.Tuple) if (fromScript.Type == DataType.Tuple)
{ {
foreach (DynValue d in fromScript.Tuple) foreach (DynValue d in fromScript.Tuple)

View File

@ -1,163 +0,0 @@
using System;
using System.Runtime.InteropServices;
using FFXIVClassic.Common;
using NLog;
using NLog.Targets;
namespace FFXIVClassic_Map_Server.packets
{
[StructLayout(LayoutKind.Sequential)]
public struct SubPacketHeader
{
public ushort subpacketSize;
public ushort type;
public uint sourceId;
public uint targetId;
public uint unknown1;
}
[StructLayout(LayoutKind.Sequential)]
public struct GameMessageHeader
{
public ushort unknown4; //Always 0x14
public ushort opcode;
public uint unknown5;
public uint timestamp;
public uint unknown6;
}
public class SubPacket
{
public const int SUBPACKET_SIZE = 0x10;
public const int GAMEMESSAGE_SIZE = 0x10;
private static readonly Logger logger = LogManager.GetCurrentClassLogger();
public byte[] data;
public GameMessageHeader gameMessage;
public SubPacketHeader header;
public unsafe SubPacket(byte[] bytes, ref int offset)
{
if (bytes.Length < offset + SUBPACKET_SIZE)
throw new OverflowException("Packet Error: Subpacket was too small");
fixed (byte* pdata = &bytes[offset])
{
header = (SubPacketHeader) Marshal.PtrToStructure(new IntPtr(pdata), typeof(SubPacketHeader));
}
if (header.type == 0x3)
{
fixed (byte* pdata = &bytes[offset + SUBPACKET_SIZE])
{
gameMessage =
(GameMessageHeader) Marshal.PtrToStructure(new IntPtr(pdata), typeof(GameMessageHeader));
}
}
if (bytes.Length < offset + header.subpacketSize)
throw new OverflowException("Packet Error: Subpacket size didn't equal subpacket data");
if (header.type == 0x3)
{
data = new byte[header.subpacketSize - SUBPACKET_SIZE - GAMEMESSAGE_SIZE];
Array.Copy(bytes, offset + SUBPACKET_SIZE + GAMEMESSAGE_SIZE, data, 0, data.Length);
}
else
{
data = new byte[header.subpacketSize - SUBPACKET_SIZE];
Array.Copy(bytes, offset + SUBPACKET_SIZE, data, 0, data.Length);
}
offset += header.subpacketSize;
}
public SubPacket(ushort opcode, uint sourceId, uint targetId, byte[] data)
{
header = new SubPacketHeader();
gameMessage = new GameMessageHeader();
gameMessage.opcode = opcode;
header.sourceId = sourceId;
header.targetId = targetId;
gameMessage.timestamp = Utils.UnixTimeStampUTC();
header.type = 0x03;
header.unknown1 = 0x00;
gameMessage.unknown4 = 0x14;
gameMessage.unknown5 = 0x00;
gameMessage.unknown6 = 0x00;
this.data = data;
header.subpacketSize = (ushort) (SUBPACKET_SIZE + GAMEMESSAGE_SIZE + data.Length);
}
public SubPacket(SubPacket original, uint newTargetId)
{
header = new SubPacketHeader();
gameMessage = original.gameMessage;
header.subpacketSize = original.header.subpacketSize;
header.type = original.header.type;
header.sourceId = original.header.sourceId;
header.targetId = newTargetId;
data = original.data;
}
public byte[] GetHeaderBytes()
{
var size = Marshal.SizeOf(header);
var arr = new byte[size];
var ptr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(header, ptr, true);
Marshal.Copy(ptr, arr, 0, size);
Marshal.FreeHGlobal(ptr);
return arr;
}
public byte[] GetGameMessageBytes()
{
var size = Marshal.SizeOf(gameMessage);
var arr = new byte[size];
var ptr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(gameMessage, ptr, true);
Marshal.Copy(ptr, arr, 0, size);
Marshal.FreeHGlobal(ptr);
return arr;
}
public byte[] GetBytes()
{
var outBytes = new byte[header.subpacketSize];
Array.Copy(GetHeaderBytes(), 0, outBytes, 0, SUBPACKET_SIZE);
if (header.type == 0x3)
Array.Copy(GetGameMessageBytes(), 0, outBytes, SUBPACKET_SIZE, GAMEMESSAGE_SIZE);
Array.Copy(data, 0, outBytes, SUBPACKET_SIZE + (header.type == 0x3 ? GAMEMESSAGE_SIZE : 0), data.Length);
return outBytes;
}
public void DebugPrintSubPacket()
{
#if DEBUG
logger.ColorDebug(
string.Format("Size:0x{0:X} Opcode:0x{1:X}{2}{3}", header.subpacketSize, gameMessage.opcode,
Environment.NewLine,
Utils.ByteArrayToHex(GetHeaderBytes())), ConsoleOutputColor.DarkRed);
if (header.type == 0x03)
{
logger.ColorDebug(Utils.ByteArrayToHex(GetGameMessageBytes(), SUBPACKET_SIZE),
ConsoleOutputColor.DarkRed);
logger.ColorDebug(Utils.ByteArrayToHex(data, SUBPACKET_SIZE + GAMEMESSAGE_SIZE),
ConsoleOutputColor.DarkMagenta);
}
#endif
}
}
}

View File

@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_Map_Server.packets.WorldPackets.Receive
{
class ErrorPacket
{
public uint errorCode;
public bool invalidPacket = false;
public ErrorPacket(byte[] data)
{
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryReader binReader = new BinaryReader(mem))
{
try
{
errorCode = binReader.ReadUInt32();
}
catch (Exception)
{
invalidPacket = true;
}
}
}
}
}
}

View File

@ -0,0 +1,44 @@
using FFXIVClassic_Map_Server.actors.group;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_Map_Server.packets.WorldPackets.Receive
{
class PartySyncPacket
{
public ulong partyGroupId;
public uint owner;
public uint[] memberActorIds;
public bool invalidPacket = false;
public PartySyncPacket(byte[] data)
{
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryReader binReader = new BinaryReader(mem))
{
try
{
partyGroupId = binReader.ReadUInt64();
owner = binReader.ReadUInt32();
uint numMembers = binReader.ReadUInt32();
memberActorIds = new uint[numMembers];
for (int i = 0; i < numMembers; i++)
memberActorIds[i] = binReader.ReadUInt32();
}
catch (Exception)
{
invalidPacket = true;
}
}
}
}
}
}

View File

@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_Map_Server.packets.WorldPackets.Receive
{
class SessionBeginPacket
{
public bool isLogin;
public bool invalidPacket = false;
public SessionBeginPacket(byte[] data)
{
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryReader binReader = new BinaryReader(mem))
{
try
{
isLogin = binReader.ReadByte() != 0;
}
catch (Exception)
{
invalidPacket = true;
}
}
}
}
}
}

View File

@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_Map_Server.packets.WorldPackets.Receive
{
class SessionEndPacket
{
public uint destinationZoneId;
public ushort destinationSpawnType;
public float destinationX;
public float destinationY;
public float destinationZ;
public float destinationRot;
public bool invalidPacket = false;
public SessionEndPacket(byte[] data)
{
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryReader binReader = new BinaryReader(mem))
{
try
{
destinationZoneId = binReader.ReadUInt32();
destinationSpawnType = binReader.ReadUInt16();
destinationX = binReader.ReadSingle();
destinationY = binReader.ReadSingle();
destinationZ = binReader.ReadSingle();
destinationRot = binReader.ReadSingle();
}
catch (Exception)
{
invalidPacket = true;
}
}
}
}
}
}

View File

@ -0,0 +1,30 @@
using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.dataobjects;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace FFXIVClassic_Map_Server.packets.WorldPackets.Send.Group
{
class CreateLinkshellPacket
{
public const ushort OPCODE = 0x1025;
public const uint PACKET_SIZE = 0x48;
public static SubPacket BuildPacket(Session session, string name, ushort crest, uint master)
{
byte[] data = new byte[PACKET_SIZE - 0x20];
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryWriter binWriter = new BinaryWriter(mem))
{
binWriter.Write(Encoding.ASCII.GetBytes(name), 0, Encoding.ASCII.GetByteCount(name) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(name));
binWriter.Write((UInt16)crest);
binWriter.Write((UInt32)master);
}
}
return new SubPacket(true, OPCODE, session.id, data);
}
}
}

View File

@ -0,0 +1,27 @@
using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.dataobjects;
using System;
using System.IO;
using System.Text;
namespace FFXIVClassic_Map_Server.packets.WorldPackets.Send.Group
{
class DeleteLinkshellPacket
{
public const ushort OPCODE = 0x1027;
public const uint PACKET_SIZE = 0x40;
public static SubPacket BuildPacket(Session session, string name)
{
byte[] data = new byte[PACKET_SIZE - 0x20];
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryWriter binWriter = new BinaryWriter(mem))
{
binWriter.Write(Encoding.ASCII.GetBytes(name), 0, Encoding.ASCII.GetByteCount(name) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(name));
}
}
return new SubPacket(true, OPCODE, session.id, data);
}
}
}

View File

@ -0,0 +1,32 @@
using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.dataobjects;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_Map_Server.packets.WorldPackets.Send.Group
{
class GroupInviteResultPacket
{
public const ushort OPCODE = 0x1023;
public const uint PACKET_SIZE = 0x28;
public static SubPacket BuildPacket(Session session, uint groupType, uint result)
{
byte[] data = new byte[PACKET_SIZE - 0x20];
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryWriter binWriter = new BinaryWriter(mem))
{
binWriter.Write((UInt32)groupType);
binWriter.Write((UInt32)result);
}
}
return new SubPacket(true, OPCODE, session.id, data);
}
}
}

View File

@ -0,0 +1,30 @@
using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.dataobjects;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace FFXIVClassic_Map_Server.packets.WorldPackets.Send.Group
{
class LinkshellChangePacket
{
public const ushort OPCODE = 0x1028;
public const uint PACKET_SIZE = 0x48;
public static SubPacket BuildPacket(Session session, string lsName)
{
byte[] data = new byte[PACKET_SIZE - 0x20];
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryWriter binWriter = new BinaryWriter(mem))
{
binWriter.Write(Encoding.ASCII.GetBytes(lsName), 0, Encoding.ASCII.GetByteCount(lsName) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(lsName));
}
}
return new SubPacket(true, OPCODE, session.id, data);
}
}
}

View File

@ -0,0 +1,23 @@
using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.dataobjects;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_Map_Server.packets.WorldPackets.Send.Group
{
class LinkshellInviteCancelPacket
{
public const ushort OPCODE = 0x1030;
public const uint PACKET_SIZE = 0x28;
public static SubPacket BuildPacket(Session session)
{
byte[] data = new byte[PACKET_SIZE - 0x20];
return new SubPacket(true, OPCODE, session.id, data);
}
}
}

View File

@ -0,0 +1,31 @@
using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.dataobjects;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_Map_Server.packets.WorldPackets.Send.Group
{
class LinkshellInvitePacket
{
public const ushort OPCODE = 0x1029;
public const uint PACKET_SIZE = 0x48;
public static SubPacket BuildPacket(Session session, uint actorId, string linkshellName)
{
byte[] data = new byte[PACKET_SIZE - 0x20];
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryWriter binWriter = new BinaryWriter(mem))
{
binWriter.Write((UInt32)actorId);
binWriter.Write(Encoding.ASCII.GetBytes(linkshellName), 0, Encoding.ASCII.GetByteCount(linkshellName) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(linkshellName));
}
}
return new SubPacket(true, OPCODE, session.id, data);
}
}
}

View File

@ -0,0 +1,34 @@
using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.dataobjects;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace FFXIVClassic_Map_Server.packets.WorldPackets.Send.Group
{
class LinkshellLeavePacket
{
public const ushort OPCODE = 0x1031;
public const uint PACKET_SIZE = 0x68;
public static SubPacket BuildPacket(Session session, string lsName, string kickedName, bool isKicked)
{
byte[] data = new byte[PACKET_SIZE - 0x20];
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryWriter binWriter = new BinaryWriter(mem))
{
binWriter.Write((UInt16)(isKicked ? 1 : 0));
if (kickedName != null && isKicked)
binWriter.Write(Encoding.ASCII.GetBytes(kickedName), 0, Encoding.ASCII.GetByteCount(kickedName) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(kickedName));
binWriter.Seek(0x22, SeekOrigin.Begin);
binWriter.Write(Encoding.ASCII.GetBytes(lsName), 0, Encoding.ASCII.GetByteCount(lsName) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(lsName));
}
}
return new SubPacket(true, OPCODE, session.id, data);
}
}
}

View File

@ -0,0 +1,34 @@
using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.dataobjects;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace FFXIVClassic_Map_Server.packets.WorldPackets.Send.Group
{
class LinkshellRankChangePacket
{
public const ushort OPCODE = 0x1032;
public const uint PACKET_SIZE = 0x68;
public static SubPacket BuildPacket(Session session, string name, string lsName, byte rank)
{
byte[] data = new byte[PACKET_SIZE - 0x20];
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryWriter binWriter = new BinaryWriter(mem))
{
binWriter.Write(Encoding.ASCII.GetBytes(name), 0, Encoding.ASCII.GetByteCount(name) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(name));
binWriter.Seek(0x20, SeekOrigin.Begin);
binWriter.Write(Encoding.ASCII.GetBytes(lsName), 0, Encoding.ASCII.GetByteCount(lsName) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(lsName));
binWriter.Seek(0x40, SeekOrigin.Begin);
binWriter.Write((Byte)rank);
}
}
return new SubPacket(true, OPCODE, session.id, data);
}
}
}

View File

@ -0,0 +1,41 @@
using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.dataobjects;
using System;
using System.IO;
using System.Text;
namespace FFXIVClassic_Map_Server.packets.WorldPackets.Send.Group
{
class ModifyLinkshellPacket
{
public const ushort OPCODE = 0x1026;
public const uint PACKET_SIZE = 0x60;
public static SubPacket BuildPacket(Session session, ushort changeArg, string name, string newName, ushort crest, uint master)
{
byte[] data = new byte[PACKET_SIZE - 0x20];
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryWriter binWriter = new BinaryWriter(mem))
{
binWriter.Write(Encoding.ASCII.GetBytes(name), 0, Encoding.ASCII.GetByteCount(name) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(name));
binWriter.Write((UInt16)changeArg);
switch (changeArg)
{
case 0:
binWriter.Write(Encoding.ASCII.GetBytes(newName), 0, Encoding.ASCII.GetByteCount(newName) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(newName));
break;
case 1:
binWriter.Write((UInt16)crest);
break;
case 2:
binWriter.Write((UInt32)master);
break;
}
}
}
return new SubPacket(true, OPCODE, session.id, data);
}
}
}

View File

@ -0,0 +1,45 @@
using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.dataobjects;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_Map_Server.packets.WorldPackets.Send.Group
{
class PartyInvitePacket
{
public const ushort OPCODE = 0x1022;
public const uint PACKET_SIZE = 0x48;
public static SubPacket BuildPacket(Session session, string name)
{
byte[] data = new byte[PACKET_SIZE - 0x20];
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryWriter binWriter = new BinaryWriter(mem))
{
binWriter.Write((UInt16)0);
binWriter.Write(Encoding.ASCII.GetBytes(name), 0, Encoding.ASCII.GetByteCount(name) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(name));
}
}
return new SubPacket(true, OPCODE, session.id, data);
}
public static SubPacket BuildPacket(Session session, uint actorId)
{
byte[] data = new byte[PACKET_SIZE - 0x20];
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryWriter binWriter = new BinaryWriter(mem))
{
binWriter.Write((UInt16)1);
binWriter.Write((UInt32)actorId);
}
}
return new SubPacket(true, OPCODE, session.id, data);
}
}
}

View File

@ -0,0 +1,30 @@
using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.dataobjects;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace FFXIVClassic_Map_Server.packets.WorldPackets.Send.Group
{
class PartyLeavePacket
{
public const ushort OPCODE = 0x1021;
public const uint PACKET_SIZE = 0x28;
public static SubPacket BuildPacket(Session session, bool isDisband)
{
byte[] data = new byte[PACKET_SIZE - 0x20];
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryWriter binWriter = new BinaryWriter(mem))
{
binWriter.Write((UInt16)(isDisband ? 1 : 0));
}
}
return new SubPacket(true, OPCODE, session.id, data);
}
}
}

View File

@ -0,0 +1,45 @@
using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.dataobjects;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace FFXIVClassic_Map_Server.packets.WorldPackets.Send.Group
{
class PartyModifyPacket
{
public const ushort OPCODE = 0x1020;
public const uint PACKET_SIZE = 0x48;
public static SubPacket BuildPacket(Session session, ushort command, string name)
{
byte[] data = new byte[PACKET_SIZE - 0x20];
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryWriter binWriter = new BinaryWriter(mem))
{
binWriter.Write((UInt16)command);
binWriter.Write(Encoding.ASCII.GetBytes(name), 0, Encoding.ASCII.GetByteCount(name) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(name));
}
}
return new SubPacket(true, OPCODE, session.id, data);
}
public static SubPacket BuildPacket(Session session, ushort command, uint actorId)
{
byte[] data = new byte[PACKET_SIZE - 0x20];
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryWriter binWriter = new BinaryWriter(mem))
{
binWriter.Write((UInt16)(command + 2));
binWriter.Write((UInt32)actorId);
}
}
return new SubPacket(true, OPCODE, session.id, data);
}
}
}

View File

@ -0,0 +1,27 @@
using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.dataobjects;
using System;
using System.IO;
namespace FFXIVClassic_Map_Server.packets.WorldPackets.Send
{
class SessionBeginConfirmPacket
{
public const ushort OPCODE = 0x1000;
public const uint PACKET_SIZE = 0x28;
public static SubPacket BuildPacket(Session session, ushort errorCode = 0)
{
byte[] data = new byte[PACKET_SIZE - 0x20];
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryWriter binWriter = new BinaryWriter(mem))
{
binWriter.Write((UInt32)session.id);
binWriter.Write((UInt16)errorCode);
}
}
return new SubPacket(true, OPCODE, session.id, data);
}
}
}

View File

@ -0,0 +1,28 @@
using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.dataobjects;
using System;
using System.IO;
namespace FFXIVClassic_Map_Server.packets.WorldPackets.Send
{
class SessionEndConfirmPacket
{
public const ushort OPCODE = 0x1001;
public const uint PACKET_SIZE = 0x30;
public static SubPacket BuildPacket(Session session, uint destinationZone, ushort errorCode = 0)
{
byte[] data = new byte[PACKET_SIZE - 0x20];
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryWriter binWriter = new BinaryWriter(mem))
{
binWriter.Write((UInt32)session.id);
binWriter.Write((UInt16)errorCode);
binWriter.Write((UInt32)destinationZone);
}
}
return new SubPacket(true, OPCODE, session.id, data);
}
}
}

View File

@ -0,0 +1,37 @@
using FFXIVClassic.Common;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_Map_Server.packets.WorldPackets.Send
{
class WorldRequestZoneChangePacket
{
public const ushort OPCODE = 0x1002;
public const uint PACKET_SIZE = 0x048;
public static SubPacket BuildPacket(uint sessionId, uint destinationZoneId, byte spawnType, float spawnX, float spawnY, float spawnZ, float spawnRotation)
{
byte[] data = new byte[PACKET_SIZE - 0x20];
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryWriter binWriter = new BinaryWriter(mem))
{
binWriter.Write((UInt32)sessionId);
binWriter.Write((UInt32)destinationZoneId);
binWriter.Write((UInt16)spawnType);
binWriter.Write((Single)spawnX);
binWriter.Write((Single)spawnY);
binWriter.Write((Single)spawnZ);
binWriter.Write((Single)spawnRotation);
}
}
return new SubPacket(OPCODE, sessionId, data);
}
}
}

View File

@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_Map_Server.packets.receive
{
class GroupCreatedPacket
{
public ulong groupId;
public string workString;
public bool invalidPacket = false;
public GroupCreatedPacket(byte[] data)
{
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryReader binReader = new BinaryReader(mem))
{
try{
groupId = binReader.ReadUInt64();
workString = Encoding.ASCII.GetString(binReader.ReadBytes(0x20)).Trim(new[] { '\0' });
}
catch (Exception){
invalidPacket = true;
}
}
}
}
}
}

View File

@ -3,13 +3,13 @@ using System.IO;
namespace FFXIVClassic_Map_Server.packets.receive namespace FFXIVClassic_Map_Server.packets.receive
{ {
class _0x07Packet class ZoneInCompletePacket
{ {
public bool invalidPacket = false; public bool invalidPacket = false;
public uint timestamp; public uint timestamp;
public uint unknown; public int unknown;
public _0x07Packet(byte[] data) public ZoneInCompletePacket(byte[] data)
{ {
using (MemoryStream mem = new MemoryStream(data)) using (MemoryStream mem = new MemoryStream(data))
{ {
@ -17,7 +17,7 @@ namespace FFXIVClassic_Map_Server.packets.receive
{ {
try{ try{
timestamp = binReader.ReadUInt32(); timestamp = binReader.ReadUInt32();
unknown = binReader.ReadUInt32(); unknown = binReader.ReadInt32();
} }
catch (Exception){ catch (Exception){
invalidPacket = true; invalidPacket = true;

View File

@ -63,7 +63,10 @@ namespace FFXIVClassic_Map_Server.packets.receive.events
binReader.BaseStream.Seek(0x31, SeekOrigin.Begin); binReader.BaseStream.Seek(0x31, SeekOrigin.Begin);
luaParams = LuaUtils.ReadLuaParams(binReader); if (binReader.PeekChar() == 0x1)
luaParams = new List<LuaParam>();
else
luaParams = LuaUtils.ReadLuaParams(binReader);
} }
catch (Exception){ catch (Exception){
invalidPacket = true; invalidPacket = true;

Some files were not shown because too many files have changed in this diff Show More