diff options
174 files changed, 7498 insertions, 1451 deletions
diff --git a/contrib/Connection Patcher/App.config b/contrib/Connection Patcher/App.config new file mode 100644 index 00000000000..87b8cafdd3d --- /dev/null +++ b/contrib/Connection Patcher/App.config @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<configuration> + <startup> + <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0,Profile=Client"/> + </startup> +</configuration> diff --git a/contrib/Connection Patcher/Connection Patcher.csproj b/contrib/Connection Patcher/Connection Patcher.csproj new file mode 100644 index 00000000000..8ad5a631aed --- /dev/null +++ b/contrib/Connection Patcher/Connection Patcher.csproj @@ -0,0 +1,69 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProjectGuid>{137B1355-6A81-4A3A-A01E-93ABAA4FFFDB}</ProjectGuid> + <OutputType>Exe</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>Connection_Patcher</RootNamespace> + <AssemblyName>Connection Patcher</AssemblyName> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> + <FileAlignment>512</FileAlignment> + <TargetFrameworkProfile>Client</TargetFrameworkProfile> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <PlatformTarget>AnyCPU</PlatformTarget> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>TRACE;DEBUG</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies> + <RunCodeAnalysis>false</RunCodeAnalysis> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <PlatformTarget>AnyCPU</PlatformTarget> + <DebugType>none</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants> + </DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies> + <UseVSHostingProcess>false</UseVSHostingProcess> + </PropertyGroup> + <PropertyGroup> + <NoWin32Manifest>true</NoWin32Manifest> + </PropertyGroup> + <ItemGroup> + <Reference Include="System" /> + </ItemGroup> + <ItemGroup> + <Compile Include="Constants\BinaryTypes.cs" /> + <Compile Include="Helper.cs" /> + <Compile Include="Offsets\Windows.cs" /> + <Compile Include="Patcher.cs" /> + <Compile Include="Patches\Mac.cs" /> + <Compile Include="Patches\Windows.cs" /> + <Compile Include="Patterns\Mac.cs" /> + <Compile Include="Patterns\Windows.cs" /> + <Compile Include="Program.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + </ItemGroup> + <ItemGroup> + <None Include="App.config" /> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> +</Project>
\ No newline at end of file diff --git a/contrib/Connection Patcher/Connection Patcher.sln b/contrib/Connection Patcher/Connection Patcher.sln new file mode 100644 index 00000000000..7ba4e8c6137 --- /dev/null +++ b/contrib/Connection Patcher/Connection Patcher.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.30110.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Connection Patcher", "Connection Patcher.csproj", "{137B1355-6A81-4A3A-A01E-93ABAA4FFFDB}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {137B1355-6A81-4A3A-A01E-93ABAA4FFFDB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {137B1355-6A81-4A3A-A01E-93ABAA4FFFDB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {137B1355-6A81-4A3A-A01E-93ABAA4FFFDB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {137B1355-6A81-4A3A-A01E-93ABAA4FFFDB}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/contrib/Connection Patcher/Constants/BinaryTypes.cs b/contrib/Connection Patcher/Constants/BinaryTypes.cs new file mode 100644 index 00000000000..b98a7ea73c0 --- /dev/null +++ b/contrib/Connection Patcher/Constants/BinaryTypes.cs @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2012-2014 Arctium Emulation <http://arctium.org> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +namespace Connection_Patcher.Constants +{ + enum BinaryTypes : uint + { + None = 0000000000, + Pe32 = 0x0000014C, + Pe64 = 0x00008664, + Mach32 = 0xFEEDFACE, + Mach64 = 0xFEEDFACF + } +} diff --git a/contrib/Connection Patcher/Helper.cs b/contrib/Connection Patcher/Helper.cs new file mode 100644 index 00000000000..d0e8f6655e7 --- /dev/null +++ b/contrib/Connection Patcher/Helper.cs @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2012-2014 Arctium Emulation <http://arctium.org> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +using Connection_Patcher.Constants; +using System; +using System.IO; +using System.Security.Cryptography; + +namespace Connection_Patcher +{ + class Helper + { + public static BinaryTypes GetBinaryType(byte[] data) + { + BinaryTypes type = 0u; + + using (var reader = new BinaryReader(new MemoryStream(data))) + { + var magic = (uint)reader.ReadUInt16(); + + // Check MS-DOS magic + if (magic == 0x5A4D) + { + reader.BaseStream.Seek(0x3C, SeekOrigin.Begin); + + // Read PE start offset + var peOffset = reader.ReadUInt32(); + + reader.BaseStream.Seek(peOffset, SeekOrigin.Begin); + + var peMagic = reader.ReadUInt32(); + + // Check PE magic + if (peMagic != 0x4550) + throw new NotSupportedException("Not a PE file!"); + + type = (BinaryTypes)reader.ReadUInt16(); + } + else + { + reader.BaseStream.Seek(0, SeekOrigin.Begin); + + type = (BinaryTypes)reader.ReadUInt32(); + } + } + + return type; + } + + public static string GetFileChecksum(byte[] data) + { + using (var stream = new BufferedStream(new MemoryStream(data), 1200000)) + { + var sha256 = new SHA256Managed(); + var checksum = sha256.ComputeHash(stream); + + return BitConverter.ToString(checksum).Replace("-", "").ToLower(); + } + } + } +} diff --git a/contrib/Connection Patcher/Offsets/Windows.cs b/contrib/Connection Patcher/Offsets/Windows.cs new file mode 100644 index 00000000000..4f2f32708cc --- /dev/null +++ b/contrib/Connection Patcher/Offsets/Windows.cs @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +namespace Connection_Patcher.Offsets +{ + static class Windows + { + public static class x86 + { + public static readonly long BNet = 0xD3259; + public static readonly long Send = 0x889CA; + public static readonly long Recv = 0x86EEE; + public static readonly long Signature = 0x20B79; + public static readonly long RealmList = 0x228D6C; + } + + public static class x64 + { + public static readonly long BNet = 0; + public static readonly long Send = 0xAAB6B; + public static readonly long Recv = 0xA9FA3; + public static readonly long Signature = 0; + public static readonly long RealmList = 0x2BB33C; + } + } +} diff --git a/contrib/Connection Patcher/Patcher.cs b/contrib/Connection Patcher/Patcher.cs new file mode 100644 index 00000000000..8e73997365c --- /dev/null +++ b/contrib/Connection Patcher/Patcher.cs @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2012-2014 Arctium Emulation <http://arctium.org> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +using Connection_Patcher.Constants; +using System; +using System.IO; + +namespace Connection_Patcher +{ + class Patcher : IDisposable + { + public string Binary { get; set; } + public bool Initialized { get; private set; } + public BinaryTypes Type { get; private set; } + + public byte[] binary; + bool success; + + public Patcher(string file) + { + Initialized = false; + success = false; + + using (var stream = new MemoryStream(File.ReadAllBytes(file))) + { + Binary = file; + binary = stream.ToArray(); + + if (binary != null) + { + Type = Helper.GetBinaryType(binary); + + Initialized = true; + } + } + } + + public void Patch(byte[] bytes, byte[] pattern, long address = 0) + { + if (Initialized && (address != 0 || binary.Length >= pattern.Length)) + { + var offset = pattern == null ? address : SearchOffset(pattern); + Console.WriteLine("Found offset {0}", offset); + + if (offset != 0 && binary.Length >= bytes.Length) + { + try + { + for (int i = 0; i < bytes.Length; i++) + binary[offset + i] = bytes[i]; + } + catch (Exception ex) + { + throw new NotSupportedException(ex.Message); + } + } + } + } + + long SearchOffset(byte[] pattern) + { + var matches = 0; + + for (long i = 0; i < binary.Length; i++) + { + matches = 0; + + for (int j = 0; j < pattern.Length; j++) + { + if (pattern.Length > (binary.Length - i)) + return 0; + + if (pattern[j] == 0) + { + matches++; + continue; + } + + if (binary[i + j] != pattern[j]) + break; + + matches++; + } + + if (matches == pattern.Length) + return i; + } + + return 0; + } + + public void Finish() + { + success = true; + } + + public void Dispose() + { + try + { + if (File.Exists(Binary)) + File.Delete(Binary); + + if (success) + File.WriteAllBytes(Binary, binary); + } + catch (UnauthorizedAccessException) + { + + } + + binary = null; + } + } +} diff --git a/contrib/Connection Patcher/Patches/Mac.cs b/contrib/Connection Patcher/Patches/Mac.cs new file mode 100644 index 00000000000..583d1398354 --- /dev/null +++ b/contrib/Connection Patcher/Patches/Mac.cs @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2012-2014 Arctium Emulation <http://arctium.org> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +namespace Connection_Patcher.Patches +{ + class Mac + { + public static class x86 + { + public static byte[] BNet = { }; + public static byte[] Send = { }; + public static byte[] Recv = { }; + public static byte[] Password = { 0x0F, 0x85 }; + public static byte[] Signature = { }; + } + + public static class x64 + { + //public static byte[] BNet = { 0xB8, 0xD5, 0xF8, 0x7F, 0x82, 0x89, 0x47, 0x0C, 0x5D, 0xC3, 0x90, 0x90, 0x90 }; + public static byte[] BNet = { }; + //public static byte[] Send = { 0x90, 0x31, 0xDB }; + public static byte[] Send = { }; + public static byte[] Recv = { }; + public static byte[] Password = { 0x0F, 0x85 }; + //public static byte[] Signature = { 0x45, 0x31, 0xED, 0x4D, 0x89, 0xFC, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0xEB }; + public static byte[] Signature = { }; + } + } +} diff --git a/contrib/Connection Patcher/Patches/Windows.cs b/contrib/Connection Patcher/Patches/Windows.cs new file mode 100644 index 00000000000..feb10507084 --- /dev/null +++ b/contrib/Connection Patcher/Patches/Windows.cs @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2012-2014 Arctium Emulation <http://arctium.org> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +namespace Connection_Patcher.Patches +{ + class Windows + { + public static class x86 + { + public static byte[] BNet = { 0x89, 0x48, 0x08, 0xC7, 0x40, 0x0C, 0xD5, 0xF8, 0x7F, 0x82, 0x90 }; + public static byte[] Send = { 0xBA, 0x00, 0x00, 0x00, 0x00, 0x90, 0xEB }; + public static byte[] Recv = { 0xB8, 0x00, 0x00, 0x00, 0x00 }; + public static byte[] Password = { 0x75 }; + public static byte[] Signature = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0xE9 }; + public static byte[] RealmList = { 0x08 }; + public static byte[] RealmListBn = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + } + + public static class x64 + { + //public static byte[] BNet = { 0xB8, 0xD5, 0xF8, 0x7F, 0x82, 0x89, 0x41, 0x0C, 0x48, 0x8B, 0xC1, 0xC3 }; + public static byte[] BNet = { }; + public static byte[] Send = { 0x45, 0x33, 0xED, 0x90, 0x90, 0x90 }; + public static byte[] Recv = { 0xB8, 0x00, 0x00, 0x00, 0x00, 0x90 }; + public static byte[] Password = { 0x75 }; + public static byte[] RealmList = { 0x4C, 0x8B, 0xEA }; + //public static byte[] Signature = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0xE9 }; + public static byte[] Signature = { }; + } + } +} diff --git a/contrib/Connection Patcher/Patterns/Mac.cs b/contrib/Connection Patcher/Patterns/Mac.cs new file mode 100644 index 00000000000..d518aa3c78f --- /dev/null +++ b/contrib/Connection Patcher/Patterns/Mac.cs @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2012-2014 Arctium Emulation <http://arctium.org> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +namespace Connection_Patcher.Patterns +{ + class Mac + { + public static class x86 + { + public static byte[] Password = { 0x0F, 0x84, 0xE3, 0x00, 0x00, 0x00, 0x8B, 0x03, 0x8B, 0x40, 0x04 }; + } + + public static class x64 + { + public static byte[] Password = { 0x0F, 0x84, 0x00, 0xFF, 0xFF, 0xFF, 0x49, 0x8B, 0x45, 0x00, 0xB9, 0x40 }; + } + } +} diff --git a/contrib/Connection Patcher/Patterns/Windows.cs b/contrib/Connection Patcher/Patterns/Windows.cs new file mode 100644 index 00000000000..f8bde67dddb --- /dev/null +++ b/contrib/Connection Patcher/Patterns/Windows.cs @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2012-2014 Arctium Emulation <http://arctium.org> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +namespace Connection_Patcher.Patterns +{ + class Windows + { + public static class x86 + { + public static byte[] Password = { 0x74, 0x89, 0x8B, 0x16, 0x8B, 0x42, 0x04 }; + public static byte[] RealmListBn = { 0x2E, 0x6C, 0x6F, 0x67, 0x6F, 0x6E, 0x2E, 0x62, 0x61, 0x74, 0x74, 0x6C, 0x65, 0x2E, 0x6E, 0x65, 0x74 }; + } + + public static class x64 + { + public static byte[] Password = { 0x74, 0x84, 0x48, 0x8B, 0x03 }; + } + } +} diff --git a/contrib/Connection Patcher/Program.cs b/contrib/Connection Patcher/Program.cs new file mode 100644 index 00000000000..956741b625b --- /dev/null +++ b/contrib/Connection Patcher/Program.cs @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2012-2014 Arctium Emulation <http://arctium.org> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +using Connection_Patcher.Constants; +using System; +using System.IO; +using System.Net; +using System.Text; +using System.Threading; + +namespace Connection_Patcher +{ + class Program + { + static void Main(string[] args) + { + if (args.Length >= 1) + { + Console.ForegroundColor = ConsoleColor.Cyan; + + Console.WriteLine("Client Connection Patcher"); + Console.WriteLine("Press Enter to patch..."); + + Console.ReadKey(true); + + var commonAppData = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData); + var modulePath = ""; + var moduleFile = ""; + + // Let's use Win32 as default module + var patchSend = Patches.Windows.x86.Send; + var offsetSend = Offsets.Windows.x86.Send; + var patchRecv = Patches.Windows.x86.Recv; + var offsetRecv = Offsets.Windows.x86.Recv; + var patchBNet = Patches.Windows.x86.BNet; + var offsetBNet = Offsets.Windows.x86.BNet; + var patchSignature = Patches.Windows.x86.Signature; + var offsetSignature = Offsets.Windows.x86.Signature; + var fileName = args[0].Replace(".exe", "_Patched.exe"); + var battleNetFileName = args[0].Replace("Wow.exe", "Battle.net.dll"); + var modulePatch = Patches.Windows.x86.Password; + var modulePattern = Patterns.Windows.x86.Password; + var realmListPatch = Patches.Windows.x86.RealmList; + var realmListoffset = Offsets.Windows.x86.RealmList; + var realmListBnPatch = Patches.Windows.x86.RealmListBn; + var realmListBnPattern = Patterns.Windows.x86.RealmListBn; + + Console.ForegroundColor = ConsoleColor.White; + Console.Write("Creating patched binaries for "); + + using (var patcher = new Patcher(args[0])) + { + switch (patcher.Type) + { + case BinaryTypes.Pe32: + Console.WriteLine("Win32 client..."); + modulePath = commonAppData + "/Blizzard Entertainment/Battle.net/Cache/"; + moduleFile = "8f52906a2c85b416a595702251570f96d3522f39237603115f2f1ab24962043c.auth"; + break; + //case BinaryTypes.Pe64: + // Console.WriteLine("Win64 client..."); + // fileName = patcher.Binary.Replace(".exe", "") + "_Patched.exe"; + + // modulePath = commonAppData + "/Blizzard Entertainment/Battle.net/Cache/"; + // moduleFile = "0a3afee2cade3a0e8b458c4b4660104cac7fc50e2ca9bef0d708942e77f15c1d.auth"; + // break; + //case BinaryTypes.Mach32: + // break; + //case BinaryTypes.Mach64: + // Console.WriteLine("Mc64 client..."); + // patchBNet = Patches.Mac.x64.BNet; + // patternBNet = Patterns.Mac.x64.BNet; + // patchSend = Patches.Mac.x64.Send; + // patternSend = Patterns.Mac.x64.Send; + // patchSignature = Patches.Mac.x64.Signature; + // patternSignature = Patterns.Mac.x64.Signature; + // fileName = patcher.Binary + " Patched"; + + // modulePath = "/Users/Shared/Blizzard/Battle.net/Cache/"; + // moduleFile = "97eeb2e28e9e56ed6a22d09f44e2ff43c93315e006bbad43bafc0defaa6f50ae.auth"; + // modulePatch = Patches.Mac.x64.Password; + // modulePattern = Patterns.Mac.x64.Password; + // break; + default: + throw new NotSupportedException("Type: " + patcher.Type + " not supported!"); + } + + if (!File.Exists(battleNetFileName + "_backup")) + { + File.Copy(battleNetFileName, battleNetFileName + "_backup"); + File.SetAttributes(battleNetFileName + "_backup", File.GetAttributes(battleNetFileName + "_backup") | FileAttributes.ReadOnly); + } + + using (var bnpatcher = new Patcher(battleNetFileName)) + { + bnpatcher.Patch(patchBNet, null, offsetBNet); + bnpatcher.Patch(patchSignature, null, offsetSignature); + bnpatcher.Patch(realmListBnPatch, realmListBnPattern); + bnpatcher.Finish(); + } + + patcher.Patch(patchSend, null, offsetSend); + patcher.Patch(patchRecv, null, offsetRecv); + patcher.Patch(realmListPatch, null, realmListoffset); + + patcher.Binary = fileName; + + patcher.Finish(); + + Console.ForegroundColor = ConsoleColor.Green; + Console.WriteLine("Patching done."); + + CreateModule(moduleFile, modulePath, modulePatch, modulePattern); + + Console.ForegroundColor = ConsoleColor.Green; + Console.WriteLine("Successfully created your patched binaries."); + } + } + else + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine("Wrong number of arguments: Missing client file."); + } + + Console.ForegroundColor = ConsoleColor.Gray; + Thread.Sleep(5000); + Environment.Exit(0); + } + + static void CreateModule(string moduleName, string path, byte[] patches, byte[] patterns) + { + var modulePath = path + moduleName[0] + moduleName[1] + "/" + moduleName[2] + moduleName[3]; + var module = modulePath + "/" + moduleName; + + if (!File.Exists(module)) + { + Console.ForegroundColor = ConsoleColor.White; + Console.WriteLine("Base module doesn't exist, downloading it..."); + + if (!Directory.Exists(modulePath)) + Directory.CreateDirectory(modulePath); + + var webClient = new WebClient(); + + webClient.DownloadFileCompleted += (o, e) => PatchModule(module, path, patches, patterns); + webClient.DownloadFileAsync(new Uri("http://xx.depot.battle.net:1119/" + moduleName), module); + + Console.ForegroundColor = ConsoleColor.Green; + Console.WriteLine("Done."); + } + else + PatchModule(module, path, patches, patterns); + } + + static void PatchModule(string file, string path, byte[] patches, byte[] pattern) + { + Console.ForegroundColor = ConsoleColor.White; + Console.WriteLine("Patching module..."); + + using (var patcher2 = new Patcher(file)) + { + patcher2.Patch(patches, pattern); + + var moduleName = Helper.GetFileChecksum(patcher2.binary) + ".auth"; + var modulePath = path + moduleName[0] + moduleName[1] + "/" + moduleName[2] + moduleName[3]; + + if (!Directory.Exists(modulePath)) + Directory.CreateDirectory(modulePath); + + patcher2.Binary = modulePath + "/" + moduleName; + + patcher2.Finish(); + } + + Console.ForegroundColor = ConsoleColor.Green; + Console.WriteLine("Patching module finished."); + + Console.ForegroundColor = ConsoleColor.Gray; + } + } +} diff --git a/contrib/Connection Patcher/Properties/AssemblyInfo.cs b/contrib/Connection Patcher/Properties/AssemblyInfo.cs new file mode 100644 index 00000000000..b1d174575c5 --- /dev/null +++ b/contrib/Connection Patcher/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Connection Patcher")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Connection Patcher")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("07c6905b-5b42-4804-81fe-73d0f74ebfb1")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/sql/base/auth_database.sql b/sql/base/auth_database.sql index 0a989cdcb92..a76281da729 100644 --- a/sql/base/auth_database.sql +++ b/sql/base/auth_database.sql @@ -46,8 +46,12 @@ CREATE TABLE `account` ( `locale` tinyint(3) unsigned NOT NULL DEFAULT '0', `os` varchar(3) NOT NULL DEFAULT '', `recruiter` int(10) unsigned NOT NULL DEFAULT '0', + `battlenet_account` int(10) unsigned DEFAULT NULL, + `battlenet_index` tinyint(3) unsigned DEFAULT NULL, PRIMARY KEY (`id`), - UNIQUE KEY `idx_username` (`username`) + UNIQUE KEY `idx_username` (`username`), + UNIQUE KEY `uk_bnet_acc` (`battlenet_account`, `battlenet_index`), + CONSTRAINT `fk_bnet_acc` FOREIGN KEY (`battlenet_account`) REFERENCES `battlenet_accounts` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Account System'; /*!40101 SET character_set_client = @saved_cs_client */; @@ -137,6 +141,145 @@ LOCK TABLES `autobroadcast` WRITE; UNLOCK TABLES; -- +-- Table structure for table `battlenet_account_bans` +-- + +DROP TABLE IF EXISTS `battlenet_account_bans`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `battlenet_account_bans` ( + `id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Account id', + `bandate` int(10) unsigned NOT NULL DEFAULT '0', + `unbandate` int(10) unsigned NOT NULL DEFAULT '0', + `bannedby` varchar(50) NOT NULL, + `banreason` varchar(255) NOT NULL, + `active` tinyint(3) unsigned NOT NULL DEFAULT '1', + PRIMARY KEY (`id`,`bandate`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Ban List'; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `battlenet_account_bans` +-- + +LOCK TABLES `battlenet_account_bans` WRITE; +/*!40000 ALTER TABLE `battlenet_account_bans` DISABLE KEYS */; +/*!40000 ALTER TABLE `battlenet_account_bans` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `battlenet_accounts` +-- + +DROP TABLE IF EXISTS `battlenet_accounts`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `battlenet_accounts` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Identifier', + `email` varchar(320) NOT NULL, + `sha_pass_hash` varchar(64) NOT NULL DEFAULT '', + `v` varchar(256) NOT NULL DEFAULT '', + `s` varchar(64) NOT NULL DEFAULT '', + `sessionKey` varchar(128) NOT NULL DEFAULT '', + `joindate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `last_ip` varchar(15) NOT NULL DEFAULT '127.0.0.1', + `failed_logins` int(10) unsigned NOT NULL DEFAULT '0', + `locked` tinyint(3) unsigned NOT NULL DEFAULT '0', + `lock_country` varchar(2) NOT NULL DEFAULT '00', + `last_login` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', + `online` tinyint(3) unsigned NOT NULL DEFAULT '0', + `locale` tinyint(3) unsigned NOT NULL DEFAULT '0', + `os` varchar(3) NOT NULL DEFAULT '', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8 COMMENT='Account System'; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- Table structure for table `battlenet_components` +-- + +DROP TABLE IF EXISTS `battlenet_components`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `battlenet_components` ( + `Program` varchar(4) NOT NULL, + `Platform` varchar(4) NOT NULL, + `Build` int(11) unsigned NOT NULL, + PRIMARY KEY (`Program`,`Platform`,`Build`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `battlenet_components` +-- + +LOCK TABLES `battlenet_components` WRITE; +/*!40000 ALTER TABLE `battlenet_components` DISABLE KEYS */; +INSERT INTO `battlenet_components` VALUES +('Bnet','Cmp1',3), +('Bnet','Win',26487), +('Bnet','Wn64',26487), +('Tool','Win',2736), +('WoW','base',15595), +('WoW','enGB',15595), +('WoW','enUS',15595), +('WoW','Win',15595), +('WoW','Wn64',15595); +/*!40000 ALTER TABLE `battlenet_components` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `battlenet_modules` +-- + +DROP TABLE IF EXISTS `battlenet_modules`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `battlenet_modules` ( + `Hash` varchar(64) NOT NULL, + `Name` varchar(64) NOT NULL DEFAULT '', + `Type` varchar(8) NOT NULL, + `System` varchar(8) NOT NULL, + `Data` text, + PRIMARY KEY (`Hash`), + UNIQUE KEY `uk_name_type_system` (`Name`,`Type`,`System`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `battlenet_modules` +-- + +LOCK TABLES `battlenet_modules` WRITE; +/*!40000 ALTER TABLE `battlenet_modules` DISABLE KEYS */; +INSERT INTO `battlenet_modules` VALUES +('19c91b68752b7826df498bf73aca1103c86962a9a55a0a7033e5ad895f4d927c','Password','auth','Mc64',NULL), +('1af5418a448f8ad05451e3f7dbb2d9af9cb13458eea2368ebfc539476b954f1c','RiskFingerprint','auth','Mc64',NULL), +('207640724f4531d3b2a21532224d1486e8c4d2d805170381cbc3093264157960','SelectGameAccount','auth','Mac',NULL), +('2e6d53adab37a41542b38e01f62cd365eab8805ed0de73c307cc6d9d1dfe478c','Password','auth','Win',NULL), +('36b27cd911b33c61730a8b82c8b2495fd16e8024fc3b2dde08861c77a852941c','Thumbprint','auth','Win','E716F4F0A01EB9C032A6C1393356A4F766F067949D71023C0CFC0613718966EF814E65CC6EE70C432A7F8AFD8A062B52603A2697E851D231D72C0277614181D713369B1E8E4BEEAB72045A9AAD45F319DB918ECDDB83C8EF8B7510600D391D45E7FEC0BEEAE904A5F9FA620F1CCDAD699D84A4739CE669B5A551831E396214E13B4C88F573F5CDC784CD01530C086B674C03BEB66403A0F87ED17ABBB403DE54CF31BE828A20C566C22E4D4263AA77220B0644D99245345BCAC276EA06925EB984D664725C3CB757140AFE12E27CB996F17159B1057E9B58B78BBB5A139C9FF6215A0D250B75FC9DD435655DDEADCD6CFD84800792C146B3633188ECEB53D2038C185E0BD51A9E6C70FD38ADF530F8DF50FB62053C5E894897AB7DD65C7AC80665F18E7989BE6E30F15E939751123D6D8A44F033175301D15AAAD2AEA06FAC60BA4065846AE938F32B1CB15F16DC0E76792A7332346896048065D17C059899E1D2300E402BD0EA74265DA6A42B1C854E2470D7B21AE4A2DAE90E602A759B2CA0EE610B50D5389DB89335D5451FE76DD85B09FD5297D6F9EFB6C34CE885007F7DF20D6A524E0C3E772FA04B3DD2E014D3A337A790943DAD523CBB5453F4FDF8E74DFE361BD5F25AB31952B478148B570DF5762643F32B994FEC99A747E4A265A66EE84A53509EC285C84679606049314FC526C61B537AC8061C788F8B86F52208'), +('393ca8d75aff6f04f79532cf95a88b91e5743bc59121520ac31fc4508019fe60','Token','auth','Mac',NULL), +('3c2f63e5949aa6fd6cf330b109ca5b9adcd215beac846b7462ed3aa01d5ad6bb','Password','auth','Mac',NULL), +('52e2978db6468dfade7c61da89513f443c9225692b5085fbe956749870993703','SelectGameAccount','auth','Mc64',NULL), +('548b5ef9e0dd5c2f89f59c3e0979249b27505c51f0c77d2b27133726eaee0ad0','Thumbprint','auth','Mac','E716F4F0A01EB9C032A6C1393356A4F766F067949D71023C0CFC0613718966EF814E65CC6EE70C432A7F8AFD8A062B52603A2697E851D231D72C0277614181D713369B1E8E4BEEAB72045A9AAD45F319DB918ECDDB83C8EF8B7510600D391D45E7FEC0BEEAE904A5F9FA620F1CCDAD699D84A4739CE669B5A551831E396214E13B4C88F573F5CDC784CD01530C086B674C03BEB66403A0F87ED17ABBB403DE54CF31BE828A20C566C22E4D4263AA77220B0644D99245345BCAC276EA06925EB984D664725C3CB757140AFE12E27CB996F17159B1057E9B58B78BBB5A139C9FF6215A0D250B75FC9DD435655DDEADCD6CFD84800792C146B3633188ECEB53D2038C185E0BD51A9E6C70FD38ADF530F8DF50FB62053C5E894897AB7DD65C7AC80665F18E7989BE6E30F15E939751123D6D8A44F033175301D15AAAD2AEA06FAC60BA4065846AE938F32B1CB15F16DC0E76792A7332346896048065D17C059899E1D2300E402BD0EA74265DA6A42B1C854E2470D7B21AE4A2DAE90E602A759B2CA0EE610B50D5389DB89335D5451FE76DD85B09FD5297D6F9EFB6C34CE885007F7DF20D6A524E0C3E772FA04B3DD2E014D3A337A790943DAD523CBB5453F4FDF8E74DFE361BD5F25AB31952B478148B570DF5762643F32B994FEC99A747E4A265A66EE84A53509EC285C84679606049314FC526C61B537AC8061C788F8B86F52208'), +('5e298e530698af905e1247e51ef0b109b352ac310ce7802a1f63613db980ed17','RiskFingerprint','auth','Win',NULL), +('851c1d2ef926e9b9a345a460874e65517195129b9e3bdec7cc77710fa0b1fad6','Password','auth','Wn64',NULL), +('894d25d3219d97d085ea5a8b98e66df5bd9f460ec6f104455246a12b8921409d','SelectGameAccount','auth','Wn64',NULL), +('8c43bda10be33a32abbc09fb2279126c7f5953336391276cff588565332fcd40','RiskFingerprint','auth','Wn64',NULL), +('a1edab845d9e13e9c84531369be2f61b930a37c8e7a9c66d11ef8963380e178a','Token','auth','Mc64',NULL), +('a330f388b6687f8a42fe8fbb592a3df724b20b65fb0989342bb8261f2f452318','Token','auth','Wn64',NULL), +('abc6bb719a73ec1055296001910e26afa561f701ad9995b1ecd7f55f9d3ca37c','SelectGameAccount','auth','Win',NULL), +('b37136b39add83cfdbafa81857de3dd8f15b34e0135ec6cd9c3131d3a578d8c2','Thumbprint','auth','Mc64','E716F4F0A01EB9C032A6C1393356A4F766F067949D71023C0CFC0613718966EF814E65CC6EE70C432A7F8AFD8A062B52603A2697E851D231D72C0277614181D713369B1E8E4BEEAB72045A9AAD45F319DB918ECDDB83C8EF8B7510600D391D45E7FEC0BEEAE904A5F9FA620F1CCDAD699D84A4739CE669B5A551831E396214E13B4C88F573F5CDC784CD01530C086B674C03BEB66403A0F87ED17ABBB403DE54CF31BE828A20C566C22E4D4263AA77220B0644D99245345BCAC276EA06925EB984D664725C3CB757140AFE12E27CB996F17159B1057E9B58B78BBB5A139C9FF6215A0D250B75FC9DD435655DDEADCD6CFD84800792C146B3633188ECEB53D2038C185E0BD51A9E6C70FD38ADF530F8DF50FB62053C5E894897AB7DD65C7AC80665F18E7989BE6E30F15E939751123D6D8A44F033175301D15AAAD2AEA06FAC60BA4065846AE938F32B1CB15F16DC0E76792A7332346896048065D17C059899E1D2300E402BD0EA74265DA6A42B1C854E2470D7B21AE4A2DAE90E602A759B2CA0EE610B50D5389DB89335D5451FE76DD85B09FD5297D6F9EFB6C34CE885007F7DF20D6A524E0C3E772FA04B3DD2E014D3A337A790943DAD523CBB5453F4FDF8E74DFE361BD5F25AB31952B478148B570DF5762643F32B994FEC99A747E4A265A66EE84A53509EC285C84679606049314FC526C61B537AC8061C788F8B86F52208'), +('c0f38d05aa1b83065e839c9bd96c831e9f7e42477085138752657a6a9bb9c520','RiskFingerprint','auth','Mac',NULL), +('c3a1ac0694979e709c3b5486927e558af1e2be02ca96e5615c5a65aacc829226','Thumbprint','auth','Wn64','E716F4F0A01EB9C032A6C1393356A4F766F067949D71023C0CFC0613718966EF814E65CC6EE70C432A7F8AFD8A062B52603A2697E851D231D72C0277614181D713369B1E8E4BEEAB72045A9AAD45F319DB918ECDDB83C8EF8B7510600D391D45E7FEC0BEEAE904A5F9FA620F1CCDAD699D84A4739CE669B5A551831E396214E13B4C88F573F5CDC784CD01530C086B674C03BEB66403A0F87ED17ABBB403DE54CF31BE828A20C566C22E4D4263AA77220B0644D99245345BCAC276EA06925EB984D664725C3CB757140AFE12E27CB996F17159B1057E9B58B78BBB5A139C9FF6215A0D250B75FC9DD435655DDEADCD6CFD84800792C146B3633188ECEB53D2038C185E0BD51A9E6C70FD38ADF530F8DF50FB62053C5E894897AB7DD65C7AC80665F18E7989BE6E30F15E939751123D6D8A44F033175301D15AAAD2AEA06FAC60BA4065846AE938F32B1CB15F16DC0E76792A7332346896048065D17C059899E1D2300E402BD0EA74265DA6A42B1C854E2470D7B21AE4A2DAE90E602A759B2CA0EE610B50D5389DB89335D5451FE76DD85B09FD5297D6F9EFB6C34CE885007F7DF20D6A524E0C3E772FA04B3DD2E014D3A337A790943DAD523CBB5453F4FDF8E74DFE361BD5F25AB31952B478148B570DF5762643F32B994FEC99A747E4A265A66EE84A53509EC285C84679606049314FC526C61B537AC8061C788F8B86F52208'), +('fbe675a99fb5f4b7fb3eb5e5a22add91a4cabf83e3c5930c6659ad13c457ba18','Token','auth','Win',NULL), +('bfe4ceb47700aa872e815e007e27df955d4cd4bc1fe731039ee6498ce209f368','Resume','auth','Win',NULL), +('00ffd88a437afbb88d7d4b74be2e3b43601605ee229151aa9f4bebb29ef66280','Resume','auth','Mac',NULL), +('898166926805f897804bdbbf40662c9d768590a51a0b26c40dbcdf332ba11974','Resume','auth','Wn64',NULL), +('304627d437c38500c0b5ca0c6220eeade91390e52a2b005ff3f7754afa1f93cd','Resume','auth','Mc64',NULL); +/*!40000 ALTER TABLE `battlenet_modules` ENABLE KEYS */; +UNLOCK TABLES; + +-- -- Table structure for table `ip2nation` -- @@ -317,7 +460,7 @@ CREATE TABLE `rbac_linked_permissions` ( LOCK TABLES `rbac_linked_permissions` WRITE; /*!40000 ALTER TABLE `rbac_linked_permissions` DISABLE KEYS */; -INSERT INTO `rbac_linked_permissions` VALUES (192,21),(192,42),(192,43),(192,193),(192,196),(193,48),(193,194),(193,197),(194,1),(194,2),(194,11),(194,13),(194,14),(194,15),(194,16),(194,17),(194,18),(194,19),(194,20),(194,22),(194,23),(194,25),(194,26),(194,27),(194,28),(194,29),(194,30),(194,31),(194,32),(194,33),(194,34),(194,35),(194,36),(194,37),(194,38),(194,39),(194,40),(194,41),(194,44),(194,46),(194,47),(194,195),(194,198),(195,3),(195,4),(195,5),(195,6),(195,24),(195,49),(195,199),(196,200),(196,201),(196,226),(196,227),(196,230),(196,231),(196,233),(196,234),(196,235),(196,238),(196,239),(196,240),(196,241),(196,242),(196,243),(196,244),(196,245),(196,246),(196,247),(196,248),(196,249),(196,250),(196,251),(196,252),(196,253),(196,254),(196,255),(196,256),(196,257),(196,258),(196,259),(196,260),(196,261),(196,262),(196,264),(196,265),(196,266),(196,267),(196,268),(196,269),(196,270),(196,271),(196,272),(196,279),(196,280),(196,283),(196,287),(196,288),(196,289),(196,290),(196,291),(196,292),(196,293),(196,294),(196,295),(196,296),(196,297),(196,298),(196,299),(196,302),(196,303),(196,304),(196,305),(196,306),(196,307),(196,308),(196,309),(196,310),(196,313),(196,314),(196,319),(196,320),(196,321),(196,322),(196,323),(196,324),(196,325),(196,326),(196,327),(196,328),(196,329),(196,330),(196,331),(196,332),(196,333),(196,334),(196,335),(196,336),(196,337),(196,338),(196,339),(196,340),(196,341),(196,342),(196,343),(196,344),(196,345),(196,346),(196,347),(196,348),(196,349),(196,350),(196,351),(196,352),(196,353),(196,354),(196,355),(196,356),(196,357),(196,358),(196,359),(196,360),(196,361),(196,362),(196,363),(196,364),(196,365),(196,366),(196,373),(196,375),(196,400),(196,401),(196,402),(196,403),(196,404),(196,405),(196,406),(196,407),(196,417),(196,418),(196,419),(196,420),(196,421),(196,422),(196,423),(196,424),(196,425),(196,426),(196,427),(196,428),(196,429),(196,434),(196,435),(196,436),(196,437),(196,438),(196,439),(196,440),(196,441),(196,442),(196,443),(196,444),(196,445),(196,446),(196,447),(196,448),(196,449),(196,450),(196,451),(196,452),(196,453),(196,454),(196,455),(196,456),(196,457),(196,458),(196,459),(196,461),(196,463),(196,464),(196,465),(196,472),(196,473),(196,474),(196,475),(196,476),(196,477),(196,478),(196,488),(196,489),(196,491),(196,492),(196,493),(196,495),(196,497),(196,498),(196,499),(196,500),(196,502),(196,503),(196,505),(196,508),(196,511),(196,513),(196,514),(196,516),(196,519),(196,522),(196,523),(196,526),(196,527),(196,529),(196,530),(196,533),(196,535),(196,536),(196,537),(196,538),(196,539),(196,540),(196,541),(196,556),(196,581),(196,582),(196,592),(196,593),(196,596),(196,602),(196,603),(196,604),(196,605),(196,606),(196,607),(196,608),(196,609),(196,610),(196,611),(196,612),(196,613),(196,614),(196,615),(196,616),(196,617),(196,618),(196,619),(196,620),(196,621),(196,622),(196,623),(196,624),(196,625),(196,626),(196,627),(196,628),(196,629),(196,630),(196,633),(196,634),(196,635),(196,636),(196,637),(196,638),(196,639),(196,640),(196,641),(196,642),(196,643),(196,644),(196,645),(196,646),(196,647),(196,648),(196,649),(196,650),(196,651),(196,652),(196,653),(196,654),(196,655),(196,656),(196,657),(196,658),(196,659),(196,660),(196,661),(196,662),(196,663),(196,664),(196,665),(196,666),(196,667),(196,668),(196,669),(196,670),(196,671),(196,672),(196,673),(196,674),(196,675),(196,676),(196,677),(196,678),(196,679),(196,680),(196,681),(196,682),(196,683),(196,684),(196,685),(196,686),(196,687),(196,688),(196,689),(196,690),(196,691),(196,692),(196,693),(196,694),(196,695),(196,696),(196,697),(196,698),(196,699),(196,700),(196,701),(196,702),(196,703),(196,704),(196,705),(196,706),(196,707),(196,708),(196,709),(196,710),(196,711),(196,712),(196,713),(196,714),(196,715),(196,716),(196,717),(196,718),(196,719),(196,721),(196,722),(196,723),(196,724),(196,725),(196,726),(196,727),(196,728),(196,729),(196,730),(196,733),(196,734),(196,735),(196,736),(196,738),(196,739),(196,748),(196,753),(196,757),(196,773),(196,777),(197,232),(197,236),(197,237),(197,273),(197,274),(197,275),(197,276),(197,277),(197,284),(197,285),(197,286),(197,301),(197,311),(197,387),(197,388),(197,389),(197,390),(197,391),(197,392),(197,393),(197,394),(197,395),(197,396),(197,397),(197,398),(197,399),(197,479),(197,480),(197,481),(197,482),(197,485),(197,486),(197,487),(197,494),(197,506),(197,509),(197,510),(197,517),(197,518),(197,521),(197,542),(197,543),(197,550),(197,558),(197,568),(197,571),(197,572),(197,573),(197,574),(197,575),(197,576),(197,577),(197,578),(197,579),(197,580),(197,583),(197,584),(197,585),(197,586),(197,587),(197,588),(197,589),(197,590),(197,591),(197,594),(197,595),(197,601),(197,743),(197,750),(197,758),(197,761),(197,762),(197,763),(197,764),(197,765),(197,766),(197,767),(197,768),(197,769),(197,770),(197,771),(197,772),(197,774),(198,218),(198,300),(198,312),(198,315),(198,316),(198,317),(198,318),(198,367),(198,368),(198,369),(198,370),(198,371),(198,372),(198,374),(198,376),(198,377),(198,378),(198,379),(198,380),(198,381),(198,382),(198,383),(198,384),(198,385),(198,386),(198,408),(198,409),(198,410),(198,411),(198,412),(198,413),(198,414),(198,415),(198,416),(198,430),(198,431),(198,432),(198,433),(198,462),(198,466),(198,467),(198,468),(198,469),(198,470),(198,471),(198,483),(198,484),(198,490),(198,504),(198,512),(198,515),(198,520),(198,524),(198,528),(198,531),(198,532),(198,544),(198,545),(198,546),(198,547),(198,548),(198,549),(198,551),(198,552),(198,553),(198,554),(198,555),(198,557),(198,559),(198,560),(198,561),(198,562),(198,563),(198,564),(198,565),(198,566),(198,567),(198,569),(198,570),(198,597),(198,598),(198,599),(198,600),(198,737),(198,740),(198,741),(198,742),(198,744),(198,745),(198,746),(198,747),(198,749),(198,751),(198,752),(198,754),(198,755),(198,756),(198,759),(198,760),(199,217),(199,221),(199,222),(199,223),(199,225),(199,263),(199,496),(199,501),(199,507),(199,525),(199,534); +INSERT INTO `rbac_linked_permissions` VALUES (192,21),(192,42),(192,43),(192,193),(192,196),(193,48),(193,194),(193,197),(194,1),(194,2),(194,11),(194,13),(194,14),(194,15),(194,16),(194,17),(194,18),(194,19),(194,20),(194,22),(194,23),(194,25),(194,26),(194,27),(194,28),(194,29),(194,30),(194,31),(194,32),(194,33),(194,34),(194,35),(194,36),(194,37),(194,38),(194,39),(194,40),(194,41),(194,44),(194,46),(194,47),(194,195),(194,198),(195,3),(195,4),(195,5),(195,6),(195,24),(195,49),(195,199),(196,200),(196,201),(196,208),(196,212),(196,213),(196,226),(196,227),(196,230),(196,231),(196,233),(196,234),(196,235),(196,238),(196,239),(196,240),(196,241),(196,242),(196,243),(196,244),(196,245),(196,246),(196,247),(196,248),(196,249),(196,250),(196,251),(196,252),(196,253),(196,254),(196,255),(196,256),(196,257),(196,258),(196,259),(196,260),(196,261),(196,262),(196,264),(196,265),(196,266),(196,267),(196,268),(196,269),(196,270),(196,271),(196,272),(196,279),(196,280),(196,283),(196,287),(196,288),(196,289),(196,290),(196,291),(196,292),(196,293),(196,294),(196,295),(196,296),(196,297),(196,298),(196,299),(196,302),(196,303),(196,304),(196,305),(196,306),(196,307),(196,308),(196,309),(196,310),(196,313),(196,314),(196,319),(196,320),(196,321),(196,322),(196,323),(196,324),(196,325),(196,326),(196,327),(196,328),(196,329),(196,330),(196,331),(196,332),(196,333),(196,334),(196,335),(196,336),(196,337),(196,338),(196,339),(196,340),(196,341),(196,342),(196,343),(196,344),(196,345),(196,346),(196,347),(196,348),(196,349),(196,350),(196,351),(196,352),(196,353),(196,354),(196,355),(196,356),(196,357),(196,358),(196,359),(196,360),(196,361),(196,362),(196,363),(196,364),(196,365),(196,366),(196,373),(196,375),(196,400),(196,401),(196,402),(196,403),(196,404),(196,405),(196,406),(196,407),(196,417),(196,418),(196,419),(196,420),(196,421),(196,422),(196,423),(196,424),(196,425),(196,426),(196,427),(196,428),(196,429),(196,434),(196,435),(196,436),(196,437),(196,438),(196,439),(196,440),(196,441),(196,442),(196,443),(196,444),(196,445),(196,446),(196,447),(196,448),(196,449),(196,450),(196,451),(196,452),(196,453),(196,454),(196,455),(196,456),(196,457),(196,458),(196,459),(196,461),(196,463),(196,464),(196,465),(196,472),(196,473),(196,474),(196,475),(196,476),(196,477),(196,478),(196,488),(196,489),(196,491),(196,492),(196,493),(196,495),(196,497),(196,498),(196,499),(196,500),(196,502),(196,503),(196,505),(196,508),(196,511),(196,513),(196,514),(196,516),(196,519),(196,522),(196,523),(196,526),(196,527),(196,529),(196,530),(196,533),(196,535),(196,536),(196,537),(196,538),(196,539),(196,540),(196,541),(196,556),(196,581),(196,582),(196,592),(196,593),(196,596),(196,602),(196,603),(196,604),(196,605),(196,606),(196,607),(196,608),(196,609),(196,610),(196,611),(196,612),(196,613),(196,614),(196,615),(196,616),(196,617),(196,618),(196,619),(196,620),(196,621),(196,622),(196,623),(196,624),(196,625),(196,626),(196,627),(196,628),(196,629),(196,630),(196,633),(196,634),(196,635),(196,636),(196,637),(196,638),(196,639),(196,640),(196,641),(196,642),(196,643),(196,644),(196,645),(196,646),(196,647),(196,648),(196,649),(196,650),(196,651),(196,652),(196,653),(196,654),(196,655),(196,656),(196,657),(196,658),(196,659),(196,660),(196,661),(196,662),(196,663),(196,664),(196,665),(196,666),(196,667),(196,668),(196,669),(196,670),(196,671),(196,672),(196,673),(196,674),(196,675),(196,676),(196,677),(196,678),(196,679),(196,680),(196,681),(196,682),(196,683),(196,684),(196,685),(196,686),(196,687),(196,688),(196,689),(196,690),(196,691),(196,692),(196,693),(196,694),(196,695),(196,696),(196,697),(196,698),(196,699),(196,700),(196,701),(196,702),(196,703),(196,704),(196,705),(196,706),(196,707),(196,708),(196,709),(196,710),(196,711),(196,712),(196,713),(196,714),(196,715),(196,716),(196,717),(196,718),(196,719),(196,721),(196,722),(196,723),(196,724),(196,725),(196,726),(196,727),(196,728),(196,729),(196,730),(196,733),(196,734),(196,735),(196,736),(196,738),(196,739),(196,748),(196,753),(196,757),(196,773),(196,777),(197,232),(197,236),(197,237),(197,273),(197,274),(197,275),(197,276),(197,277),(197,284),(197,285),(197,286),(197,301),(197,311),(197,387),(197,388),(197,389),(197,390),(197,391),(197,392),(197,393),(197,394),(197,395),(197,396),(197,397),(197,398),(197,399),(197,479),(197,480),(197,481),(197,482),(197,485),(197,486),(197,487),(197,494),(197,506),(197,509),(197,510),(197,517),(197,518),(197,521),(197,542),(197,543),(197,550),(197,558),(197,568),(197,571),(197,572),(197,573),(197,574),(197,575),(197,576),(197,577),(197,578),(197,579),(197,580),(197,583),(197,584),(197,585),(197,586),(197,587),(197,588),(197,589),(197,590),(197,591),(197,594),(197,595),(197,601),(197,743),(197,750),(197,758),(197,761),(197,762),(197,763),(197,764),(197,765),(197,766),(197,767),(197,768),(197,769),(197,770),(197,771),(197,772),(197,774),(198,218),(198,300),(198,312),(198,315),(198,316),(198,317),(198,318),(198,367),(198,368),(198,369),(198,370),(198,371),(198,372),(198,374),(198,376),(198,377),(198,378),(198,379),(198,380),(198,381),(198,382),(198,383),(198,384),(198,385),(198,386),(198,408),(198,409),(198,410),(198,411),(198,412),(198,413),(198,414),(198,415),(198,416),(198,430),(198,431),(198,432),(198,433),(198,462),(198,466),(198,467),(198,468),(198,469),(198,470),(198,471),(198,483),(198,484),(198,490),(198,504),(198,512),(198,515),(198,520),(198,524),(198,528),(198,531),(198,532),(198,544),(198,545),(198,546),(198,547),(198,548),(198,549),(198,551),(198,552),(198,553),(198,554),(198,555),(198,557),(198,559),(198,560),(198,561),(198,562),(198,563),(198,564),(198,565),(198,566),(198,567),(198,569),(198,570),(198,597),(198,598),(198,599),(198,600),(198,737),(198,740),(198,741),(198,742),(198,744),(198,745),(198,746),(198,747),(198,749),(198,751),(198,752),(198,754),(198,755),(198,756),(198,759),(198,760),(199,207),(199,209),(199,210),(199,211),(199,217),(199,221),(199,222),(199,223),(199,225),(199,263),(199,496),(199,501),(199,507),(199,525),(199,534); /*!40000 ALTER TABLE `rbac_linked_permissions` ENABLE KEYS */; UNLOCK TABLES; @@ -341,7 +484,7 @@ CREATE TABLE `rbac_permissions` ( LOCK TABLES `rbac_permissions` WRITE; /*!40000 ALTER TABLE `rbac_permissions` DISABLE KEYS */; -INSERT INTO `rbac_permissions` VALUES (1,'Instant logout'),(2,'Skip Queue'),(3,'Join Normal Battleground'),(4,'Join Random Battleground'),(5,'Join Arenas'),(6,'Join Dungeon Finder'),(11,'Log GM trades'),(13,'Skip Instance required bosses check'),(14,'Skip character creation team mask check'),(15,'Skip character creation class mask check'),(16,'Skip character creation race mask check'),(17,'Skip character creation reserved name check'),(18,'Skip character creation heroic min level check'),(19,'Skip needed requirements to use channel check'),(20,'Skip disable map check'),(21,'Skip reset talents when used more than allowed check'),(22,'Skip spam chat check'),(23,'Skip over-speed ping check'),(24,'Two side faction characters on the same account'),(25,'Allow say chat between factions'),(26,'Allow channel chat between factions'),(27,'Two side mail interaction'),(28,'See two side who list'),(29,'Add friends of other faction'),(30,'Save character without delay with .save command'),(31,'Use params with .unstuck command'),(32,'Can be assigned tickets with .assign ticket command'),(33,'Notify if a command was not found'),(34,'Check if should appear in list using .gm ingame command'),(35,'See all security levels with who command'),(36,'Filter whispers'),(37,'Use staff badge in chat'),(38,'Resurrect with full Health Points'),(39,'Restore saved gm setting states'),(40,'Allows to add a gm to friend list'),(41,'Use Config option START_GM_LEVEL to assign new character level'),(42,'Allows to use CMSG_WORLD_TELEPORT opcode'),(43,'Allows to use CMSG_WHOIS opcode'),(44,'Receive global GM messages/texts'),(45,'Join channels without announce'),(46,'Change channel settings without being channel moderator'),(47,'Enables lower security than target check'),(48,'Enable IP, Last Login and EMail output in pinfo'),(49,'Forces to enter the email for confirmation on password change'),(50,'Allow user to check his own email with .account'),(192,'Role: Sec Level Administrator'),(193,'Role: Sec Level Gamemaster'),(194,'Role: Sec Level Moderator'),(195,'Role: Sec Level Player'),(196,'Role: Administrator Commands'),(197,'Role: Gamemaster Commands'),(198,'Role: Moderator Commands'),(199,'Role: Player Commands'),(200,'Command: rbac'),(201,'Command: rbac account'),(202,'Command: rbac account list'),(203,'Command: rbac account grant'),(204,'Command: rbac account deny'),(205,'Command: rbac account revoke'),(206,'Command: rbac list'),(217,'Command: account'),(218,'Command: account addon'),(219,'Command: account create'),(220,'Command: account delete'),(221,'Command: account lock'),(222,'Command: account lock country'),(223,'Command: account lock ip'),(224,'Command: account onlinelist'),(225,'Command: account password'),(226,'Command: account set'),(227,'Command: account set addon'),(228,'Command: account set gmlevel'),(229,'Command: account set password'),(230,'Command: achievement'),(231,'Command: achievement add'),(232,'Command: arena'),(233,'Command: arena captain'),(234,'Command: arena create'),(235,'Command: arena disband'),(236,'Command: arena info'),(237,'Command: arena lookup'),(238,'Command: arena rename'),(239,'Command: ban'),(240,'Command: ban account'),(241,'Command: ban character'),(242,'Command: ban ip'),(243,'Command: ban playeraccount'),(244,'Command: baninfo'),(245,'Command: baninfo account'),(246,'Command: baninfo character'),(247,'Command: baninfo ip'),(248,'Command: banlist'),(249,'Command: banlist account'),(250,'Command: banlist character'),(251,'Command: banlist ip'),(252,'Command: unban'),(253,'Command: unban account'),(254,'Command: unban character'),(255,'Command: unban ip'),(256,'Command: unban playeraccount'),(257,'Command: bf'),(258,'Command: bf start'),(259,'Command: bf stop'),(260,'Command: bf switch'),(261,'Command: bf timer'),(262,'Command: bf enable'),(263,'Command: account email'),(264,'Command: account set sec'),(265,'Command: account set sec email'),(266,'Command: account set sec regmail'),(267,'Command: cast'),(268,'Command: cast back'),(269,'Command: cast dist'),(270,'Command: cast self'),(271,'Command: cast target'),(272,'Command: cast dest'),(273,'Command: character'),(274,'Command: character customize'),(275,'Command: character changefaction'),(276,'Command: character changerace'),(277,'Command: character deleted'),(279,'Command: character deleted list'),(280,'Command: character deleted restore'),(283,'Command: character level'),(284,'Command: character rename'),(285,'Command: character reputation'),(286,'Command: character titles'),(287,'Command: levelup'),(288,'Command: pdump'),(289,'Command: pdump load'),(290,'Command: pdump write'),(291,'Command: cheat'),(292,'Command: cheat casttime'),(293,'Command: cheat cooldown'),(294,'Command: cheat explore'),(295,'Command: cheat god'),(296,'Command: cheat power'),(297,'Command: cheat status'),(298,'Command: cheat taxi'),(299,'Command: cheat waterwalk'),(300,'Command: debug'),(301,'Command: debug anim'),(302,'Command: debug areatriggers'),(303,'Command: debug arena'),(304,'Command: debug bg'),(305,'Command: debug entervehicle'),(306,'Command: debug getitemstate'),(307,'Command: debug getitemvalue'),(308,'Command: debug getvalue'),(309,'Command: debug hostil'),(310,'Command: debug itemexpire'),(311,'Command: debug lootrecipient'),(312,'Command: debug los'),(313,'Command: debug mod32value'),(314,'Command: debug moveflags'),(315,'Command: debug play'),(316,'Command: debug play cinematics'),(317,'Command: debug play movie'),(318,'Command: debug play sound'),(319,'Command: debug send'),(320,'Command: debug send buyerror'),(321,'Command: debug send channelnotify'),(322,'Command: debug send chatmessage'),(323,'Command: debug send equiperror'),(324,'Command: debug send largepacket'),(325,'Command: debug send opcode'),(326,'Command: debug send qinvalidmsg'),(327,'Command: debug send qpartymsg'),(328,'Command: debug send sellerror'),(329,'Command: debug send setphaseshift'),(330,'Command: debug send spellfail'),(331,'Command: debug setaurastate'),(332,'Command: debug setbit'),(333,'Command: debug setitemvalue'),(334,'Command: debug setvalue'),(335,'Command: debug setvid'),(336,'Command: debug spawnvehicle'),(337,'Command: debug threat'),(338,'Command: debug update'),(339,'Command: debug uws'),(340,'Command: wpgps'),(341,'Command: deserter'),(342,'Command: deserter bg'),(343,'Command: deserter bg add'),(344,'Command: deserter bg remove'),(345,'Command: deserter instance'),(346,'Command: deserter instance add'),(347,'Command: deserter instance remove'),(348,'Command: disable'),(349,'Command: disable add'),(350,'Command: disable add achievement_criteria'),(351,'Command: disable add battleground'),(352,'Command: disable add map'),(353,'Command: disable add mmap'),(354,'Command: disable add outdoorpvp'),(355,'Command: disable add quest'),(356,'Command: disable add spell'),(357,'Command: disable add vmap'),(358,'Command: disable remove'),(359,'Command: disable remove achievement_criteria'),(360,'Command: disable remove battleground'),(361,'Command: disable remove map'),(362,'Command: disable remove mmap'),(363,'Command: disable remove outdoorpvp'),(364,'Command: disable remove quest'),(365,'Command: disable remove spell'),(366,'Command: disable remove vmap'),(367,'Command: event'),(368,'Command: event activelist'),(369,'Command: event start'),(370,'Command: event stop'),(371,'Command: gm'),(372,'Command: gm chat'),(373,'Command: gm fly'),(374,'Command: gm ingame'),(375,'Command: gm list'),(376,'Command: gm visible'),(377,'Command: go'),(378,'Command: go creature'),(379,'Command: go graveyard'),(380,'Command: go grid'),(381,'Command: go object'),(382,'Command: go taxinode'),(383,'Command: go ticket'),(384,'Command: go trigger'),(385,'Command: go xyz'),(386,'Command: go zonexy'),(387,'Command: gobject'),(388,'Command: gobject activate'),(389,'Command: gobject add'),(390,'Command: gobject add temp'),(391,'Command: gobject delete'),(392,'Command: gobject info'),(393,'Command: gobject move'),(394,'Command: gobject near'),(395,'Command: gobject set'),(396,'Command: gobject set phase'),(397,'Command: gobject set state'),(398,'Command: gobject target'),(399,'Command: gobject turn'),(400,'debug transport'),(401,'Command: guild'),(402,'Command: guild create'),(403,'Command: guild delete'),(404,'Command: guild invite'),(405,'Command: guild uninvite'),(406,'Command: guild rank'),(407,'Command: guild rename'),(408,'Command: honor'),(409,'Command: honor add'),(410,'Command: honor add kill'),(411,'Command: honor update'),(412,'Command: instance'),(413,'Command: instance listbinds'),(414,'Command: instance unbind'),(415,'Command: instance stats'),(416,'Command: instance savedata'),(417,'Command: learn'),(418,'Command: learn all'),(419,'Command: learn all my'),(420,'Command: learn all my class'),(421,'Command: learn all my pettalents'),(422,'Command: learn all my spells'),(423,'Command: learn all my talents'),(424,'Command: learn all gm'),(425,'Command: learn all crafts'),(426,'Command: learn all default'),(427,'Command: learn all lang'),(428,'Command: learn all recipes'),(429,'Command: unlearn'),(430,'Command: lfg'),(431,'Command: lfg player'),(432,'Command: lfg group'),(433,'Command: lfg queue'),(434,'Command: lfg clean'),(435,'Command: lfg options'),(436,'Command: list'),(437,'Command: list creature'),(438,'Command: list item'),(439,'Command: list object'),(440,'Command: list auras'),(441,'Command: list mail'),(442,'Command: lookup'),(443,'Command: lookup area'),(444,'Command: lookup creature'),(445,'Command: lookup event'),(446,'Command: lookup faction'),(447,'Command: lookup item'),(448,'Command: lookup itemset'),(449,'Command: lookup object'),(450,'Command: lookup quest'),(451,'Command: lookup player'),(452,'Command: lookup player ip'),(453,'Command: lookup player account'),(454,'Command: lookup player email'),(455,'Command: lookup skill'),(456,'Command: lookup spell'),(457,'Command: lookup spell id'),(458,'Command: lookup taxinode'),(459,'Command: lookup tele'),(460,'Command: lookup title'),(461,'Command: lookup map'),(462,'Command: announce'),(463,'Command: channel'),(464,'Command: channel set'),(465,'Command: channel set ownership'),(466,'Command: gmannounce'),(467,'Command: gmnameannounce'),(468,'Command: gmnotify'),(469,'Command: nameannounce'),(470,'Command: notify'),(471,'Command: whispers'),(472,'Command: group'),(473,'Command: group leader'),(474,'Command: group disband'),(475,'Command: group remove'),(476,'Command: group join'),(477,'Command: group list'),(478,'Command: group summon'),(479,'Command: pet'),(480,'Command: pet create'),(481,'Command: pet learn'),(482,'Command: pet unlearn'),(483,'Command: send'),(484,'Command: send items'),(485,'Command: send mail'),(486,'Command: send message'),(487,'Command: send money'),(488,'Command: additem'),(489,'Command: additemset'),(490,'Command: appear'),(491,'Command: aura'),(492,'Command: bank'),(493,'Command: bindsight'),(494,'Command: combatstop'),(495,'Command: cometome'),(496,'Command: commands'),(497,'Command: cooldown'),(498,'Command: damage'),(499,'Command: dev'),(500,'Command: die'),(501,'Command: dismount'),(502,'Command: distance'),(503,'Command: flusharenapoints'),(504,'Command: freeze'),(505,'Command: gps'),(506,'Command: guid'),(507,'Command: help'),(508,'Command: hidearea'),(509,'Command: itemmove'),(510,'Command: kick'),(511,'Command: linkgrave'),(512,'Command: listfreeze'),(513,'Command: maxskill'),(514,'Command: movegens'),(515,'Command: mute'),(516,'Command: neargrave'),(517,'Command: pinfo'),(518,'Command: playall'),(519,'Command: possess'),(520,'Command: recall'),(521,'Command: repairitems'),(522,'Command: respawn'),(523,'Command: revive'),(524,'Command: saveall'),(525,'Command: save'),(526,'Command: setskill'),(527,'Command: showarea'),(528,'Command: summon'),(529,'Command: unaura'),(530,'Command: unbindsight'),(531,'Command: unfreeze'),(532,'Command: unmute'),(533,'Command: unpossess'),(534,'Command: unstuck'),(535,'Command: wchange'),(536,'Command: mmap'),(537,'Command: mmap loadedtiles'),(538,'Command: mmap loc'),(539,'Command: mmap path'),(540,'Command: mmap stats'),(541,'Command: mmap testarea'),(542,'Command: morph'),(543,'Command: demorph'),(544,'Command: modify'),(545,'Command: modify arenapoints'),(546,'Command: modify bit'),(547,'Command: modify drunk'),(548,'Command: modify energy'),(549,'Command: modify faction'),(550,'Command: modify gender'),(551,'Command: modify honor'),(552,'Command: modify hp'),(553,'Command: modify mana'),(554,'Command: modify money'),(555,'Command: modify mount'),(556,'Command: modify phase'),(557,'Command: modify rage'),(558,'Command: modify reputation'),(559,'Command: modify runicpower'),(560,'Command: modify scale'),(561,'Command: modify speed'),(562,'Command: modify speed all'),(563,'Command: modify speed backwalk'),(564,'Command: modify speed fly'),(565,'Command: modify speed walk'),(566,'Command: modify speed swim'),(567,'Command: modify spell'),(568,'Command: modify standstate'),(569,'Command: modify talentpoints'),(570,'Command: npc'),(571,'Command: npc add'),(572,'Command: npc add formation'),(573,'Command: npc add item'),(574,'Command: npc add move'),(575,'Command: npc add temp'),(576,'Command: npc add delete'),(577,'Command: npc add delete item'),(578,'Command: npc add follow'),(579,'Command: npc add follow stop'),(580,'Command: npc set'),(581,'Command: npc set allowmove'),(582,'Command: npc set entry'),(583,'Command: npc set factionid'),(584,'Command: npc set flag'),(585,'Command: npc set level'),(586,'Command: npc set link'),(587,'Command: npc set model'),(588,'Command: npc set movetype'),(589,'Command: npc set phase'),(590,'Command: npc set spawndist'),(591,'Command: npc set spawntime'),(592,'Command: npc set data'),(593,'Command: npc info'),(594,'Command: npc near'),(595,'Command: npc move'),(596,'Command: npc playemote'),(597,'Command: npc say'),(598,'Command: npc textemote'),(599,'Command: npc whisper'),(600,'Command: npc yell'),(601,'Command: npc tame'),(602,'Command: quest'),(603,'Command: quest add'),(604,'Command: quest complete'),(605,'Command: quest remove'),(606,'Command: quest reward'),(607,'Command: reload'),(608,'Command: reload access_requirement'),(609,'Command: reload achievement_criteria_data'),(610,'Command: reload achievement_reward'),(611,'Command: reload all'),(612,'Command: reload all achievement'),(613,'Command: reload all area'),(614,'Command: mailbox'),(615,'Command: reload all gossips'),(616,'Command: reload all item'),(617,'Command: reload all locales'),(618,'Command: reload all loot'),(619,'Command: reload all npc'),(620,'Command: reload all quest'),(621,'Command: reload all scripts'),(622,'Command: reload all spell'),(623,'Command: reload areatrigger_involvedrelation'),(624,'Command: reload areatrigger_tavern'),(625,'Command: reload areatrigger_teleport'),(626,'Command: reload auctions'),(627,'Command: reload autobroadcast'),(628,'Command: reload command'),(629,'Command: reload conditions'),(630,'Command: reload config'),(633,'Command: reload creature_linked_respawn'),(634,'Command: reload creature_loot_template'),(635,'Command: reload creature_onkill_reputation'),(636,'Command: reload creature_questender'),(637,'Command: reload creature_queststarter'),(638,'Command: reload creature_summon_groups'),(639,'Command: reload creature_template'),(640,'Command: reload creature_text'),(641,'Command: reload disables'),(642,'Command: reload disenchant_loot_template'),(643,'Command: reload event_scripts'),(644,'Command: reload fishing_loot_template'),(645,'Command: reload game_graveyard_zone'),(646,'Command: reload game_tele'),(647,'Command: reload gameobject_questender'),(648,'Command: reload gameobject_loot_template'),(649,'Command: reload gameobject_queststarter'),(650,'Command: reload gm_tickets'),(651,'Command: reload gossip_menu'),(652,'Command: reload gossip_menu_option'),(653,'Command: reload item_enchantment_template'),(654,'Command: reload item_loot_template'),(655,'Command: reload item_set_names'),(656,'Command: reload lfg_dungeon_rewards'),(657,'Command: reload locales_achievement_reward'),(658,'Command: reload locales_creature'),(659,'Command: reload locales_creature_text'),(660,'Command: reload locales_gameobject'),(661,'Command: reload locales_gossip_menu_option'),(662,'Command: reload locales_item'),(663,'Command: reload locales_item_set_name'),(664,'Command: reload locales_npc_text'),(665,'Command: reload locales_page_text'),(666,'Command: reload locales_points_of_interest'),(667,'Command: reload locales_quest'),(668,'Command: reload mail_level_reward'),(669,'Command: reload mail_loot_template'),(670,'Command: reload milling_loot_template'),(671,'Command: reload npc_spellclick_spells'),(672,'Command: reload npc_trainer'),(673,'Command: reload npc_vendor'),(674,'Command: reload page_text'),(675,'Command: reload pickpocketing_loot_template'),(676,'Command: reload points_of_interest'),(677,'Command: reload prospecting_loot_template'),(678,'Command: reload quest_poi'),(679,'Command: reload quest_template'),(680,'Command: reload rbac'),(681,'Command: reload reference_loot_template'),(682,'Command: reload reserved_name'),(683,'Command: reload reputation_reward_rate'),(684,'Command: reload reputation_spillover_template'),(685,'Command: reload skill_discovery_template'),(686,'Command: reload skill_extra_item_template'),(687,'Command: reload skill_fishing_base_level'),(688,'Command: reload skinning_loot_template'),(689,'Command: reload smart_scripts'),(690,'Command: reload spell_required'),(691,'Command: reload spell_area'),(692,'Command: reload spell_bonus_data'),(693,'Command: reload spell_group'),(694,'Command: reload spell_learn_spell'),(695,'Command: reload spell_loot_template'),(696,'Command: reload spell_linked_spell'),(697,'Command: reload spell_pet_auras'),(698,'Command: reload spell_proc_event'),(699,'Command: reload spell_proc'),(700,'Command: reload spell_scripts'),(701,'Command: reload spell_target_position'),(702,'Command: reload spell_threats'),(703,'Command: reload spell_group_stack_rules'),(704,'Command: reload trinity_string'),(705,'Command: reload warden_action'),(706,'Command: reload waypoint_scripts'),(707,'Command: reload waypoint_data'),(708,'Command: reload vehicle_accessory'),(709,'Command: reload vehicle_template_accessory'),(710,'Command: reset'),(711,'Command: reset achievements'),(712,'Command: reset honor'),(713,'Command: reset level'),(714,'Command: reset spells'),(715,'Command: reset stats'),(716,'Command: reset talents'),(717,'Command: reset all'),(718,'Command: server'),(719,'Command: server corpses'),(720,'Command: server exit'),(721,'Command: server idlerestart'),(722,'Command: server idlerestart cancel'),(723,'Command: server idleshutdown'),(724,'Command: server idleshutdown cancel'),(725,'Command: server info'),(726,'Command: server plimit'),(727,'Command: server restart'),(728,'Command: server restart cancel'),(729,'Command: server set'),(730,'Command: server set closed'),(731,'Command: server set difftime'),(732,'Command: server set loglevel'),(733,'Command: server set motd'),(734,'Command: server shutdown'),(735,'Command: server shutdown cancel'),(736,'Command: server motd'),(737,'Command: tele'),(738,'Command: tele add'),(739,'Command: tele del'),(740,'Command: tele name'),(741,'Command: tele group'),(742,'Command: ticket'),(743,'Command: ticket assign'),(744,'Command: ticket close'),(745,'Command: ticket closedlist'),(746,'Command: ticket comment'),(747,'Command: ticket complete'),(748,'Command: ticket delete'),(749,'Command: ticket escalate'),(750,'Command: ticket escalatedlist'),(751,'Command: ticket list'),(752,'Command: ticket onlinelist'),(753,'Command: ticket reset'),(754,'Command: ticket response'),(755,'Command: ticket response append'),(756,'Command: ticket response appendln'),(757,'Command: ticket togglesystem'),(758,'Command: ticket unassign'),(759,'Command: ticket viewid'),(760,'Command: ticket viewname'),(761,'Command: titles'),(762,'Command: titles add'),(763,'Command: titles current'),(764,'Command: titles remove'),(765,'Command: titles set'),(766,'Command: titles set mask'),(767,'Command: wp'),(768,'Command: wp add'),(769,'Command: wp event'),(770,'Command: wp load'),(771,'Command: wp modify'),(772,'Command: wp unload'),(773,'Command: wp reload'),(774,'Command: wp show'),(777,'Command: mailbox'); +INSERT INTO `rbac_permissions` VALUES (1,'Instant logout'),(2,'Skip Queue'),(3,'Join Normal Battleground'),(4,'Join Random Battleground'),(5,'Join Arenas'),(6,'Join Dungeon Finder'),(11,'Log GM trades'),(13,'Skip Instance required bosses check'),(14,'Skip character creation team mask check'),(15,'Skip character creation class mask check'),(16,'Skip character creation race mask check'),(17,'Skip character creation reserved name check'),(18,'Skip character creation heroic min level check'),(19,'Skip needed requirements to use channel check'),(20,'Skip disable map check'),(21,'Skip reset talents when used more than allowed check'),(22,'Skip spam chat check'),(23,'Skip over-speed ping check'),(24,'Two side faction characters on the same account'),(25,'Allow say chat between factions'),(26,'Allow channel chat between factions'),(27,'Two side mail interaction'),(28,'See two side who list'),(29,'Add friends of other faction'),(30,'Save character without delay with .save command'),(31,'Use params with .unstuck command'),(32,'Can be assigned tickets with .assign ticket command'),(33,'Notify if a command was not found'),(34,'Check if should appear in list using .gm ingame command'),(35,'See all security levels with who command'),(36,'Filter whispers'),(37,'Use staff badge in chat'),(38,'Resurrect with full Health Points'),(39,'Restore saved gm setting states'),(40,'Allows to add a gm to friend list'),(41,'Use Config option START_GM_LEVEL to assign new character level'),(42,'Allows to use CMSG_WORLD_TELEPORT opcode'),(43,'Allows to use CMSG_WHOIS opcode'),(44,'Receive global GM messages/texts'),(45,'Join channels without announce'),(46,'Change channel settings without being channel moderator'),(47,'Enables lower security than target check'),(48,'Enable IP, Last Login and EMail output in pinfo'),(49,'Forces to enter the email for confirmation on password change'),(50,'Allow user to check his own email with .account'),(192,'Role: Sec Level Administrator'),(193,'Role: Sec Level Gamemaster'),(194,'Role: Sec Level Moderator'),(195,'Role: Sec Level Player'),(196,'Role: Administrator Commands'),(197,'Role: Gamemaster Commands'),(198,'Role: Moderator Commands'),(199,'Role: Player Commands'),(200,'Command: rbac'),(201,'Command: rbac account'),(202,'Command: rbac account list'),(203,'Command: rbac account grant'),(204,'Command: rbac account deny'),(205,'Command: rbac account revoke'),(206,'Command: rbac list'),(207, 'Command: battlenetaccount'),(208, 'Command: battlenetaccount create'),(209, 'Command: battlenetaccount lock country'),(210, 'Command: battlenetaccount lock ip'),(211, 'Command: battlenetaccount password'),(212, 'Command: battlenetaccount set'),(213, 'Command: battlenetaccount set password'),(217,'Command: account'),(218,'Command: account addon'),(219,'Command: account create'),(220,'Command: account delete'),(221,'Command: account lock'),(222,'Command: account lock country'),(223,'Command: account lock ip'),(224,'Command: account onlinelist'),(225,'Command: account password'),(226,'Command: account set'),(227,'Command: account set addon'),(228,'Command: account set gmlevel'),(229,'Command: account set password'),(230,'Command: achievement'),(231,'Command: achievement add'),(232,'Command: arena'),(233,'Command: arena captain'),(234,'Command: arena create'),(235,'Command: arena disband'),(236,'Command: arena info'),(237,'Command: arena lookup'),(238,'Command: arena rename'),(239,'Command: ban'),(240,'Command: ban account'),(241,'Command: ban character'),(242,'Command: ban ip'),(243,'Command: ban playeraccount'),(244,'Command: baninfo'),(245,'Command: baninfo account'),(246,'Command: baninfo character'),(247,'Command: baninfo ip'),(248,'Command: banlist'),(249,'Command: banlist account'),(250,'Command: banlist character'),(251,'Command: banlist ip'),(252,'Command: unban'),(253,'Command: unban account'),(254,'Command: unban character'),(255,'Command: unban ip'),(256,'Command: unban playeraccount'),(257,'Command: bf'),(258,'Command: bf start'),(259,'Command: bf stop'),(260,'Command: bf switch'),(261,'Command: bf timer'),(262,'Command: bf enable'),(263,'Command: account email'),(264,'Command: account set sec'),(265,'Command: account set sec email'),(266,'Command: account set sec regmail'),(267,'Command: cast'),(268,'Command: cast back'),(269,'Command: cast dist'),(270,'Command: cast self'),(271,'Command: cast target'),(272,'Command: cast dest'),(273,'Command: character'),(274,'Command: character customize'),(275,'Command: character changefaction'),(276,'Command: character changerace'),(277,'Command: character deleted'),(279,'Command: character deleted list'),(280,'Command: character deleted restore'),(283,'Command: character level'),(284,'Command: character rename'),(285,'Command: character reputation'),(286,'Command: character titles'),(287,'Command: levelup'),(288,'Command: pdump'),(289,'Command: pdump load'),(290,'Command: pdump write'),(291,'Command: cheat'),(292,'Command: cheat casttime'),(293,'Command: cheat cooldown'),(294,'Command: cheat explore'),(295,'Command: cheat god'),(296,'Command: cheat power'),(297,'Command: cheat status'),(298,'Command: cheat taxi'),(299,'Command: cheat waterwalk'),(300,'Command: debug'),(301,'Command: debug anim'),(302,'Command: debug areatriggers'),(303,'Command: debug arena'),(304,'Command: debug bg'),(305,'Command: debug entervehicle'),(306,'Command: debug getitemstate'),(307,'Command: debug getitemvalue'),(308,'Command: debug getvalue'),(309,'Command: debug hostil'),(310,'Command: debug itemexpire'),(311,'Command: debug lootrecipient'),(312,'Command: debug los'),(313,'Command: debug mod32value'),(314,'Command: debug moveflags'),(315,'Command: debug play'),(316,'Command: debug play cinematics'),(317,'Command: debug play movie'),(318,'Command: debug play sound'),(319,'Command: debug send'),(320,'Command: debug send buyerror'),(321,'Command: debug send channelnotify'),(322,'Command: debug send chatmessage'),(323,'Command: debug send equiperror'),(324,'Command: debug send largepacket'),(325,'Command: debug send opcode'),(326,'Command: debug send qinvalidmsg'),(327,'Command: debug send qpartymsg'),(328,'Command: debug send sellerror'),(329,'Command: debug send setphaseshift'),(330,'Command: debug send spellfail'),(331,'Command: debug setaurastate'),(332,'Command: debug setbit'),(333,'Command: debug setitemvalue'),(334,'Command: debug setvalue'),(335,'Command: debug setvid'),(336,'Command: debug spawnvehicle'),(337,'Command: debug threat'),(338,'Command: debug update'),(339,'Command: debug uws'),(340,'Command: wpgps'),(341,'Command: deserter'),(342,'Command: deserter bg'),(343,'Command: deserter bg add'),(344,'Command: deserter bg remove'),(345,'Command: deserter instance'),(346,'Command: deserter instance add'),(347,'Command: deserter instance remove'),(348,'Command: disable'),(349,'Command: disable add'),(350,'Command: disable add achievement_criteria'),(351,'Command: disable add battleground'),(352,'Command: disable add map'),(353,'Command: disable add mmap'),(354,'Command: disable add outdoorpvp'),(355,'Command: disable add quest'),(356,'Command: disable add spell'),(357,'Command: disable add vmap'),(358,'Command: disable remove'),(359,'Command: disable remove achievement_criteria'),(360,'Command: disable remove battleground'),(361,'Command: disable remove map'),(362,'Command: disable remove mmap'),(363,'Command: disable remove outdoorpvp'),(364,'Command: disable remove quest'),(365,'Command: disable remove spell'),(366,'Command: disable remove vmap'),(367,'Command: event'),(368,'Command: event activelist'),(369,'Command: event start'),(370,'Command: event stop'),(371,'Command: gm'),(372,'Command: gm chat'),(373,'Command: gm fly'),(374,'Command: gm ingame'),(375,'Command: gm list'),(376,'Command: gm visible'),(377,'Command: go'),(378,'Command: go creature'),(379,'Command: go graveyard'),(380,'Command: go grid'),(381,'Command: go object'),(382,'Command: go taxinode'),(383,'Command: go ticket'),(384,'Command: go trigger'),(385,'Command: go xyz'),(386,'Command: go zonexy'),(387,'Command: gobject'),(388,'Command: gobject activate'),(389,'Command: gobject add'),(390,'Command: gobject add temp'),(391,'Command: gobject delete'),(392,'Command: gobject info'),(393,'Command: gobject move'),(394,'Command: gobject near'),(395,'Command: gobject set'),(396,'Command: gobject set phase'),(397,'Command: gobject set state'),(398,'Command: gobject target'),(399,'Command: gobject turn'),(400,'debug transport'),(401,'Command: guild'),(402,'Command: guild create'),(403,'Command: guild delete'),(404,'Command: guild invite'),(405,'Command: guild uninvite'),(406,'Command: guild rank'),(407,'Command: guild rename'),(408,'Command: honor'),(409,'Command: honor add'),(410,'Command: honor add kill'),(411,'Command: honor update'),(412,'Command: instance'),(413,'Command: instance listbinds'),(414,'Command: instance unbind'),(415,'Command: instance stats'),(416,'Command: instance savedata'),(417,'Command: learn'),(418,'Command: learn all'),(419,'Command: learn all my'),(420,'Command: learn all my class'),(421,'Command: learn all my pettalents'),(422,'Command: learn all my spells'),(423,'Command: learn all my talents'),(424,'Command: learn all gm'),(425,'Command: learn all crafts'),(426,'Command: learn all default'),(427,'Command: learn all lang'),(428,'Command: learn all recipes'),(429,'Command: unlearn'),(430,'Command: lfg'),(431,'Command: lfg player'),(432,'Command: lfg group'),(433,'Command: lfg queue'),(434,'Command: lfg clean'),(435,'Command: lfg options'),(436,'Command: list'),(437,'Command: list creature'),(438,'Command: list item'),(439,'Command: list object'),(440,'Command: list auras'),(441,'Command: list mail'),(442,'Command: lookup'),(443,'Command: lookup area'),(444,'Command: lookup creature'),(445,'Command: lookup event'),(446,'Command: lookup faction'),(447,'Command: lookup item'),(448,'Command: lookup itemset'),(449,'Command: lookup object'),(450,'Command: lookup quest'),(451,'Command: lookup player'),(452,'Command: lookup player ip'),(453,'Command: lookup player account'),(454,'Command: lookup player email'),(455,'Command: lookup skill'),(456,'Command: lookup spell'),(457,'Command: lookup spell id'),(458,'Command: lookup taxinode'),(459,'Command: lookup tele'),(460,'Command: lookup title'),(461,'Command: lookup map'),(462,'Command: announce'),(463,'Command: channel'),(464,'Command: channel set'),(465,'Command: channel set ownership'),(466,'Command: gmannounce'),(467,'Command: gmnameannounce'),(468,'Command: gmnotify'),(469,'Command: nameannounce'),(470,'Command: notify'),(471,'Command: whispers'),(472,'Command: group'),(473,'Command: group leader'),(474,'Command: group disband'),(475,'Command: group remove'),(476,'Command: group join'),(477,'Command: group list'),(478,'Command: group summon'),(479,'Command: pet'),(480,'Command: pet create'),(481,'Command: pet learn'),(482,'Command: pet unlearn'),(483,'Command: send'),(484,'Command: send items'),(485,'Command: send mail'),(486,'Command: send message'),(487,'Command: send money'),(488,'Command: additem'),(489,'Command: additemset'),(490,'Command: appear'),(491,'Command: aura'),(492,'Command: bank'),(493,'Command: bindsight'),(494,'Command: combatstop'),(495,'Command: cometome'),(496,'Command: commands'),(497,'Command: cooldown'),(498,'Command: damage'),(499,'Command: dev'),(500,'Command: die'),(501,'Command: dismount'),(502,'Command: distance'),(503,'Command: flusharenapoints'),(504,'Command: freeze'),(505,'Command: gps'),(506,'Command: guid'),(507,'Command: help'),(508,'Command: hidearea'),(509,'Command: itemmove'),(510,'Command: kick'),(511,'Command: linkgrave'),(512,'Command: listfreeze'),(513,'Command: maxskill'),(514,'Command: movegens'),(515,'Command: mute'),(516,'Command: neargrave'),(517,'Command: pinfo'),(518,'Command: playall'),(519,'Command: possess'),(520,'Command: recall'),(521,'Command: repairitems'),(522,'Command: respawn'),(523,'Command: revive'),(524,'Command: saveall'),(525,'Command: save'),(526,'Command: setskill'),(527,'Command: showarea'),(528,'Command: summon'),(529,'Command: unaura'),(530,'Command: unbindsight'),(531,'Command: unfreeze'),(532,'Command: unmute'),(533,'Command: unpossess'),(534,'Command: unstuck'),(535,'Command: wchange'),(536,'Command: mmap'),(537,'Command: mmap loadedtiles'),(538,'Command: mmap loc'),(539,'Command: mmap path'),(540,'Command: mmap stats'),(541,'Command: mmap testarea'),(542,'Command: morph'),(543,'Command: demorph'),(544,'Command: modify'),(545,'Command: modify arenapoints'),(546,'Command: modify bit'),(547,'Command: modify drunk'),(548,'Command: modify energy'),(549,'Command: modify faction'),(550,'Command: modify gender'),(551,'Command: modify honor'),(552,'Command: modify hp'),(553,'Command: modify mana'),(554,'Command: modify money'),(555,'Command: modify mount'),(556,'Command: modify phase'),(557,'Command: modify rage'),(558,'Command: modify reputation'),(559,'Command: modify runicpower'),(560,'Command: modify scale'),(561,'Command: modify speed'),(562,'Command: modify speed all'),(563,'Command: modify speed backwalk'),(564,'Command: modify speed fly'),(565,'Command: modify speed walk'),(566,'Command: modify speed swim'),(567,'Command: modify spell'),(568,'Command: modify standstate'),(569,'Command: modify talentpoints'),(570,'Command: npc'),(571,'Command: npc add'),(572,'Command: npc add formation'),(573,'Command: npc add item'),(574,'Command: npc add move'),(575,'Command: npc add temp'),(576,'Command: npc add delete'),(577,'Command: npc add delete item'),(578,'Command: npc add follow'),(579,'Command: npc add follow stop'),(580,'Command: npc set'),(581,'Command: npc set allowmove'),(582,'Command: npc set entry'),(583,'Command: npc set factionid'),(584,'Command: npc set flag'),(585,'Command: npc set level'),(586,'Command: npc set link'),(587,'Command: npc set model'),(588,'Command: npc set movetype'),(589,'Command: npc set phase'),(590,'Command: npc set spawndist'),(591,'Command: npc set spawntime'),(592,'Command: npc set data'),(593,'Command: npc info'),(594,'Command: npc near'),(595,'Command: npc move'),(596,'Command: npc playemote'),(597,'Command: npc say'),(598,'Command: npc textemote'),(599,'Command: npc whisper'),(600,'Command: npc yell'),(601,'Command: npc tame'),(602,'Command: quest'),(603,'Command: quest add'),(604,'Command: quest complete'),(605,'Command: quest remove'),(606,'Command: quest reward'),(607,'Command: reload'),(608,'Command: reload access_requirement'),(609,'Command: reload achievement_criteria_data'),(610,'Command: reload achievement_reward'),(611,'Command: reload all'),(612,'Command: reload all achievement'),(613,'Command: reload all area'),(614,'Command: mailbox'),(615,'Command: reload all gossips'),(616,'Command: reload all item'),(617,'Command: reload all locales'),(618,'Command: reload all loot'),(619,'Command: reload all npc'),(620,'Command: reload all quest'),(621,'Command: reload all scripts'),(622,'Command: reload all spell'),(623,'Command: reload areatrigger_involvedrelation'),(624,'Command: reload areatrigger_tavern'),(625,'Command: reload areatrigger_teleport'),(626,'Command: reload auctions'),(627,'Command: reload autobroadcast'),(628,'Command: reload command'),(629,'Command: reload conditions'),(630,'Command: reload config'),(633,'Command: reload creature_linked_respawn'),(634,'Command: reload creature_loot_template'),(635,'Command: reload creature_onkill_reputation'),(636,'Command: reload creature_questender'),(637,'Command: reload creature_queststarter'),(638,'Command: reload creature_summon_groups'),(639,'Command: reload creature_template'),(640,'Command: reload creature_text'),(641,'Command: reload disables'),(642,'Command: reload disenchant_loot_template'),(643,'Command: reload event_scripts'),(644,'Command: reload fishing_loot_template'),(645,'Command: reload game_graveyard_zone'),(646,'Command: reload game_tele'),(647,'Command: reload gameobject_questender'),(648,'Command: reload gameobject_loot_template'),(649,'Command: reload gameobject_queststarter'),(650,'Command: reload gm_tickets'),(651,'Command: reload gossip_menu'),(652,'Command: reload gossip_menu_option'),(653,'Command: reload item_enchantment_template'),(654,'Command: reload item_loot_template'),(655,'Command: reload item_set_names'),(656,'Command: reload lfg_dungeon_rewards'),(657,'Command: reload locales_achievement_reward'),(658,'Command: reload locales_creature'),(659,'Command: reload locales_creature_text'),(660,'Command: reload locales_gameobject'),(661,'Command: reload locales_gossip_menu_option'),(662,'Command: reload locales_item'),(663,'Command: reload locales_item_set_name'),(664,'Command: reload locales_npc_text'),(665,'Command: reload locales_page_text'),(666,'Command: reload locales_points_of_interest'),(667,'Command: reload locales_quest'),(668,'Command: reload mail_level_reward'),(669,'Command: reload mail_loot_template'),(670,'Command: reload milling_loot_template'),(671,'Command: reload npc_spellclick_spells'),(672,'Command: reload npc_trainer'),(673,'Command: reload npc_vendor'),(674,'Command: reload page_text'),(675,'Command: reload pickpocketing_loot_template'),(676,'Command: reload points_of_interest'),(677,'Command: reload prospecting_loot_template'),(678,'Command: reload quest_poi'),(679,'Command: reload quest_template'),(680,'Command: reload rbac'),(681,'Command: reload reference_loot_template'),(682,'Command: reload reserved_name'),(683,'Command: reload reputation_reward_rate'),(684,'Command: reload reputation_spillover_template'),(685,'Command: reload skill_discovery_template'),(686,'Command: reload skill_extra_item_template'),(687,'Command: reload skill_fishing_base_level'),(688,'Command: reload skinning_loot_template'),(689,'Command: reload smart_scripts'),(690,'Command: reload spell_required'),(691,'Command: reload spell_area'),(692,'Command: reload spell_bonus_data'),(693,'Command: reload spell_group'),(694,'Command: reload spell_learn_spell'),(695,'Command: reload spell_loot_template'),(696,'Command: reload spell_linked_spell'),(697,'Command: reload spell_pet_auras'),(698,'Command: reload spell_proc_event'),(699,'Command: reload spell_proc'),(700,'Command: reload spell_scripts'),(701,'Command: reload spell_target_position'),(702,'Command: reload spell_threats'),(703,'Command: reload spell_group_stack_rules'),(704,'Command: reload trinity_string'),(705,'Command: reload warden_action'),(706,'Command: reload waypoint_scripts'),(707,'Command: reload waypoint_data'),(708,'Command: reload vehicle_accessory'),(709,'Command: reload vehicle_template_accessory'),(710,'Command: reset'),(711,'Command: reset achievements'),(712,'Command: reset honor'),(713,'Command: reset level'),(714,'Command: reset spells'),(715,'Command: reset stats'),(716,'Command: reset talents'),(717,'Command: reset all'),(718,'Command: server'),(719,'Command: server corpses'),(720,'Command: server exit'),(721,'Command: server idlerestart'),(722,'Command: server idlerestart cancel'),(723,'Command: server idleshutdown'),(724,'Command: server idleshutdown cancel'),(725,'Command: server info'),(726,'Command: server plimit'),(727,'Command: server restart'),(728,'Command: server restart cancel'),(729,'Command: server set'),(730,'Command: server set closed'),(731,'Command: server set difftime'),(732,'Command: server set loglevel'),(733,'Command: server set motd'),(734,'Command: server shutdown'),(735,'Command: server shutdown cancel'),(736,'Command: server motd'),(737,'Command: tele'),(738,'Command: tele add'),(739,'Command: tele del'),(740,'Command: tele name'),(741,'Command: tele group'),(742,'Command: ticket'),(743,'Command: ticket assign'),(744,'Command: ticket close'),(745,'Command: ticket closedlist'),(746,'Command: ticket comment'),(747,'Command: ticket complete'),(748,'Command: ticket delete'),(749,'Command: ticket escalate'),(750,'Command: ticket escalatedlist'),(751,'Command: ticket list'),(752,'Command: ticket onlinelist'),(753,'Command: ticket reset'),(754,'Command: ticket response'),(755,'Command: ticket response append'),(756,'Command: ticket response appendln'),(757,'Command: ticket togglesystem'),(758,'Command: ticket unassign'),(759,'Command: ticket viewid'),(760,'Command: ticket viewname'),(761,'Command: titles'),(762,'Command: titles add'),(763,'Command: titles current'),(764,'Command: titles remove'),(765,'Command: titles set'),(766,'Command: titles set mask'),(767,'Command: wp'),(768,'Command: wp add'),(769,'Command: wp event'),(770,'Command: wp load'),(771,'Command: wp modify'),(772,'Command: wp unload'),(773,'Command: wp reload'),(774,'Command: wp show'),(777,'Command: mailbox'); /*!40000 ALTER TABLE `rbac_permissions` ENABLE KEYS */; UNLOCK TABLES; @@ -390,6 +533,8 @@ CREATE TABLE `realmlist` ( `allowedSecurityLevel` tinyint(3) unsigned NOT NULL DEFAULT '0', `population` float unsigned NOT NULL DEFAULT '0', `gamebuild` int(10) unsigned NOT NULL DEFAULT '15595', + `Region` tinyint(3) unsigned NOT NULL DEFAULT '2', + `Battlegroup` tinyint(3) unsigned NOT NULL DEFAULT '1', PRIMARY KEY (`id`), UNIQUE KEY `idx_name` (`name`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='Realm System'; @@ -401,7 +546,7 @@ CREATE TABLE `realmlist` ( LOCK TABLES `realmlist` WRITE; /*!40000 ALTER TABLE `realmlist` DISABLE KEYS */; -INSERT INTO `realmlist` VALUES (1,'Trinity','127.0.0.1','127.0.0.1','255.255.255.0',8085,1,0,1,0,0,15595); +INSERT INTO `realmlist` VALUES (1,'Trinity','127.0.0.1','127.0.0.1','255.255.255.0',8085,1,0,1,0,0,15595,2,1); /*!40000 ALTER TABLE `realmlist` ENABLE KEYS */; UNLOCK TABLES; diff --git a/sql/updates/auth/2014_04_26_00_rbac_permissions.sql b/sql/updates/auth/2014_04_26_00_auth_rbac_permissions.sql index 11beed8f106..11beed8f106 100644 --- a/sql/updates/auth/2014_04_26_00_rbac_permissions.sql +++ b/sql/updates/auth/2014_04_26_00_auth_rbac_permissions.sql diff --git a/sql/updates/auth/2014_04_28_00_rbac_permissions.sql b/sql/updates/auth/2014_04_28_00_auth_rbac_permissions.sql index 290052764dd..290052764dd 100644 --- a/sql/updates/auth/2014_04_28_00_rbac_permissions.sql +++ b/sql/updates/auth/2014_04_28_00_auth_rbac_permissions.sql diff --git a/sql/updates/auth/2014_05_06_00_auth_battlenet_434.sql b/sql/updates/auth/2014_05_06_00_auth_battlenet_434.sql new file mode 100644 index 00000000000..704902e9742 --- /dev/null +++ b/sql/updates/auth/2014_05_06_00_auth_battlenet_434.sql @@ -0,0 +1,147 @@ +ALTER TABLE `realmlist` + ADD `Region` tinyint(3) UNSIGNED NOT NULL DEFAULT 2 AFTER `gamebuild`, + ADD `Battlegroup` tinyint(3) UNSIGNED NOT NULL DEFAULT 0 AFTER `Region`; + +-- +-- Table structure for table `battlenet_account_bans` +-- + +DROP TABLE IF EXISTS `battlenet_account_bans`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `battlenet_account_bans` ( + `id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Account id', + `bandate` int(10) unsigned NOT NULL DEFAULT '0', + `unbandate` int(10) unsigned NOT NULL DEFAULT '0', + `bannedby` varchar(50) NOT NULL, + `banreason` varchar(255) NOT NULL, + `active` tinyint(3) unsigned NOT NULL DEFAULT '1', + PRIMARY KEY (`id`,`bandate`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Ban List'; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `battlenet_account_bans` +-- + +LOCK TABLES `battlenet_account_bans` WRITE; +/*!40000 ALTER TABLE `battlenet_account_bans` DISABLE KEYS */; +/*!40000 ALTER TABLE `battlenet_account_bans` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `battlenet_accounts` +-- + +DROP TABLE IF EXISTS `battlenet_accounts`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `battlenet_accounts` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Identifier', + `email` varchar(320) NOT NULL, + `sha_pass_hash` varchar(64) NOT NULL DEFAULT '', + `v` varchar(256) NOT NULL DEFAULT '', + `s` varchar(64) NOT NULL DEFAULT '', + `joindate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `last_ip` varchar(15) NOT NULL DEFAULT '127.0.0.1', + `failed_logins` int(10) unsigned NOT NULL DEFAULT '0', + `locked` tinyint(3) unsigned NOT NULL DEFAULT '0', + `lock_country` varchar(2) NOT NULL DEFAULT '00', + `last_login` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', + `online` tinyint(3) unsigned NOT NULL DEFAULT '0', + `locale` tinyint(3) unsigned NOT NULL DEFAULT '0', + `os` varchar(3) NOT NULL DEFAULT '', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8 COMMENT='Account System'; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- Table structure for table `battlenet_components` +-- + +DROP TABLE IF EXISTS `battlenet_components`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `battlenet_components` ( + `Program` varchar(4) NOT NULL, + `Platform` varchar(4) NOT NULL, + `Build` int(11) unsigned NOT NULL, + PRIMARY KEY (`Program`,`Platform`,`Build`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `battlenet_components` +-- + +LOCK TABLES `battlenet_components` WRITE; +/*!40000 ALTER TABLE `battlenet_components` DISABLE KEYS */; +INSERT INTO `battlenet_components` VALUES +('Bnet','Cmp1',3), +('Bnet','Win',21719), +('Bnet','Win',26487), +('Bnet','Wn64',26487), +('Tool','Win',1569), +('Tool','Win',2736), +('WoW','base',12340), +('WoW','base',15595), +('WoW','enGB',12340), +('WoW','enGB',15595), +('WoW','enUS',12340), +('WoW','enUS',15595), +('WoW','Win',12340), +('WoW','Win',15595), +('WoW','Wn64',15595); +/*!40000 ALTER TABLE `battlenet_components` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `battlenet_modules` +-- + +DROP TABLE IF EXISTS `battlenet_modules`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `battlenet_modules` ( + `Hash` varchar(64) NOT NULL, + `Name` varchar(64) NOT NULL DEFAULT '', + `Type` varchar(8) NOT NULL, + `System` varchar(8) NOT NULL, + `Data` text, + PRIMARY KEY (`Hash`), + UNIQUE KEY `uk_name_type_system` (`Name`,`Type`,`System`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `battlenet_modules` +-- + +LOCK TABLES `battlenet_modules` WRITE; +/*!40000 ALTER TABLE `battlenet_modules` DISABLE KEYS */; +INSERT INTO `battlenet_modules` VALUES +('19c91b68752b7826df498bf73aca1103c86962a9a55a0a7033e5ad895f4d927c','Password','auth','Mc64',NULL), +('1af5418a448f8ad05451e3f7dbb2d9af9cb13458eea2368ebfc539476b954f1c','RiskFingerprint','auth','Mc64',NULL), +('207640724f4531d3b2a21532224d1486e8c4d2d805170381cbc3093264157960','SelectGameAccount','auth','Mac',NULL), +('2e6d53adab37a41542b38e01f62cd365eab8805ed0de73c307cc6d9d1dfe478c','Password','auth','Win',NULL), +('36b27cd911b33c61730a8b82c8b2495fd16e8024fc3b2dde08861c77a852941c','Thumbprint','auth','Win','E716F4F0A01EB9C032A6C1393356A4F766F067949D71023C0CFC0613718966EF814E65CC6EE70C432A7F8AFD8A062B52603A2697E851D231D72C0277614181D713369B1E8E4BEEAB72045A9AAD45F319DB918ECDDB83C8EF8B7510600D391D45E7FEC0BEEAE904A5F9FA620F1CCDAD699D84A4739CE669B5A551831E396214E13B4C88F573F5CDC784CD01530C086B674C03BEB66403A0F87ED17ABBB403DE54CF31BE828A20C566C22E4D4263AA77220B0644D99245345BCAC276EA06925EB984D664725C3CB757140AFE12E27CB996F17159B1057E9B58B78BBB5A139C9FF6215A0D250B75FC9DD435655DDEADCD6CFD84800792C146B3633188ECEB53D2038C185E0BD51A9E6C70FD38ADF530F8DF50FB62053C5E894897AB7DD65C7AC80665F18E7989BE6E30F15E939751123D6D8A44F033175301D15AAAD2AEA06FAC60BA4065846AE938F32B1CB15F16DC0E76792A7332346896048065D17C059899E1D2300E402BD0EA74265DA6A42B1C854E2470D7B21AE4A2DAE90E602A759B2CA0EE610B50D5389DB89335D5451FE76DD85B09FD5297D6F9EFB6C34CE885007F7DF20D6A524E0C3E772FA04B3DD2E014D3A337A790943DAD523CBB5453F4FDF8E74DFE361BD5F25AB31952B478148B570DF5762643F32B994FEC99A747E4A265A66EE84A53509EC285C84679606049314FC526C61B537AC8061C788F8B86F52208'), +('393ca8d75aff6f04f79532cf95a88b91e5743bc59121520ac31fc4508019fe60','Token','auth','Mac',NULL), +('3c2f63e5949aa6fd6cf330b109ca5b9adcd215beac846b7462ed3aa01d5ad6bb','Password','auth','Mac',NULL), +('52e2978db6468dfade7c61da89513f443c9225692b5085fbe956749870993703','SelectGameAccount','auth','Mc64',NULL), +('548b5ef9e0dd5c2f89f59c3e0979249b27505c51f0c77d2b27133726eaee0ad0','Thumbprint','auth','Mac','E716F4F0A01EB9C032A6C1393356A4F766F067949D71023C0CFC0613718966EF814E65CC6EE70C432A7F8AFD8A062B52603A2697E851D231D72C0277614181D713369B1E8E4BEEAB72045A9AAD45F319DB918ECDDB83C8EF8B7510600D391D45E7FEC0BEEAE904A5F9FA620F1CCDAD699D84A4739CE669B5A551831E396214E13B4C88F573F5CDC784CD01530C086B674C03BEB66403A0F87ED17ABBB403DE54CF31BE828A20C566C22E4D4263AA77220B0644D99245345BCAC276EA06925EB984D664725C3CB757140AFE12E27CB996F17159B1057E9B58B78BBB5A139C9FF6215A0D250B75FC9DD435655DDEADCD6CFD84800792C146B3633188ECEB53D2038C185E0BD51A9E6C70FD38ADF530F8DF50FB62053C5E894897AB7DD65C7AC80665F18E7989BE6E30F15E939751123D6D8A44F033175301D15AAAD2AEA06FAC60BA4065846AE938F32B1CB15F16DC0E76792A7332346896048065D17C059899E1D2300E402BD0EA74265DA6A42B1C854E2470D7B21AE4A2DAE90E602A759B2CA0EE610B50D5389DB89335D5451FE76DD85B09FD5297D6F9EFB6C34CE885007F7DF20D6A524E0C3E772FA04B3DD2E014D3A337A790943DAD523CBB5453F4FDF8E74DFE361BD5F25AB31952B478148B570DF5762643F32B994FEC99A747E4A265A66EE84A53509EC285C84679606049314FC526C61B537AC8061C788F8B86F52208'), +('5e298e530698af905e1247e51ef0b109b352ac310ce7802a1f63613db980ed17','RiskFingerprint','auth','Win',NULL), +('851c1d2ef926e9b9a345a460874e65517195129b9e3bdec7cc77710fa0b1fad6','Password','auth','Wn64',NULL), +('894d25d3219d97d085ea5a8b98e66df5bd9f460ec6f104455246a12b8921409d','SelectGameAccount','auth','Wn64',NULL), +('8c43bda10be33a32abbc09fb2279126c7f5953336391276cff588565332fcd40','RiskFingerprint','auth','Wn64',NULL), +('a1edab845d9e13e9c84531369be2f61b930a37c8e7a9c66d11ef8963380e178a','Token','auth','Mc64',NULL), +('a330f388b6687f8a42fe8fbb592a3df724b20b65fb0989342bb8261f2f452318','Token','auth','Wn64',NULL), +('abc6bb719a73ec1055296001910e26afa561f701ad9995b1ecd7f55f9d3ca37c','SelectGameAccount','auth','Win',NULL), +('b37136b39add83cfdbafa81857de3dd8f15b34e0135ec6cd9c3131d3a578d8c2','Thumbprint','auth','Mc64','E716F4F0A01EB9C032A6C1393356A4F766F067949D71023C0CFC0613718966EF814E65CC6EE70C432A7F8AFD8A062B52603A2697E851D231D72C0277614181D713369B1E8E4BEEAB72045A9AAD45F319DB918ECDDB83C8EF8B7510600D391D45E7FEC0BEEAE904A5F9FA620F1CCDAD699D84A4739CE669B5A551831E396214E13B4C88F573F5CDC784CD01530C086B674C03BEB66403A0F87ED17ABBB403DE54CF31BE828A20C566C22E4D4263AA77220B0644D99245345BCAC276EA06925EB984D664725C3CB757140AFE12E27CB996F17159B1057E9B58B78BBB5A139C9FF6215A0D250B75FC9DD435655DDEADCD6CFD84800792C146B3633188ECEB53D2038C185E0BD51A9E6C70FD38ADF530F8DF50FB62053C5E894897AB7DD65C7AC80665F18E7989BE6E30F15E939751123D6D8A44F033175301D15AAAD2AEA06FAC60BA4065846AE938F32B1CB15F16DC0E76792A7332346896048065D17C059899E1D2300E402BD0EA74265DA6A42B1C854E2470D7B21AE4A2DAE90E602A759B2CA0EE610B50D5389DB89335D5451FE76DD85B09FD5297D6F9EFB6C34CE885007F7DF20D6A524E0C3E772FA04B3DD2E014D3A337A790943DAD523CBB5453F4FDF8E74DFE361BD5F25AB31952B478148B570DF5762643F32B994FEC99A747E4A265A66EE84A53509EC285C84679606049314FC526C61B537AC8061C788F8B86F52208'), +('c0f38d05aa1b83065e839c9bd96c831e9f7e42477085138752657a6a9bb9c520','RiskFingerprint','auth','Mac',NULL), +('c3a1ac0694979e709c3b5486927e558af1e2be02ca96e5615c5a65aacc829226','Thumbprint','auth','Wn64','E716F4F0A01EB9C032A6C1393356A4F766F067949D71023C0CFC0613718966EF814E65CC6EE70C432A7F8AFD8A062B52603A2697E851D231D72C0277614181D713369B1E8E4BEEAB72045A9AAD45F319DB918ECDDB83C8EF8B7510600D391D45E7FEC0BEEAE904A5F9FA620F1CCDAD699D84A4739CE669B5A551831E396214E13B4C88F573F5CDC784CD01530C086B674C03BEB66403A0F87ED17ABBB403DE54CF31BE828A20C566C22E4D4263AA77220B0644D99245345BCAC276EA06925EB984D664725C3CB757140AFE12E27CB996F17159B1057E9B58B78BBB5A139C9FF6215A0D250B75FC9DD435655DDEADCD6CFD84800792C146B3633188ECEB53D2038C185E0BD51A9E6C70FD38ADF530F8DF50FB62053C5E894897AB7DD65C7AC80665F18E7989BE6E30F15E939751123D6D8A44F033175301D15AAAD2AEA06FAC60BA4065846AE938F32B1CB15F16DC0E76792A7332346896048065D17C059899E1D2300E402BD0EA74265DA6A42B1C854E2470D7B21AE4A2DAE90E602A759B2CA0EE610B50D5389DB89335D5451FE76DD85B09FD5297D6F9EFB6C34CE885007F7DF20D6A524E0C3E772FA04B3DD2E014D3A337A790943DAD523CBB5453F4FDF8E74DFE361BD5F25AB31952B478148B570DF5762643F32B994FEC99A747E4A265A66EE84A53509EC285C84679606049314FC526C61B537AC8061C788F8B86F52208'), +('fbe675a99fb5f4b7fb3eb5e5a22add91a4cabf83e3c5930c6659ad13c457ba18','Token','auth','Win',NULL); +/*!40000 ALTER TABLE `battlenet_modules` ENABLE KEYS */; +UNLOCK TABLES; + +ALTER TABLE `account` + ADD `battlenet_account` int(10) unsigned DEFAULT NULL AFTER `recruiter`, + ADD CONSTRAINT `fk_bnet_acc` FOREIGN KEY (`battlenet_account`) REFERENCES `battlenet_accounts` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT; diff --git a/sql/updates/auth/2014_06_01_00_auth_battlenet_434.sql b/sql/updates/auth/2014_06_01_00_auth_battlenet_434.sql new file mode 100644 index 00000000000..ee88c91b323 --- /dev/null +++ b/sql/updates/auth/2014_06_01_00_auth_battlenet_434.sql @@ -0,0 +1,8 @@ +ALTER TABLE `battlenet_accounts` ADD `sessionKey` VARCHAR(128) NOT NULL DEFAULT '' AFTER `s`; + +DELETE FROM `battlenet_modules` WHERE `Name`='Resume'; +INSERT INTO `battlenet_modules` VALUES +('bfe4ceb47700aa872e815e007e27df955d4cd4bc1fe731039ee6498ce209f368','Resume','auth','Win',NULL), +('00ffd88a437afbb88d7d4b74be2e3b43601605ee229151aa9f4bebb29ef66280','Resume','auth','Mac',NULL), +('898166926805f897804bdbbf40662c9d768590a51a0b26c40dbcdf332ba11974','Resume','auth','Wn64',NULL), +('304627d437c38500c0b5ca0c6220eeade91390e52a2b005ff3f7754afa1f93cd','Resume','auth','Mc64',NULL); diff --git a/sql/updates/auth/2014_06_08_00_auth_account_434.sql b/sql/updates/auth/2014_06_08_00_auth_account_434.sql new file mode 100644 index 00000000000..bc57136dc07 --- /dev/null +++ b/sql/updates/auth/2014_06_08_00_auth_account_434.sql @@ -0,0 +1,3 @@ +ALTER TABLE `account` + ADD `battlenet_index` tinyint(3) unsigned DEFAULT NULL AFTER `battlenet_account`, + ADD UNIQUE KEY `uk_bnet_acc` (`battlenet_account`, `battlenet_index`); diff --git a/sql/updates/auth/2014_06_08_01_auth_account_434.sql b/sql/updates/auth/2014_06_08_01_auth_account_434.sql new file mode 100644 index 00000000000..dc05a98d17b --- /dev/null +++ b/sql/updates/auth/2014_06_08_01_auth_account_434.sql @@ -0,0 +1,3 @@ +DELETE FROM `battlenet_components` WHERE `Program`='WoW' AND `Build`=12340; +DELETE FROM `battlenet_components` WHERE `Program`='Tool' AND `Build`=1569; +DELETE FROM `battlenet_components` WHERE `Program`='Bnet' AND `Build`=21719; diff --git a/sql/updates/auth/2014_06_08_02_rbac_permissions_434.sql b/sql/updates/auth/2014_06_08_02_rbac_permissions_434.sql new file mode 100644 index 00000000000..508e1147e9c --- /dev/null +++ b/sql/updates/auth/2014_06_08_02_rbac_permissions_434.sql @@ -0,0 +1,19 @@ +DELETE FROM `rbac_permissions` WHERE `id` IN (207,208,209,210,211,212,213); +INSERT INTO `rbac_permissions` (`id`, `name`) VALUES +(207, 'Command: battlenetaccount'), +(208, 'Command: battlenetaccount create'), +(209, 'Command: battlenetaccount lock country'), +(210, 'Command: battlenetaccount lock ip'), +(211, 'Command: battlenetaccount password'), +(212, 'Command: battlenetaccount set'), +(213, 'Command: battlenetaccount set password'); + +DELETE FROM `rbac_linked_permissions` WHERE `linkedId` IN (207,208,209,210,211,212,213); +INSERT INTO `rbac_linked_permissions` (`id`, `linkedId`) VALUES +(199, 207), +(196, 208), +(199, 209), +(199, 210), +(199, 211), +(196, 212), +(196, 213); diff --git a/sql/updates/characters/2014_04_30_00_character_queststatus_seasonal.sql b/sql/updates/characters/2014_04_30_00_characters_character_queststatus_seasonal.sql index 0c063b29df0..0c063b29df0 100644 --- a/sql/updates/characters/2014_04_30_00_character_queststatus_seasonal.sql +++ b/sql/updates/characters/2014_04_30_00_characters_character_queststatus_seasonal.sql diff --git a/sql/updates/world/2014_06_03_world_creature.sql b/sql/updates/world/2014_06_03_00_world_creature.sql index 81953785fd5..81953785fd5 100644 --- a/sql/updates/world/2014_06_03_world_creature.sql +++ b/sql/updates/world/2014_06_03_00_world_creature.sql diff --git a/sql/updates/world/2014_06_08_00_world_trinity_string_434.sql b/sql/updates/world/2014_06_08_00_world_trinity_string_434.sql new file mode 100644 index 00000000000..806ff6bd233 --- /dev/null +++ b/sql/updates/world/2014_06_08_00_world_trinity_string_434.sql @@ -0,0 +1,14 @@ +DELETE FROM `trinity_string` WHERE `entry`=1029; + +INSERT INTO `trinity_string` (`entry`, `content_default`) VALUES +(1029, 'Account name must contain the @ symbol.'); + +DELETE FROM `command` WHERE `permission` IN (207,208,209,210,211,212,213); +INSERT INTO `command` (`name`, `permission`, `help`) VALUES +('battlenetaccount', 207, 'Syntax: .battlenetaccount $subcommand\r\nType .battlenetaccount to see the list of possible subcommands or .help account set $subcommand to see info on subcommands.'), +('battlenetaccount create', 208, 'Syntax: .battlenetaccount create $account $password\r\nCreate battle.net account and set password to it. Account must contain the @ symbol.'), +('battlenetaccount lock country', 209, 'Syntax: .battlenetaccount lock country [on|off]\r\nAllow login to account only from current used Country or remove this requirement.'), +('battlenetaccount lock ip', 210, 'Syntax: .battlenetaccount lock ip [on|off]\nAllow login to account only from current used IP or remove this requirement.'), +('battlenetaccount password', 211, 'Syntax: .battlenetaccount password $old_password $new_password $new_password\nChange your account password.'), +('battlenetaccount set', 212, 'Syntax: .battlenetaccount set $subcommand\nType .battlenetaccount set to see the list of possible subcommands or .help account set $subcommand to see info on subcommands.'), +('battlenetaccount set password', 213, 'Syntax: .battlenetaccount set password $account $password $password\nSet password for account.'); diff --git a/sql/updates/world/2014_06_08_01_world_gameobject.sql b/sql/updates/world/2014_06_08_01_world_gameobject.sql new file mode 100644 index 00000000000..844d32ed393 --- /dev/null +++ b/sql/updates/world/2014_06_08_01_world_gameobject.sql @@ -0,0 +1,17 @@ +UPDATE `gameobject` SET `phaseMask`=1 WHERE `id` IN (192161, 192162); +UPDATE `gameobject` SET `phaseMask`=9 WHERE `id`=193985; +UPDATE `gameobject` SET `phaseMask`=12 WHERE `id` IN (190791, 190792, 190793, 190919, 190920, 190921, 190922, 190923, 190924, 190925, 190926, 190927, 190928, 190929); +UPDATE `gameobject` SET `phaseMask`=19 WHERE `id` IN (190799, 190859, 190860, 190861, 190862, 190863, 190864, 190865, 190866, 190867, 190868, 190869, 190870, 190871, 190872, 190873, 190874, 190875, 190876, 190877, 190878, 190879, 190880, 190881, 190882, 190883, 190884, 190885, 190886, 190887, 190888, 190889, 190890, 190891, 190892, 190893, 190898, 190899, 190900, 190901, 190902, 190903, 190904, 190905, 190906, 190907, 190908, 190909, 190910, 190911, 190930, 190931, 190932, 190933, 190934); +UPDATE `gameobject` SET `phaseMask`=32 WHERE `id` IN (192273, 192274, 192406, 192407, 192416, 192417, 192418, 192433); +UPDATE `gameobject` SET `phaseMask`=35 WHERE `id` IN (190800, 191166, 191167, 191169, 191171, 191172, 191173, 191178, 191191); +UPDATE `gameobject` SET `phaseMask`=51 WHERE `id`=190789; +UPDATE `gameobject` SET `phaseMask`=64 WHERE `id` IN (192269, 192277, 192278, 192414, 192429, 193110, 193111, 193112, 193113, 193114, 193115, 193116, 193117, 193118, 193119, 193120, 193121, 193122, 193123); +UPDATE `gameobject` SET `phaseMask`=66 WHERE `id`=192579; +UPDATE `gameobject` SET `phaseMask`=128 WHERE `id` IN (191261, 191262, 191263, 191264, 191265, 191266, 191267, 191268, 191269, 191270, 191271); +UPDATE `gameobject` SET `phaseMask`=129 WHERE `id` IN (192575, 192578); +UPDATE `gameobject` SET `phaseMask`=193 WHERE `id` IN (192576, 192577); +UPDATE `gameobject` SET `phaseMask`=198 WHERE `id` IN (192934, 192935, 192936, 192937, 192938, 192953, 192954, 192955, 192956, 192957, 192981); +UPDATE `gameobject` SET `phaseMask`=204 WHERE `id` IN (190801, 190802, 190804, 190805, 190806, 190807, 190808, 190809, 190810, 190811, 190812, 190813, 190814, 190815, 190894, 190895, 190896, 190912, 190913, 190935, 191165, 191168, 191170, 191174, 191175, 191176, 191177, 191190); +UPDATE `gameobject` SET `phaseMask`=257 WHERE `id`=192038; +UPDATE `gameobject` SET `phaseMask`=510 WHERE `id` IN (192958, 192959, 192960, 192961, 192962, 192963, 192964, 192965, 192966, 192967, 192968, 192969, 192970, 192971, 192972, 192973, 192974, 192975, 192976, 192977, 192978, 192979, 192980, 192982, 192983, 192985, 192986, 192987, 192988, 192989, 192990, 192991, 192992, 192993, 192994, 192995, 192996, 192997, 192999, 193000, 193001, 193002); +UPDATE `gameobject` SET `phaseMask`=511 WHERE `id` IN (192522, 192787); diff --git a/sql/updates/world/2014_06_08_02_world_gameobject.sql b/sql/updates/world/2014_06_08_02_world_gameobject.sql new file mode 100644 index 00000000000..5b5bfa9a90c --- /dev/null +++ b/sql/updates/world/2014_06_08_02_world_gameobject.sql @@ -0,0 +1,40 @@ +SET @OGUID := 75166; + +DELETE FROM `gameobject` WHERE `guid` BETWEEN @OGUID+0 AND @OGUID+28; +INSERT INTO `gameobject` (`guid`, `id`, `map`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`) VALUES +(@OGUID+0, 192252, 571, 128, 5154.37, 2853.23, 409.183, 3.14159, 0, 0, 1, 0), -- Alliance Banner +(@OGUID+1, 192253, 571, 128, 5154.42, 2828.93, 409.189, 3.14159, 0, 0, 1, 0), -- Alliance Banner +(@OGUID+2, 192266, 571, 64, 4452.8, 2639, 358.552, 1.4748, 0, 0, -0.672366, 0.740219), -- Alliance Banner +(@OGUID+3, 192267, 571, 128, 4452.76, 2639.14, 358.444, 1.67552, 0, 0, 0.743145, 0.66913), -- Horde Banner +(@OGUID+4, 192268, 571, 128, 4526.51, 2810.18, 390.986, 3.26377, 0, 0, 0.998135, -0.061049), -- Horde Banner +(@OGUID+5, 192270, 571, 64, 4424.71, 2975.6, 367.387, 1.69297, 0, 0, 0.748955, 0.662621), -- Alliance Banner +(@OGUID+6, 192271, 571, 128, 4424.74, 2975.6, 367.227, 1.7017, 0, 0, 0.75184, 0.659346), -- Horde Banner +(@OGUID+7, 192272, 571, 16, 4417.93, 2324.81, 371.219, 3.09796, 0, 0, 0.999762, 0.021815), -- Horde Banner +(@OGUID+8, 192275, 571, 16, 4424.03, 3286.61, 371.418, 3.14159, 0, 0, 1, 0), -- Horde Banner +(@OGUID+9, 192276, 571, 128, 4572.94, 3475.42, 362.805, 1.37881, 0, 0, 0.636078, 0.771625), -- Horde Banner +(@OGUID+10, 192279, 571, 128, 4433.92, 3534.2, 359.942, 1.91113, 0, 0, -0.816641, 0.577146), -- Horde Banner +(@OGUID+11, 192408, 571, 16, 4399.64, 3231.54, 368.898, 1.49226, 0, 0, 0.678801, 0.734322), -- Horde Banner +(@OGUID+12, 192409, 571, 32, 4399.59, 3231.43, 369.216, 1.67552, 0, 0, -0.743145, 0.66913), -- Alliance Banner +(@OGUID+13, 192415, 571, 64, 4517.79, 2716.99, 387.57, 1.53589, 0, 0, -0.694658, 0.71934), -- Alliance Banner +(@OGUID+14, 192423, 571, 64, 4563.73, 2171.15, 367.68, 1.30027, 0, 0, 0.605294, 0.796002), -- Alliance Banner +(@OGUID+15, 192424, 571, 128, 4563.7, 2171.03, 367.607, 1.82387, 0, 0, -0.79069, 0.612217), -- Horde Banner +(@OGUID+16, 192430, 571, 64, 4434.56, 2883.45, 406.025, 0.759216, 0, 0, 0.370557, 0.92881), -- Alliance Banner +(@OGUID+17, 192431, 571, 64, 4349.9, 2885.56, 406.105, 1.6057, 0, 0, 0.71934, 0.694658), -- Alliance Banner +(@OGUID+18, 192432, 571, 16, 4401.62, 3377.48, 363.12, 1.53589, 0, 0, 0.694658, 0.71934), -- Horde Banner +(@OGUID+19, 192440, 571, 128, 4438.38, 3361.01, 371.814, 0.0348707, 0, 0, -0.017452, 0.999848), -- Horde Banner +(@OGUID+20, 192441, 571, 16, 4448.15, 3235.61, 370.617, 1.56207, 0, 0, -0.704015, 0.710185), -- Horde Banner +(@OGUID+21, 192442, 571, 128, 4350.04, 2885.61, 406.329, 1.58825, 0, 0, 0.713251, 0.700909), -- Horde Banner +(@OGUID+22, 192443, 571, 128, 4434.33, 2883.24, 406.346, 0.767944, 0, 0, 0.374607, 0.927184), -- Horde Banner +(@OGUID+23, 192444, 571, 128, 4464.17, 2855.32, 406.391, 0.802851, 0, 0, 0.390731, 0.920505), -- Horde Banner +(@OGUID+24, 192449, 571, 128, 4517.75, 2717.23, 387.812, 1.53589, 0, 0, -0.694658, 0.71934), -- Horde Banner +(@OGUID+25, 192450, 571, 128, 4387.59, 2719.9, 390.201, 1.51843, 0, 0, -0.688354, 0.725375), -- Horde Banner +(@OGUID+26, 192451, 571, 16, 4408.65, 2422.67, 377.454, 1.58825, 0, 0, 0.713251, 0.700909), -- Horde Banner +(@OGUID+27, 192452, 571, 128, 4416.8, 2414.04, 377.487, 0.00895035, 0, 0, 0.004363, 0.99999), -- Horde Banner +(@OGUID+28, 192453, 571, 16, 4417.56, 2301.07, 377.43, 0.017442, 0, 0, 0.008727, 0.999962); -- Horde Banner + + +UPDATE `gameobject` SET `position_x`=4526.46, `position_y`=2810.18, `position_z`=391.2, `orientation`=3.28995 WHERE `id`=192269; -- Horde Banner +UPDATE `gameobject` SET `position_x`=4991.04, `position_y`=2525.72, `position_z`=340.366, `orientation`=4.04916 WHERE `id`=192290; -- Horde Banner +UPDATE `gameobject` SET `position_x`=4991.08, `position_y`=2525.76, `position_z`=340.918, `orientation`=4.04044 WHERE `id`=192291; -- Alliance Banner +UPDATE `gameobject` SET `position_x`=5352.15, `position_y`=3054.77, `position_z`=444.61, `orientation`=1.57952 WHERE `id`=192376; -- Horde Banner +UPDATE `gameobject` SET `position_x`=4408.57, `position_y`=2422.61, `position_z`=377.179, `orientation`=1.58825 WHERE `id`=192416; -- Alliance Banner diff --git a/sql/updates/world/2014_06_08_03_world_gameobject.sql b/sql/updates/world/2014_06_08_03_world_gameobject.sql new file mode 100644 index 00000000000..8fe57fa39b5 --- /dev/null +++ b/sql/updates/world/2014_06_08_03_world_gameobject.sql @@ -0,0 +1 @@ +DELETE FROM `gameobject` WHERE `guid` IN (66459, 66460, 66461, 66462, 66463, 66464, 66465, 66466, 66467, 66468, 66469, 66470, 66478, 66479, 66516, 66518, 66520, 66600, 66601, 66602, 66603, 66604, 66605, 66606, 66607, 66608, 66609, 66610, 74688, 74690, 74696, 74698, 74702, 74704, 74706, 74712, 74714, 74720, 74722, 74724, 74726, 74728, 74730, 74732, 74734, 74736, 74738, 74740, 74742, 74744, 74746, 74748, 74750, 74752, 74754, 74756, 74758, 74760, 74762, 74764, 74766, 74768, 74770, 74772); diff --git a/sql/updates/world/2014_06_09_00_world_quest_template.sql b/sql/updates/world/2014_06_09_00_world_quest_template.sql new file mode 100644 index 00000000000..240dd4a75d2 --- /dev/null +++ b/sql/updates/world/2014_06_09_00_world_quest_template.sql @@ -0,0 +1,3 @@ +-- +UPDATE `quest_template` SET `RequestItemsText` = 'What business is it you wish to speak of, $N? You must feel it is important if you continue to pester me.' WHERE `id` = 6522; +UPDATE `quest_template` SET `OfferRewardText` = 'I recognize the insignia on this scroll, $N. You found this on that crone who reigns over Razorfen Kraul? Interesting.$b$bThe Scourge aren''t content with one continent it seems. This Ambassador Malcin--the one who wrote the note--is one of the Scourge''s plagued servants, a human diplomat to the kingdom of Lordaeron before things... changed.$b$bIf the Scourge are trying to gain a foothold in Kalimdor, then it is up to us to act.' WHERE `id` = 6522; diff --git a/sql/updates/world/2014_06_11_01_world_spell_script_names.sql b/sql/updates/world/2014_06_11_01_world_spell_script_names.sql new file mode 100644 index 00000000000..433f1cf8b09 --- /dev/null +++ b/sql/updates/world/2014_06_11_01_world_spell_script_names.sql @@ -0,0 +1,3 @@ +-- +DELETE FROM `spell_script_names` WHERE `spell_id` = 50842; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES (50842, 'spell_dk_pestilence'); diff --git a/sql/updates/world/2014_06_11_02_world_fish_junk_loot_template.sql b/sql/updates/world/2014_06_11_02_world_fish_junk_loot_template.sql new file mode 100644 index 00000000000..a8dc813d4b2 --- /dev/null +++ b/sql/updates/world/2014_06_11_02_world_fish_junk_loot_template.sql @@ -0,0 +1,20 @@ +SET @FISH_JUNK_GROUP := 11799; +SET @FISH_JUNK_LOOTMODE := 32768; + +DELETE FROM fishing_loot_template WHERE `item`=@FISH_JUNK_GROUP; +INSERT INTO fishing_loot_template (`entry`, `item`, `ChanceOrQuestChance`, `lootmode`, `groupid`, `mincountOrRef`, `maxcount`) VALUES +(1, @FISH_JUNK_GROUP, 100, @FISH_JUNK_LOOTMODE, 1, -@FISH_JUNK_GROUP, 1); + +DELETE FROM reference_loot_template WHERE `entry`=@FISH_JUNK_GROUP; +INSERT INTO reference_loot_template (`entry`, `item`, `ChanceOrQuestChance`, `lootmode`, `groupid`, `mincountOrRef`, `maxcount`) VALUES +(@FISH_JUNK_GROUP, 45190, 15, @FISH_JUNK_LOOTMODE, 1, 1, 1), -- [Driftwood] +(@FISH_JUNK_GROUP, 45191, 2, @FISH_JUNK_LOOTMODE, 1, 1, 1), -- [Water Snail] +(@FISH_JUNK_GROUP, 45194, 15, @FISH_JUNK_LOOTMODE, 1, 1, 1), -- [Tangled Fishing Line] +(@FISH_JUNK_GROUP, 45195, 5, @FISH_JUNK_LOOTMODE, 1, 1, 1), -- [Empty Rum Bottle] +(@FISH_JUNK_GROUP, 45196, 15, @FISH_JUNK_LOOTMODE, 1, 1, 1), -- [Tattered Cloth] +(@FISH_JUNK_GROUP, 45197, 5, @FISH_JUNK_LOOTMODE, 1, 1, 1), -- [Tree Branch] +(@FISH_JUNK_GROUP, 45198, 15, @FISH_JUNK_LOOTMODE, 1, 1, 1), -- [Weeds] +(@FISH_JUNK_GROUP, 45199, 5, @FISH_JUNK_LOOTMODE, 1, 1, 1), -- [Old Boot] +(@FISH_JUNK_GROUP, 45200, 15, @FISH_JUNK_LOOTMODE, 1, 1, 1), -- [Sickly Fish] +(@FISH_JUNK_GROUP, 45201, 3, @FISH_JUNK_LOOTMODE, 1, 1, 1), -- [Rock] +(@FISH_JUNK_GROUP, 45202, 5, @FISH_JUNK_LOOTMODE, 1, 1, 1); -- [Water Snail] diff --git a/sql/updates/world/2014_06_12_00_world_quest_template.sql b/sql/updates/world/2014_06_12_00_world_quest_template.sql new file mode 100644 index 00000000000..333aac99b0b --- /dev/null +++ b/sql/updates/world/2014_06_12_00_world_quest_template.sql @@ -0,0 +1,3 @@ +-- +UPDATE `quest_template` SET `RequestItemsText` = 'By Nozdormu''s teeth!' WHERE `id` = 24428; +UPDATE `quest_template` SET `OfferRewardText` = 'What? How did you get this? Isn''t she... Never mind the details, I suppose. You''ll be wanting one of these baubles as recompense, no doubt.' WHERE `id` = 24428; diff --git a/sql/updates/world/2014_06_12_01_world_gossip_menu_option.sql b/sql/updates/world/2014_06_12_01_world_gossip_menu_option.sql new file mode 100644 index 00000000000..ee423e3eaea --- /dev/null +++ b/sql/updates/world/2014_06_12_01_world_gossip_menu_option.sql @@ -0,0 +1,2 @@ +-- +UPDATE `gossip_menu_option` SET `action_menu_id`=1143 WHERE `menu_id`=1142 AND `id`=0; diff --git a/sql/updates/world/2014_06_14_00_world_creature_template.sql b/sql/updates/world/2014_06_14_00_world_creature_template.sql new file mode 100644 index 00000000000..19a2063571f --- /dev/null +++ b/sql/updates/world/2014_06_14_00_world_creature_template.sql @@ -0,0 +1 @@ +UPDATE `creature_template` SET `unit_class`=4,`unit_flags2`=0x10000 WHERE `entry` IN (37672,38285,38605,38786,38787,38788,38789,38790); -- Mutated Abomination diff --git a/sql/updates/world/2014_06_14_01_world_misc.sql b/sql/updates/world/2014_06_14_01_world_misc.sql new file mode 100644 index 00000000000..05261164241 --- /dev/null +++ b/sql/updates/world/2014_06_14_01_world_misc.sql @@ -0,0 +1,49 @@ +DELETE FROM `gossip_menu_option` WHERE `menu_id`=10389; +INSERT INTO `gossip_menu_option` (`menu_id`, `id`, `option_icon`, `option_text`, `OptionBroadcastTextID`, `option_id`, `box_coded`, `box_money`, `box_text`) VALUES +(10389, 0, 0, 'Teleport to the Expedition Base Camp.', 33919, 1, 0, 0, ''), -- 194569 +(10389, 1, 0, 'Teleport to the Formation Grounds.', 33920, 1, 0, 0, ''), -- 194569 +(10389, 3, 0, 'Teleport to the Colossal Forge.', 33921, 1, 0, 0, ''), -- 194569 +(10389, 4, 0, 'Teleport to the Scrapyard.', 33922, 1, 0, 0, ''), -- 194569 +(10389, 5, 0, 'Teleport to the Antechamber of Ulduar.', 33923, 1, 0, 0, ''), -- 194569 +(10389, 6, 0, 'Teleport to the Shattered Walkway.', 33924, 1, 0, 0, ''), -- 194569 +(10389, 10, 0, 'Teleport to the Conservatory of Life.', 33926, 1, 0, 0, ''), -- 194569 +(10389, 12, 0, 'Teleport to the Spark of Imagination.', 33927, 1, 0, 0, ''), -- 194569 +(10389, 15, 0, 'Teleport to the Prison of Yogg-Saron.', 33928, 1, 0, 0, ''); -- 194569 + +UPDATE `gameobject_template` SET AIName = 'SmartGameObjectAI', `ScriptName` = '' WHERE `entry`=194569; + +SET @Entry := 194569; +DELETE FROM `smart_scripts` WHERE `entryorguid`=@Entry; +DELETE FROM `smart_scripts` WHERE `source_type`=9 AND `entryorguid`=@Script; +INSERT INTO `smart_scripts` VALUES +-- Expedition Base Camp Teleport +(@ENTRY,1,0,9,62,0,100,0,10389,0,0,0,11,64014,0,0,0,0,0,7,0,0,0,0,0,0,0,'Ulduar Teleporter - On gossip select 0 - Cast "Expedition Base Camp Teleport"'), +-- Formation Grounds Teleport +(@ENTRY,1,1,9,62,0,100,0,10389,1,0,0,11,64032,0,0,0,0,0,7,0,0,0,0,0,0,0,'Ulduar Teleporter - On gossip select 1 - Cast "Formation Grounds Teleport"'), +-- Colossal Forge Teleport +(@ENTRY,1,2,9,62,0,100,0,10389,3,0,0,11,64028,0,0,0,0,0,7,0,0,0,0,0,0,0,'Ulduar Teleporter - On gossip select 3 - Cast "Colossal Forge Teleport"'), +-- Scrapyard Teleport +(@ENTRY,1,3,9,62,0,100,0,10389,4,0,0,11,64031,0,0,0,0,0,7,0,0,0,0,0,0,0,'Ulduar Teleporter - On gossip select 4 - Cast "Scrapyard Teleport"'), +-- Antechamber Teleport +(@ENTRY,1,4,9,62,0,100,0,10389,5,0,0,11,64030,0,0,0,0,0,7,0,0,0,0,0,0,0,'Ulduar Teleporter - On gossip select 5 - Cast "Antechamber Teleport"'), +-- Shattered Walkway Teleport +(@ENTRY,1,5,9,62,0,100,0,10389,6,0,0,11,64029,0,0,0,0,0,7,0,0,0,0,0,0,0,'Ulduar Teleporter - On gossip select 6 - Cast "Shattered Walkway Teleport"'), +-- Conservatory Teleport +(@ENTRY,1,6,9,62,0,100,0,10389,10,0,0,11,64024,0,0,0,0,0,7,0,0,0,0,0,0,0,'Ulduar Teleporter - On gossip select 10 - Cast "Conservatory Teleport"'), +-- Halls of Invention Teleport +(@ENTRY,1,7,9,62,0,100,0,10389,12,0,0,11,64025,0,0,0,0,0,7,0,0,0,0,0,0,0,'Ulduar Teleporter - On gossip select 12 - Cast "Halls of Invention Teleport"'), +-- Prison of Yogg-Saron Teleport +(@ENTRY,1,8,9,62,0,100,0,10389,15,0,0,11,65042,0,0,0,0,0,7,0,0,0,0,0,0,0,'Ulduar Teleporter - On gossip select 15 - Cast "Prison of Yogg-Saron Teleport"'), +-- Close gossip +(@ENTRY,1,9,0,61,0,100,0,0,0,0,0,72,0,0,0,0,0,0,7,0,0,0,0,0,0,0,'Ulduar Teleporter - Linked with Previous Event - Close gossip'); + +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=15 AND `SourceGroup`=10389; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(15, 10389, 1, 0, 0, 13, 1, 20, 2, 0, 0, 0, 0, '', 'Show options for gossip only if 2 Collossus death'), +(15, 10389, 3, 0, 0, 13, 1, 0, 3, 2, 0, 0, 0, '', 'Show options for gossip only if BOSS_LEVIATHAN done'), +(15, 10389, 4, 0, 0, 13, 1, 3, 3, 2, 0, 0, 0, '', 'Show options for gossip only if BOSS_XT002 done'), +(15, 10389, 5, 0, 0, 13, 1, 3, 3, 2, 0, 0, 0, '', 'Show options for gossip only if BOSS_XT002 done'), +(15, 10389, 6, 0, 0, 13, 1, 5, 3, 2, 0, 0, 0, '', 'Show options for gossip only if BOSS_KOLOGARN done'), +(15, 10389, 12, 0, 0, 13, 1, 5, 3, 2, 0, 0, 0, '', 'Show options for gossip only if BOSS_KOLOGARN done'), +(15, 10389, 10, 0, 0, 13, 1, 6, 3, 2, 0, 0, 0, '', 'Show options for gossip only if BOSS_AURIAYA done'), +(15, 10389, 15, 0, 0, 13, 1, 14, 3, 2, 0, 0, 0, '', 'Show options for gossip only if BOSS_VEZAX done'); diff --git a/sql/updates/world/2014_06_14_02_world_spell_script_names.sql b/sql/updates/world/2014_06_14_02_world_spell_script_names.sql new file mode 100644 index 00000000000..53b1f2f6286 --- /dev/null +++ b/sql/updates/world/2014_06_14_02_world_spell_script_names.sql @@ -0,0 +1,9 @@ +DELETE FROM `spell_script_names` WHERE `ScriptName` = 'spell_ulduar_teleporter'; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(64014, 'spell_ulduar_teleporter'), +(64032, 'spell_ulduar_teleporter'), +(64028, 'spell_ulduar_teleporter'), +(64030, 'spell_ulduar_teleporter'), +(64029, 'spell_ulduar_teleporter'), +(64025, 'spell_ulduar_teleporter'), +(65042, 'spell_ulduar_teleporter'); diff --git a/sql/updates/world/2014_06_14_03_world_smart_scripts.sql b/sql/updates/world/2014_06_14_03_world_smart_scripts.sql new file mode 100644 index 00000000000..ffd0ed03963 --- /dev/null +++ b/sql/updates/world/2014_06_14_03_world_smart_scripts.sql @@ -0,0 +1 @@ +UPDATE `smart_scripts` SET `event_type`=61 WHERE `entryorguid`=6221 AND `id` IN (9,10); diff --git a/sql/updates/world/2014_06_14_04_world_trinity_string.sql b/sql/updates/world/2014_06_14_04_world_trinity_string.sql new file mode 100644 index 00000000000..b110a7de6d2 --- /dev/null +++ b/sql/updates/world/2014_06_14_04_world_trinity_string.sql @@ -0,0 +1,3 @@ +DELETE FROM `trinity_string` WHERE `entry`=11009; +INSERT INTO `trinity_string` (`entry`, `content_default`) VALUES +(11009, 'Flags Extra: %u'); diff --git a/sql/updates/world/2014_06_15_00_world_spell_script_names.sql b/sql/updates/world/2014_06_15_00_world_spell_script_names.sql new file mode 100644 index 00000000000..84123740083 --- /dev/null +++ b/sql/updates/world/2014_06_15_00_world_spell_script_names.sql @@ -0,0 +1,3 @@ +DELETE FROM `spell_script_names` WHERE `spell_id`=42005; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(42005, 'spell_gurtogg_bloodboil_bloodboil'); diff --git a/sql/updates/world/2014_06_15_01_world_creature_template.sql b/sql/updates/world/2014_06_15_01_world_creature_template.sql new file mode 100644 index 00000000000..48358811c94 --- /dev/null +++ b/sql/updates/world/2014_06_15_01_world_creature_template.sql @@ -0,0 +1,7 @@ +-- inherit vehicleid and accessory from normal mode npc +UPDATE `creature_template` SET `VehicleId`=0 WHERE `entry` IN ( +30935, -- Drakkari Rhino (1) +31749, -- Hover Disk (1) +31748, -- Hover Disk (1) +37626 -- Iceborn Proto-Drake (1) +); diff --git a/sql/updates/world/2014_06_15_02_world_spell_group.sql b/sql/updates/world/2014_06_15_02_world_spell_group.sql new file mode 100644 index 00000000000..4a4be6f23cd --- /dev/null +++ b/sql/updates/world/2014_06_15_02_world_spell_group.sql @@ -0,0 +1,700 @@ + +TRUNCATE `spell_group`; +TRUNCATE `spell_group_stack_rules`; + +INSERT INTO `spell_group` (`id`, `spell_id`) VALUES +-- Battle Elixirs +(1, 2367), +(1, 2374), +(1, 3160), +(1, 3164), +(1, 7844), +(1, 8212), +(1, 10667), +(1, 10669), +(1, 11328), +(1, 11334), +(1, 11390), +(1, 11405), +(1, 11406), +(1, 11474), +(1, 16322), +(1, 16323), +(1, 16329), +(1, 17038), +(1, 17537), +(1, 17538), +(1, 17539), +(1, 17624), +(1, 17626), +(1, 17627), +(1, 17628), +(1, 17629), +(1, 21920), +(1, 26276), +(1, 28486), +(1, 28488), +(1, 28490), +(1, 28491), +(1, 28493), +(1, 28497), +(1, 28501), +(1, 28503), +(1, 28518), +(1, 28519), +(1, 28520), +(1, 28521), +(1, 28540), +(1, 33720), +(1, 33721), +(1, 33726), +(1, 38954), +(1, 40567), +(1, 40568), +(1, 40572), +(1, 40573), +(1, 40575), +(1, 40576), +(1, 41608), +(1, 41609), +(1, 41610), +(1, 41611), +(1, 42735), +(1, 45373), +(1, 46837), +(1, 46839), +(1, 53746), +(1, 53748), +(1, 53749), +(1, 53752), +(1, 53755), +(1, 53758), +(1, 53760), +(1, 54212), +(1, 54452), +(1, 54494), +(1, 60340), +(1, 60341), +(1, 60344), +(1, 60345), +(1, 60346), +(1, 62380), +(1, 67016), +(1, 67017), +(1, 67018), + +-- Guardian Elixirs +(2, 673), +(2, 2378), +(2, 2380), +(2, 3166), +(2, 3219), +(2, 3220), +(2, 3222), +(2, 3223), +(2, 3593), +(2, 10668), +(2, 10692), +(2, 10693), +(2, 11319), +(2, 11348), +(2, 11349), +(2, 11364), +(2, 11371), +(2, 11396), +(2, 15231), +(2, 15233), +(2, 16321), +(2, 16325), +(2, 16326), +(2, 16327), +(2, 17535), +(2, 17624), +(2, 17626), +(2, 17627), +(2, 17628), +(2, 17629), +(2, 24361), +(2, 24363), +(2, 24382), +(2, 24383), +(2, 24417), +(2, 27652), +(2, 27653), +(2, 28502), +(2, 28509), +(2, 28514), +(2, 28518), +(2, 28519), +(2, 28520), +(2, 28521), +(2, 28540), +(2, 29348), +(2, 39625), +(2, 39626), +(2, 39627), +(2, 39628), +(2, 40567), +(2, 40568), +(2, 40572), +(2, 40573), +(2, 40575), +(2, 40576), +(2, 41608), +(2, 41609), +(2, 41610), +(2, 41611), +(2, 42735), +(2, 46837), +(2, 46839), +(2, 53747), +(2, 53751), +(2, 53752), +(2, 53755), +(2, 53758), +(2, 53760), +(2, 53763), +(2, 53764), +(2, 54212), +(2, 60343), +(2, 60347), +(2, 62380), +(2, 67016), +(2, 67017), +(2, 67018), + +-- 'only works in the Blade's Edge Mountains Plateaus and Gruul's Lair' +(3, 40567), +(3, 40568), +(3, 40572), +(3, 40573), +(3, 40575), +(3, 40576), + +-- 'Only active in Tempest Keep, Serpentshrine Cavern, Caverns of Time: Mount Hyjal, Black Temple and the Sunwell Plateau' +(4, 41608), +(4, 41609), +(4, 41610), +(4, 41611), +(4, 46837), +(4, 46839), + +-- Well Fed +(1001, 18125), +(1001, 18141), +(1001, 19705), +(1001, 19706), +(1001, 19708), +(1001, 19709), +(1001, 19710), +(1001, 19711), +(1001, 23697), +(1001, 24799), +(1001, 24870), +(1001, 25694), +(1001, 25941), +(1001, 33254), +(1001, 33256), +(1001, 33257), +(1001, 33259), +(1001, 33261), +(1001, 33263), +(1001, 33265), +(1001, 33268), +(1001, 33272), +(1001, 35272), +(1001, 40323), +(1001, 42293), +(1001, 43722), +(1001, 43764), +(1001, 43771), +(1001, 44097), +(1001, 44098), +(1001, 44099), +(1001, 44100), +(1001, 44101), +(1001, 44102), +(1001, 44104), +(1001, 44105), +(1001, 44106), +(1001, 45245), +(1001, 45619), +(1001, 46682), +(1001, 46687), +(1001, 46899), +(1001, 53284), +(1001, 57079), +(1001, 57097), +(1001, 57100), +(1001, 57102), +(1001, 57107), +(1001, 57111), +(1001, 57139), +(1001, 57286), +(1001, 57288), +(1001, 57291), +(1001, 57294), +(1001, 57325), +(1001, 57327), +(1001, 57329), +(1001, 57332), +(1001, 57334), +(1001, 57356), +(1001, 57358), +(1001, 57360), +(1001, 57363), +(1001, 57365), +(1001, 57367), +(1001, 57371), +(1001, 57373), +(1001, 57399), +(1001, 58468), +(1001, 58479), +(1001, 59230), +(1001, 62349), +(1001, 64057), +(1001, 65247), +(1001, 65365), +(1001, 65410), +(1001, 65412), +(1001, 65414), +(1001, 65415), +(1001, 65416), +(1001, 66623), +(1001, 66624), +(1001, 69559), + +-- Blessing of Might +(1002, 19740), +(1002, 25782), +(1002, 56520), + +-- Battle Shout +(1003, 6673), + +-- BoM & Battle Shout +(1004, -1003), +(1004, -1002), + +-- Blessing of Wisdom +(1005, 19742), +(1005, 25894), +(1005, 56521), + +-- Blessing of Kings +(1006, 20217), +(1006, 25898), +(1006, 43223), +(1006, 56525), +(1006, 58054), +(1006, 72586), + +-- Blessing of Sanctuary +(1007, 20911), +(1007, 25899), + +-- Blessing of Protection (is this deprecated?) +(1008, 23415), +(1008, 41450), + +-- Blessing of Light (deprecated) +(1009, 32770), + +-- Paladin Blessings +(1010, -1009), +(1010, -1008), +(1010, -1007), +(1010, -1006), +(1010, -1005), +(1010, -1002), + +-- Warrior Shouts +(1011, -1003), +(1011, -1091), -- Commanding Shout + +(1012, 55749), -- Acid Spit (Rank 1) +(1013, 8647), -- Expose Armor +(1014, 7386), -- Sunder Armor + +-- Major Armor Reduction +(1015, -1014), +(1015, -1013), +(1015, -1012), +(1015, -1063), -- Curse of Weakness + +-- Faerie Fire +(1016, 770), +(1016, 16857), + +(1017, 56626), -- Sting (Rank 1) + +-- Minor Armor Reduction +(1019, -1017), +(1019, -1016), + +(1020, 55610), -- Improved Icy Talons +(1021, 8515), -- Windfury Totem (Rank 1) + +-- Melee Haste +(1022, -1021), +(1022, -1020), + +(1023, 24932), -- Leader of the Pack +(1024, 29801), -- Rampage (Passive) + +-- Melee Critical Increase +(1025, -1024), +(1025, -1023), + +(1026, 53137), -- Abomination's Might (Rank 1) +(1027, 19506), -- Trueshot Aura +(1028, 30802), -- Unleashed Rage (Rank 1) + +-- 10% Attack Power +(1029, -1028), +(1029, -1027), +(1029, -1026), + +(1030, 33878), -- Mangle (Bear) (Rank 1) +(1031, 33876), -- Mangle (Cat) (Rank 1) +(1032, 46856), -- Trauma (Rank 1) + +-- Bleed Damage Increase +(1033, -1032), +(1033, -1031), +(1033, -1030), + +(1034, 24907), -- Moonkin Aura +(1035, 51466), -- Elemental Oath (Rank 1) + +-- Spell Critical Increase +(1036, -1035), +(1036, -1034), + +-- Spell Critical Increase Debuff +(1037, 12579), +(1037, 17794), +(1037, 17797), +(1037, 17798), +(1037, 17799), +(1037, 17800), +(1037, 22959), + +-- BoK/BoS stat increase +(1038, -1006), -- Blessing of Kings +(1038, 67480), -- Blessing of Sanctuary + +(1045, 52109), -- Flametongue Totem (Rank 1) + +-- Totem of Wrath +(1046, 57658), +(1046, 57660), +(1046, 57662), +(1046, 57663), + +(1047, 48090), -- Demonic Pact + +-- Spell Damage Increase +(1048, -1047), +(1048, -1046), +(1048, -1045), + +(1050, 33191), -- Misery (Rank 1) + +-- Hit Chance Increase +(1051, -1016), -- Faerie Fire +(1051, -1050), + +(1052, 7294), -- Retribution Aura +(1053, 63531), -- Sanctified Retribution + +-- Spell Haste +(1054, -1052), +(1054, -1053), +(1054, 50170), -- Improved Moonkin Form (Rank 1) + +-- Ferocious Inspiration +(1055, 75446), +(1055, 75447), +(1055, 75593), + +-- Raid Damage % Bonus +(1056, -1052), +(1056, -1053), +(1056, -1055), +(1056, 31579), -- Arcane Empowerment (Rank 1) + +(1057, 13218), -- Wound Poison + +-- Target Critical Increase +(1058, -1057), +(1058, 2818), +(1058, 3409), +(1058, 5760), +(1058, 21183), +(1058, 30708), + +-- Melee/Ranged Slow +(1059, 89), -- Cripple (Rank 1) +(1059, 6136), -- Chilled (Rank 1) +(1059, 6343), -- Thunder Clap (Rank 1) +(1059, 6360), -- Soothing Kiss (Rank 1) +(1059, 7321), -- Chilled (Rank 1) +(1059, 8042), -- Earth Shock (Rank 1) +(1059, 16914), -- Hurricane (Rank 1) +(1059, 20005), -- Chilled +(1059, 27648), -- Thunderfury +(1059, 51693), -- Waylay +(1059, 55095), -- Frost Fever +(1059, 58179), -- Infected Wounds +(1059, 58180), -- Infected Wounds +(1059, 58181), -- Infected Wounds +(1059, 68055), -- Judgements of the Just (Rank 1) + +-- Target Hit Chance Decrease +(1060, 5570), -- Insect Swarm (Rank 1) +(1060, 3043), -- Scorpid Sting + +-- Healing Debuffs +(1061, -1057), -- Wound Poison (Rank 1) +(1061, 19434), -- Aimed Shot (Rank 1) +(1061, 12294), -- Mortal Strike (Rank 1) +(1061, 46910), -- Furious Attacks (Rank 1) + +-- Attack Power Debuff +(1062, -1063), -- Curse of Weakness +(1062, 99), -- Demoralizing Roar (Rank 1) +(1062, 1160), -- Demoralizing Shout (Rank 1) +(1062, 67), -- Vindication + +(1063, 702), -- Curse of Weakness +(1064, 8076), -- Strength of Earth (Rank 1) +(1065, 57330), -- Horn of Winter (Rank 1) +(1066, 8118), -- Strength (Rank 1) +(1067, 8115), -- Agility (Rank 1) +(1068, 8096), -- Intellect (Rank 1) +(1069, 8099), -- Stamina (Level 1) +(1070, 8112), -- Spirit (Rank 1) +(1071, 8091), -- Armor (Rank 1) +(1072, 1459), -- Arcane Intellect (Rank 1) +(1073, 54424), -- Fel Intelligence (Rank 1) +(1074, 1243), -- Power Word: Fortitude (Rank 1) +(1075, 21562), -- Prayer of Fortitude (Rank 1) +(1076, 14752), -- Divine Spirit (Rank 1) +(1077, 27681), -- Prayer of Spirit (Rank 1) +(1078, 1126), -- Mark of the Wild (Rank 1) +(1079, 21849), -- Gift of the Wild (Rank 1) +(1080, 23028), -- Arcane Brilliance (Rank 1) +(1081, 61024), -- Dalaran Intellect (Rank 7) +(1082, 61316), -- Dalaran Brilliance (Rank 3) + +-- Intellect Buffs +(1083, -1068), -- Intellect (Rank 1) +(1083, -1072), -- Arcane Intellect (Rank 1) +(1083, -1073), -- Fel Intelligence (Rank 1) +(1083, -1081), -- Dalaran Intellect (Rank 7) +(1083, -1082), -- Dalaran Brilliance (Rank 3) + +-- Stamina Buffs +(1084, -1074), -- Power Word: Fortitude (Rank 1) +(1084, -1069), -- Stamina (Level 1) +(1084, -1075), -- Prayer of Fortitude (Rank 1) +(1084, 72590), -- Fortitude + +-- Spirit Buffs +(1085, -1070), -- Spirit (Rank 1) +(1085, -1076), -- Divine Spirit (Rank 1) +(1085, -1077), -- Prayer of Spirit (Rank 1) +(1085, -1073), -- Fel Intelligence (Rank 1) + +-- Armor Buffs +(1086, -1071), -- Armor (Rank 1) +(1086, 8072), -- Stoneskin + +-- All Stat Type Buffs +(1087, -1078), -- Mark of the Wild (Rank 1) +(1087, -1071), -- Armor (Rank 1) +(1087, -1068), -- Intellect (Rank 1) +(1087, -1069), -- Stamina (Level 1) +(1087, -1070), -- Spirit (Rank 1) +(1087, -1067), -- Agility (Rank 1) +(1087, -1066), -- Strength (Rank 1) +(1087, -1079), -- Gift of the Wild (Rank 1) +(1087, 72588), -- Gift of the Wild + +-- Strength and Agility Buffs +(1088, -1064), -- Strength of Earth (Rank 1) +(1088, -1065), -- Horn of Winter (Rank 1) + +-- Strength Buffs +(1089, -1066), -- Strength (Rank 1) +(1089, -1085), -- Strength of Earth + HoW + +-- Agility Buffs +(1090, -1067), -- Agility (Rank 1) +(1090, -1085), -- Strength of Earth + HoW + +(1091, 469), -- Commanding Shout (Rank 1) +(1092, 6307), -- Blood Pact (Rank 1) + +-- Flat Health Buffs +(1093, -1091), +(1093, -1092), + +-- Healing Received Buffs +(1094, 34123), -- Tree of Life (Passive) +(1094, 63514), -- Improved Devotion Aura (Rank 10) + +-- Physical Damage Taken Buff +(1095, 14893), -- Inspiration (Rank 1) +(1095, 16177), -- Ancestral Fortitude (Rank 1) + +-- Casting Time Debuffs +(1096, 1714), -- Curse of Tongues (Rank 1) +(1096, 31589), -- Slow +(1096, 5760), -- Mind-numbing Poison + +-- Mage Snares +(1097, 122), -- Frost Nova (Rank 1) +(1097, 33395), -- Freeze +(1097, 55080), -- Shattered Barrier + +-- Shadow Protection +(1098, 976), -- Shadow Protection (Rank 1) +(1098, 27683), -- Prayer of Shadow Protection (Rank 1) + +-- Immolate & Unstable Assfriction +(1099, 348), -- Immolate (Rank 1) +(1099, 30108), -- Unstable Assfriction (Rank 1) + +-- Dampen/Amplify Magic +(1100, 604), -- Dampen Magic (Rank 1) +(1100, 1008), -- Amplify Magic (Rank 1) + +-- Spell Damage Taken Debuffs +(1101, 1490), -- Curse of the Elements (Rank 1) +(1101, 51726), -- Ebon Plague +(1101, 51734), -- Ebon Plague +(1101, 51735), -- Ebon Plague +(1101, 60431), -- Earth and Moon +(1101, 60432), -- Earth and Moon +(1101, 60433), -- Earth and Moon + +-- Introspection +(1102, 40055), -- Introspection +(1102, 40165), -- Introspection +(1102, 40166), -- Introspection +(1102, 40167), -- Introspection + +-- Apexis Emanations +(1103, 40623), -- Apexis Emanations +(1103, 40625), -- Apexis Emanations +(1103, 40626), -- Apexis Emanations + +-- Enrage Buffs +(1104, 12880), -- Enrage (Rank 1) +(1104, 57514), -- Enrage (Rank 1) +(1104, 57518), -- Enrage (Rank 1) + +-- BoW & Mana Spring +(1105, 5677), +(1105, -1005), + +-- Heroic Presence Racials +(1106, 6562), -- Heroic Presence (Racial Passive) +(1106, 28878), -- Heroic Presence (Racial Passive) + +-- Damage Done Buffs +(1107, 49016), -- Hysteria +(1107, 57933), -- Tricks of the Trade +(1107, 12292), -- Death Wish +(1107, 12042), -- Arcane Power +(1107, 34471), -- The Beast Within +(1107, 31884), -- Avenging Wrath + +-- Physical Damage Taken Debuffs +(1108, 30069), -- Blood Frenzy (Rank 1) +(1108, 58684), -- Savage Combat (Rank 1) + +-- Scholazar Buffs +(1109, 51442), -- Blessing of the Sparkling Hare +(1109, 52119), -- Jaloot's Intensity + +-- Corporeality +(1110, 74826), -- Corporeality +(1110, 74827), -- Corporeality +(1110, 74828), -- Corporeality +(1110, 74829), -- Corporeality +(1110, 74830), -- Corporeality +(1110, 74831), -- Corporeality +(1110, 74832), -- Corporeality +(1110, 74833), -- Corporeality +(1110, 74834), -- Corporeality +(1110, 74835), -- Corporeality +(1110, 74836); -- Corporeality + +SET @SPELL_GROUP_STACK_RULE_EXCLUSIVE := 1; -- A unit can only have one of these +SET @SPELL_GROUP_STACK_RULE_EXCLUSIVE_FROM_SAME_CASTER := 2; -- A unit can have one of these, per caster +SET @SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT := 3; -- A unit can have several of these, but only the strongest count +SET @SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST := 4; -- A unit can only have one of these, the strongest + +INSERT INTO `spell_group_stack_rules` (`group_id`, `stack_rule`) VALUES +(1, @SPELL_GROUP_STACK_RULE_EXCLUSIVE), -- Battle Elixirs +(2, @SPELL_GROUP_STACK_RULE_EXCLUSIVE), -- Guardian Elixirs +(1001, @SPELL_GROUP_STACK_RULE_EXCLUSIVE), -- Well Fed +(1002, @SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST), -- Blessing of Might +(1003, @SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST), -- Battle Shout +(1004, @SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST), -- BoM & Batte Shout +(1005, @SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST), -- Blessing of Wisdom +(1006, @SPELL_GROUP_STACK_RULE_EXCLUSIVE), -- Blessing of Kings +(1007, @SPELL_GROUP_STACK_RULE_EXCLUSIVE), -- Blessing of Sanctuary +(1008, @SPELL_GROUP_STACK_RULE_EXCLUSIVE), -- Blessing of Protection +(1009, @SPELL_GROUP_STACK_RULE_EXCLUSIVE), -- Blessing of Light +(1010, @SPELL_GROUP_STACK_RULE_EXCLUSIVE_FROM_SAME_CASTER), -- Paladin Blessings +(1011, @SPELL_GROUP_STACK_RULE_EXCLUSIVE_FROM_SAME_CASTER), -- Warrior Shouts +(1015, @SPELL_GROUP_STACK_RULE_EXCLUSIVE), -- Major Armor Reduction +(1016, @SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST), -- Faerie Fire +(1019, @SPELL_GROUP_STACK_RULE_EXCLUSIVE), -- Minor Armor Reduction +(1022, @SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST), -- Melee Haste +(1025, @SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST), -- Melee Critical Increase +(1029, @SPELL_GROUP_STACK_RULE_EXCLUSIVE), -- 10% Attack Power +(1033, @SPELL_GROUP_STACK_RULE_EXCLUSIVE), -- Bleed Damage Increase +(1036, @SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST), -- Spell Critical Increase +(1037, @SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT), -- Spell Critical Increase Debuff +(1038, @SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT), -- BoK/BoS stat increase +(1046, @SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST), -- Totem of Wrath +(1048, @SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST), -- Spell Damage Increase +(1051, @SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST), -- Hit Chance Increase +(1054, @SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST), -- Spell Haste +(1055, @SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST), -- Ferocious Inspiration +(1056, @SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST), -- Raid Damage % Bonus +(1058, @SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST), -- Target Critical Increase +(1059, @SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT), -- Melee/Ranged Slow +(1060, @SPELL_GROUP_STACK_RULE_EXCLUSIVE), -- Target Hit Chance Decrease +(1061, @SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST), -- Healing Debuffs +(1062, @SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST), -- Attack Power Debuff +(1083, @SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST), -- Intellect Buffs +(1084, @SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST), -- Stamina Buffs +(1085, @SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST), -- Spirit Buffs +(1086, @SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST), -- Armor Buffs +(1087, @SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST), -- All Stat Type Buffs +(1088, @SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST), -- Strength and Agility Buffs +(1089, @SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST), -- Strength Buffs +(1090, @SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST), -- Agility Buffs +(1093, @SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST), -- Flat Health Buffs +(1094, @SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST), -- Healing Received Buffs +(1095, @SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST), -- Physical Damage Taken Buffs +(1096, @SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST), -- Casting Time Debuffs +(1097, @SPELL_GROUP_STACK_RULE_EXCLUSIVE), -- Mage Snares +(1098, @SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST), -- Shadow Protection +(1099, @SPELL_GROUP_STACK_RULE_EXCLUSIVE_FROM_SAME_CASTER), -- Immolate & Unstable Assfriction +(1100, @SPELL_GROUP_STACK_RULE_EXCLUSIVE), -- Dampen/Amplify Magic +(1101, @SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT), -- Spell Damage Taken Debuff +(1104, @SPELL_GROUP_STACK_RULE_EXCLUSIVE), -- Enrage Buffs +(1105, @SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST), -- BoW & Mana Spring +(1106, @SPELL_GROUP_STACK_RULE_EXCLUSIVE), -- Heroic Presence Racials +(1107, @SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST), -- Damage Done Buffs +(1108, @SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST), -- Physical Damage Taken Debuffs +(1109, @SPELL_GROUP_STACK_RULE_EXCLUSIVE), -- Scholazar Buffs +(1110, @SPELL_GROUP_STACK_RULE_EXCLUSIVE); -- Corporeality + diff --git a/sql/updates/world/2014_06_16_00_world_spell_group.sql b/sql/updates/world/2014_06_16_00_world_spell_group.sql new file mode 100644 index 00000000000..363030eeaa1 --- /dev/null +++ b/sql/updates/world/2014_06_16_00_world_spell_group.sql @@ -0,0 +1,3 @@ + +-- Target Critical Increase Debuffs should stack, and only the higher effect apply +UPDATE spell_group_stack_rules SET stack_rule=3 WHERE group_id=1058; diff --git a/sql/updates/world/2014_06_17_00_world_spell_group.sql b/sql/updates/world/2014_06_17_00_world_spell_group.sql new file mode 100644 index 00000000000..7d109800a42 --- /dev/null +++ b/sql/updates/world/2014_06_17_00_world_spell_group.sql @@ -0,0 +1,3 @@ + +DELETE FROM spell_group WHERE id=1059 AND spell_id=58180; +DELETE FROM spell_group WHERE id=1059 AND spell_id=58181; diff --git a/src/server/authserver/Authentication/AuthCodes.cpp b/src/server/authserver/Authentication/AuthCodes.cpp index 55517884b8e..44921f6a1cd 100644 --- a/src/server/authserver/Authentication/AuthCodes.cpp +++ b/src/server/authserver/Authentication/AuthCodes.cpp @@ -79,4 +79,9 @@ namespace AuthHelper return NULL; } + + bool IsBuildSupportingBattlenet(int build) + { + return build >= 15595; + } } diff --git a/src/server/authserver/Authentication/AuthCodes.h b/src/server/authserver/Authentication/AuthCodes.h index 97b4779da0e..eb9f443f624 100644 --- a/src/server/authserver/Authentication/AuthCodes.h +++ b/src/server/authserver/Authentication/AuthCodes.h @@ -70,6 +70,96 @@ enum LoginResult LOGIN_LOCKED_ENFORCED = 0x10 }; +enum GameAccountFlags +{ + GAMEACCOUNT_FLAG_GM = 0x00000001, + GAMEACCOUNT_FLAG_NOKICK = 0x00000002, + GAMEACCOUNT_FLAG_COLLECTOR = 0x00000004, + GAMEACCOUNT_FLAG_WOW_TRIAL = 0x00000008, + GAMEACCOUNT_FLAG_CANCELLED = 0x00000010, + GAMEACCOUNT_FLAG_IGR = 0x00000020, + GAMEACCOUNT_FLAG_WHOLESALER = 0x00000040, + GAMEACCOUNT_FLAG_PRIVILEGED = 0x00000080, + GAMEACCOUNT_FLAG_EU_FORBID_ELV = 0x00000100, + GAMEACCOUNT_FLAG_EU_FORBID_BILLING = 0x00000200, + GAMEACCOUNT_FLAG_WOW_RESTRICTED = 0x00000400, + GAMEACCOUNT_FLAG_REFERRAL = 0x00000800, + GAMEACCOUNT_FLAG_BLIZZARD = 0x00001000, + GAMEACCOUNT_FLAG_RECURRING_BILLING = 0x00002000, + GAMEACCOUNT_FLAG_NOELECTUP = 0x00004000, + GAMEACCOUNT_FLAG_KR_CERTIFICATE = 0x00008000, + GAMEACCOUNT_FLAG_EXPANSION_COLLECTOR = 0x00010000, + GAMEACCOUNT_FLAG_DISABLE_VOICE = 0x00020000, + GAMEACCOUNT_FLAG_DISABLE_VOICE_SPEAK = 0x00040000, + GAMEACCOUNT_FLAG_REFERRAL_RESURRECT = 0x00080000, + GAMEACCOUNT_FLAG_EU_FORBID_CC = 0x00100000, + GAMEACCOUNT_FLAG_OPENBETA_DELL = 0x00200000, + GAMEACCOUNT_FLAG_PROPASS = 0x00400000, + GAMEACCOUNT_FLAG_PROPASS_LOCK = 0x00800000, + GAMEACCOUNT_FLAG_PENDING_UPGRADE = 0x01000000, + GAMEACCOUNT_FLAG_RETAIL_FROM_TRIAL = 0x02000000, + GAMEACCOUNT_FLAG_EXPANSION2_COLLECTOR = 0x04000000, + GAMEACCOUNT_FLAG_OVERMIND_LINKED = 0x08000000, + GAMEACCOUNT_FLAG_DEMOS = 0x10000000, + GAMEACCOUNT_FLAG_DEATH_KNIGHT_OK = 0x20000000, +}; + +namespace Battlenet +{ + enum AuthResult + { + AUTH_OK = 0, + AUTH_INTERNAL_ERROR = 100, + AUTH_CORRUPTED_MODULE = 102, + AUTH_BAD_SERVER_PROOF = 103, + AUTH_UNKNOWN_ACCOUNT = 104, + AUTH_CLOSED = 105, + AUTH_LOGIN_TIMEOUT = 106, + AUTH_NO_GAME_ACCOUNTS = 107, + AUTH_INVALID_TOKEN = 108, + AUTH_INVALID_PROGRAM = 109, + AUTH_INVALID_OS = 110, + AUTH_UNSUPPORTED_LANGUAGE = 111, + AUTH_REGION_BAD_VERSION = 112, + AUTH_TEMP_OUTAGE = 113, + AUTH_CANT_DOWNLOAD_MODULE = 114, + AUTH_DUPLICATE_LOGON = 115, + AUTH_BAD_CREDENTIALS_2 = 116, + AUTH_VERSION_CHECK_SUCCEEDED = 117, + AUTH_BAD_VERSION_HASH = 118, + AUTH_CANT_RETRIEVE_PORTAL_LIST = 119, + AUTH_DARK_PORTAL_DOES_NOT_EXIST = 120, + AUTH_DARK_PORTAL_FILE_CORRUPTED = 121, + AUTH_BATTLENET_MAINTENANCE = 122, + AUTH_LOGON_TOO_FAST = 123, + AUTH_USE_GRUNT_LOGON = 124, + AUTH_NO_GAME_ACCOUNTS_IN_REGION = 140, + AUTH_ACCOUNT_LOCKED = 141, + + LOGIN_SERVER_BUSY = 200, + LOGIN_NO_GAME_ACCOUNT = 201, + LOGIN_BANNED = 202, + LOGIN_SUSPENDED = 203, + LOGIN_GAME_ACCOUNT_LOCKED = 204, + LOGIN_ALREADY_ONLINE = 205, + LOGIN_NOTIME = 206, + LOGIN_EXPIRED = 207, + LOGIN_EXPIRED_2 = 208, + LOGIN_PARENTALCONTROL = 209, + LOGIN_TRIAL_EXPIRED = 210, + LOGIN_ANTI_INDULGENCE = 211, + LOGIN_INCORRECT_REGION = 212, + LOGIN_LOCKED_ENFORCED = 213, + LOGIN_CHARGEBACK = 214, + LOGIN_IGR_WITHOUT_BNET = 215, + LOGIN_UNLOCKABLE_LOCK = 216, + LOGIN_IGR_REQUIRED = 217, + LOGIN_PAYMENT_CHANGED = 218, + LOGIN_INVALID_PAYMENT = 219, + LOGIN_INVALID_ACCOUNT_STATE = 220 + }; +} + enum ExpansionFlags { POST_BC_EXP_FLAG = 0x2, @@ -92,6 +182,7 @@ namespace AuthHelper bool IsAcceptedClientBuild(int build); bool IsPostBCAcceptedClientBuild(int build); bool IsPreBCAcceptedClientBuild(int build); + bool IsBuildSupportingBattlenet(int build); } #endif diff --git a/src/server/authserver/Main.cpp b/src/server/authserver/Main.cpp index be6623c7fa3..be2e6a11d4f 100644 --- a/src/server/authserver/Main.cpp +++ b/src/server/authserver/Main.cpp @@ -151,7 +151,8 @@ extern int main(int argc, char** argv) } // Launch the listening network socket - RealmAcceptor acceptor; + RealmAcceptor<AuthSocket> acceptor; + RealmAcceptor<Battlenet::Socket> bnetacceptor; int32 rmport = sConfigMgr->GetIntDefault("RealmServerPort", 3724); if (rmport < 0 || rmport > 0xFFFF) @@ -170,6 +171,13 @@ extern int main(int argc, char** argv) return 1; } + bind_addr.set_port_number(1119); + if (bnetacceptor.open(bind_addr, ACE_Reactor::instance(), ACE_NONBLOCK) == -1) + { + TC_LOG_ERROR("server.authserver", "Auth server can not bind to %s:%d", bind_ip.c_str(), 1119); + return 1; + } + // Initialize the signal handlers AuthServerSignalHandler SignalINT, SignalTERM; @@ -246,6 +254,8 @@ extern int main(int argc, char** argv) #endif #endif + sBattlenetMgr->Load(); + // maximum counter for next ping uint32 numLoops = (sConfigMgr->GetIntDefault("MaxPingTime", 30) * (MINUTE * 1000000 / 100000)); uint32 loopCounter = 0; diff --git a/src/server/authserver/Realms/RealmList.cpp b/src/server/authserver/Realms/RealmList.cpp index 4aeecfc0aaa..48b7a178c2d 100644 --- a/src/server/authserver/Realms/RealmList.cpp +++ b/src/server/authserver/Realms/RealmList.cpp @@ -18,9 +18,29 @@ #include "Common.h" #include "RealmList.h" +#include "BattlenetManager.h" #include "Database/DatabaseEnv.h" +#include "Util.h" -RealmList::RealmList() : m_UpdateInterval(0), m_NextUpdateTime(time(NULL)) { } +ACE_INET_Addr const& Realm::GetAddressForClient(ACE_INET_Addr const& clientAddr) const +{ + // Attempt to send best address for client + if (clientAddr.is_loopback()) + // Assume that user connecting from the machine that authserver is located on + // has all realms available in his local network + return LocalAddress; + + // Check if connecting client is in the same network + if (IsIPAddrInNetwork(LocalAddress, clientAddr, LocalSubnetMask)) + return LocalAddress; + + // Return external IP + return ExternalAddress; +} + +RealmList::RealmList() : m_UpdateInterval(0), m_NextUpdateTime(time(NULL)) +{ +} // Load the realm list from the database void RealmList::Initialize(uint32 updateInterval) @@ -31,7 +51,7 @@ void RealmList::Initialize(uint32 updateInterval) UpdateRealms(true); } -void RealmList::UpdateRealm(uint32 id, const std::string& name, ACE_INET_Addr const& address, ACE_INET_Addr const& localAddr, ACE_INET_Addr const& localSubmask, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float popu, uint32 build) +void RealmList::UpdateRealm(uint32 id, const std::string& name, ACE_INET_Addr const& address, ACE_INET_Addr const& localAddr, ACE_INET_Addr const& localSubmask, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float popu, uint32 build, uint8 region, uint8 battlegroup) { // Create new if not exist or update existed Realm& realm = m_realms[name]; @@ -49,6 +69,8 @@ void RealmList::UpdateRealm(uint32 id, const std::string& name, ACE_INET_Addr co realm.LocalAddress = localAddr; realm.LocalSubnetMask = localSubmask; realm.gamebuild = build; + realm.Region = region; + realm.Battlegroup = battlegroup; } void RealmList::UpdateIfNeed() @@ -91,12 +113,14 @@ void RealmList::UpdateRealms(bool init) uint8 allowedSecurityLevel = fields[9].GetUInt8(); float pop = fields[10].GetFloat(); uint32 build = fields[11].GetUInt32(); + uint8 region = fields[12].GetUInt8(); + uint8 battlegroup = fields[13].GetUInt8(); ACE_INET_Addr externalAddr(port, externalAddress.c_str(), AF_INET); ACE_INET_Addr localAddr(port, localAddress.c_str(), AF_INET); ACE_INET_Addr submask(0, localSubmask.c_str(), AF_INET); - UpdateRealm(realmId, name, externalAddr, localAddr, submask, icon, flag, timezone, (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop, build); + UpdateRealm(realmId, name, externalAddr, localAddr, submask, icon, flag, timezone, (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop, build, region, battlegroup); if (init) TC_LOG_INFO("server.authserver", "Added realm \"%s\" at %s:%u.", name.c_str(), m_realms[name].ExternalAddress.get_host_addr(), port); @@ -104,3 +128,16 @@ void RealmList::UpdateRealms(bool init) while (result->NextRow()); } } + +Realm const* RealmList::GetRealm(Battlenet::RealmId const& id) const +{ + auto itr = std::find_if(m_realms.begin(), m_realms.end(), [id](RealmMap::value_type const& pair) + { + return pair.second.Region == id.Region && pair.second.Battlegroup == id.Battlegroup && pair.second.m_ID == id.Index; + }); + + if (itr != m_realms.end()) + return &itr->second; + + return NULL; +} diff --git a/src/server/authserver/Realms/RealmList.h b/src/server/authserver/Realms/RealmList.h index 1d76c39e4f0..c4a6b4eaa0b 100644 --- a/src/server/authserver/Realms/RealmList.h +++ b/src/server/authserver/Realms/RealmList.h @@ -51,8 +51,17 @@ struct Realm AccountTypes allowedSecurityLevel; float populationLevel; uint32 gamebuild; + uint8 Region; + uint8 Battlegroup; + + ACE_INET_Addr const& GetAddressForClient(ACE_INET_Addr const& clientAddr) const; }; +namespace Battlenet +{ + struct RealmId; +} + /// Storage object for the list of realms on the server class RealmList { @@ -71,10 +80,11 @@ public: RealmMap::const_iterator begin() const { return m_realms.begin(); } RealmMap::const_iterator end() const { return m_realms.end(); } uint32 size() const { return m_realms.size(); } + Realm const* GetRealm(Battlenet::RealmId const& id) const; private: void UpdateRealms(bool init=false); - void UpdateRealm(uint32 id, const std::string& name, ACE_INET_Addr const& address, ACE_INET_Addr const& localAddr, ACE_INET_Addr const& localSubmask, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float popu, uint32 build); + void UpdateRealm(uint32 id, const std::string& name, ACE_INET_Addr const& address, ACE_INET_Addr const& localAddr, ACE_INET_Addr const& localSubmask, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float popu, uint32 build, uint8 region, uint8 battlegroup); RealmMap m_realms; uint32 m_UpdateInterval; diff --git a/src/server/authserver/Server/AuthSocket.cpp b/src/server/authserver/Server/AuthSocket.cpp index c7bb600024a..7ca49b03b56 100644 --- a/src/server/authserver/Server/AuthSocket.cpp +++ b/src/server/authserver/Server/AuthSocket.cpp @@ -293,19 +293,11 @@ void AuthSocket::_SetVSFields(const std::string& rI) x.SetBinary(sha.GetDigest(), sha.GetLength()); v = g.ModExp(x, N); - // No SQL injection (username escaped) - char *v_hex, *s_hex; - v_hex = v.AsHexStr(); - s_hex = s.AsHexStr(); - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_VS); - stmt->setString(0, v_hex); - stmt->setString(1, s_hex); + stmt->setString(0, v.AsHexStr()); + stmt->setString(1, s.AsHexStr()); stmt->setString(2, _login); LoginDatabase.Execute(stmt); - - OPENSSL_free(v_hex); - OPENSSL_free(s_hex); } // Logon Challenge command handler @@ -488,7 +480,9 @@ bool AuthSocket::_HandleLogonChallenge() unk3.SetRand(16 * 8); // Fill the response packet with the result - if (AuthHelper::IsAcceptedClientBuild(_build)) + if (fields[9].GetUInt32() && AuthHelper::IsBuildSupportingBattlenet(_build)) + pkt << uint8(WOW_FAIL_USE_BATTLENET); + else if (AuthHelper::IsAcceptedClientBuild(_build)) pkt << uint8(WOW_SUCCESS); else pkt << uint8(WOW_FAIL_VERSION_INVALID); @@ -650,19 +644,14 @@ bool AuthSocket::_HandleLogonProof() TC_LOG_DEBUG("server.authserver", "'%s:%d' User '%s' successfully authenticated", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str()); // Update the sessionkey, last_ip, last login time and reset number of failed logins in the account table for this account - // No SQL injection (escaped user name) and IP address as received by socket - const char *K_hex = K.AsHexStr(); - PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGONPROOF); - stmt->setString(0, K_hex); + stmt->setString(0, K.AsHexStr()); stmt->setString(1, socket().getRemoteAddress().c_str()); stmt->setUInt32(2, GetLocaleByName(_localizationName)); stmt->setString(3, _os); stmt->setString(4, _login); LoginDatabase.DirectExecute(stmt); - OPENSSL_free((void*)K_hex); - // Finish SRP6 and send the final result to the client sha.Initialize(); sha.UpdateBigNumbers(&A, &M, &K, NULL); @@ -693,7 +682,7 @@ bool AuthSocket::_HandleLogonProof() memcpy(proof.M2, sha.GetDigest(), 20); proof.cmd = AUTH_LOGON_PROOF; proof.error = 0; - proof.unk1 = 0x00800000; // Accountflags. 0x01 = GM, 0x08 = Trial, 0x00800000 = Pro pass (arena tournament) + proof.unk1 = GAMEACCOUNT_FLAG_PROPASS_LOCK; proof.unk2 = 0x00; // SurveyId proof.unk3 = 0x00; socket().send((char *)&proof, sizeof(proof)); @@ -879,28 +868,6 @@ bool AuthSocket::_HandleReconnectProof() } } -ACE_INET_Addr const& AuthSocket::GetAddressForClient(Realm const& realm, ACE_INET_Addr const& clientAddr) -{ - // Attempt to send best address for client - if (clientAddr.is_loopback()) - { - // Try guessing if realm is also connected locally - if (realm.LocalAddress.is_loopback() || realm.ExternalAddress.is_loopback()) - return clientAddr; - - // Assume that user connecting from the machine that authserver is located on - // has all realms available in his local network - return realm.LocalAddress; - } - - // Check if connecting client is in the same network - if (IsIPAddrInNetwork(realm.LocalAddress, clientAddr, realm.LocalSubnetMask)) - return realm.LocalAddress; - - // Return external IP - return realm.ExternalAddress; -} - // Realm List command handler bool AuthSocket::_HandleRealmList() { @@ -981,12 +948,12 @@ bool AuthSocket::_HandleRealmList() pkt << lock; // if 1, then realm locked pkt << uint8(flag); // RealmFlags pkt << name; - pkt << GetAddressString(GetAddressForClient(realm, clientAddr)); + pkt << GetAddressString(realm.GetAddressForClient(clientAddr)); pkt << realm.populationLevel; pkt << AmountOfCharacters; pkt << realm.timezone; // realm category if (_expversion & POST_BC_EXP_FLAG) // 2.x and 3.x clients - pkt << uint8(0x2C); // unk, may be realm number/id? + pkt << uint8(realm.m_ID); else pkt << uint8(0x0); // 1.12.1 and 1.12.2 clients diff --git a/src/server/authserver/Server/AuthSocket.h b/src/server/authserver/Server/AuthSocket.h index 5e04d459ba1..e81944389ef 100644 --- a/src/server/authserver/Server/AuthSocket.h +++ b/src/server/authserver/Server/AuthSocket.h @@ -39,8 +39,6 @@ public: virtual void OnAccept(void); virtual void OnClose(void); - static ACE_INET_Addr const& GetAddressForClient(Realm const& realm, ACE_INET_Addr const& clientAddr); - bool _HandleLogonChallenge(); bool _HandleLogonProof(); bool _HandleReconnectChallenge(); diff --git a/src/server/authserver/Server/BattlenetBitStream.h b/src/server/authserver/Server/BattlenetBitStream.h new file mode 100644 index 00000000000..3d1d2d5f67d --- /dev/null +++ b/src/server/authserver/Server/BattlenetBitStream.h @@ -0,0 +1,246 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __BATTLENETBITSTREAM_H__ +#define __BATTLENETBITSTREAM_H__ + +#include "ByteConverter.h" +#include "Common.h" +#include <exception> +#include <vector> +#include <type_traits> +#include <ace/Auto_Ptr.h> +#include <ace/Stack_Trace.h> + +namespace Battlenet +{ + class BitStreamPositionException : public std::exception + { + static uint32 const MessageSize = ACE_Stack_Trace::SYMBUFSIZ + 128; + + public: + BitStreamPositionException(bool read, uint32 operationSize, uint32 position, uint32 streamSize) + { + memset(_message, 0, MessageSize); +#ifndef TRINITY_DEBUG + snprintf(_message, MessageSize, "Attempted to %s more bits (%u) %s stream than %s (%u)\nStack trace:\n", + (read ? "read" : "write"), + operationSize + position, + (read ? "from" : "to"), + (read ? "exist" : "allowed"), + streamSize); +#else + ACE_Stack_Trace st(1); + snprintf(_message, MessageSize, "Attempted to %s more bits (%u) %s stream than %s (%u)\nStack trace:\n%s", + (read ? "read" : "write"), + operationSize + position, + (read ? "from" : "to"), + (read ? "exist" : "allowed"), + streamSize, + st.c_str()); +#endif + } + + char const* what() const throw() + { + return _message; + } + + private: + char _message[MessageSize]; + }; + + class BitStream + { + public: + static uint32 const MaxSize = 0x1000; + + // length : The maximum number of bytes to read + BitStream(uint32 length) : _numBits(length * 8), _readPos(0), _writePos(0) + { + _buffer.resize(length, 0); + } + + BitStream() : _numBits(0), _readPos(0), _writePos(0) + { + _buffer.reserve(0x1000); + } + + void AlignToNextByte() + { + _readPos = (_readPos + 7) & ~7; + _writePos = (_writePos + 7) & ~7; + } + + std::string ReadString(uint32 bitCount, int32 baseLength = 0) + { + uint32 len = Read<uint32>(bitCount) + baseLength; + AlignToNextByte(); + std::string str(reinterpret_cast<char*>(&_buffer[_readPos >> 3]), len); + _readPos += len * 8; + return str; + } + + ACE_Auto_Array_Ptr<uint8> ReadBytes(uint32 count) + { + AlignToNextByte(); + if (_readPos + count * 8 > _numBits) + throw BitStreamPositionException(true, count * 8, _readPos, _numBits); + + ACE_Auto_Array_Ptr<uint8> buf(new uint8[count]); + memcpy(buf.get(), &_buffer[_readPos >> 3], count); + _readPos += count * 8; + return buf; + } + + float ReadFloat() + { + uint32 val = Read<uint32>(32); + return *reinterpret_cast<float*>(&val); + } + + std::string ReadFourCC() + { + uint32 fcc = Read<uint32>(32); + EndianConvertReverse(fcc); + size_t len = 4; + while (!(fcc & 0xFF)) + { + fcc >>= 8; + --len; + } + + return std::string(reinterpret_cast<char*>(&fcc), len); + } + + template<typename T> + T Read(uint32 bitCount) + { + static_assert(std::is_integral<T>::value || std::is_enum<T>::value, "T must be an integer type"); + + if (_readPos + bitCount >= _numBits) + throw BitStreamPositionException(true, bitCount, _readPos, _numBits); + + uint64 ret = 0; + while (bitCount != 0) + { + uint32 bitPos = (_readPos & 7); + uint32 bitsLeftInByte = 8 - bitPos; + if (bitsLeftInByte >= bitCount) + bitsLeftInByte = bitCount; + + bitCount -= bitsLeftInByte; + ret |= (uint64)(_buffer[_readPos >> 3] >> bitPos & (uint32)((uint8)(1 << bitsLeftInByte) - 1)) << bitCount; + _readPos += bitsLeftInByte; + } + + return static_cast<T>(ret); + } + + void WriteString(std::string const& str, uint32 bitCount, int32 baseLength = 0) + { + Write(str.length() + baseLength, bitCount); + WriteBytes(str.c_str(), str.length()); + } + + template<typename T> + void WriteBytes(T* data, uint32 count) + { + AlignToNextByte(); + if (!count || !data) + return; + + if ((_writePos >> 3) + count > MaxSize) + throw BitStreamPositionException(false, count * 8, _writePos, MaxSize * 8); + + _buffer.resize(_buffer.size() + count); + memcpy(&_buffer[_writePos >> 3], data, count); + _writePos += count * 8; + } + + void WriteFloat(float value) + { + uint32 intVal = *reinterpret_cast<uint32*>(&value); + Write(intVal, 32); + } + + void WriteFourCC(std::string const& fcc) + { + uint32 intVal = *(uint32*)fcc.c_str(); + size_t len = fcc.length(); + EndianConvertReverse(intVal); + // Add padding + while (len++ < 4) + intVal >>= 8; + + Write(intVal, 32); + } + + template<typename T> + void Write(T value, uint32 bitCount) + { + static_assert(std::is_integral<T>::value || std::is_enum<T>::value, "T must be an integer type"); + + if (_writePos + bitCount >= 8 * MaxSize) + throw BitStreamPositionException(false, bitCount, _writePos, MaxSize * 8); + + while (bitCount != 0) + { + uint32 bitPos = (_writePos & 7); + uint32 bitsLeftInByte = 8 - bitPos; + if (bitsLeftInByte >= bitCount) + bitsLeftInByte = bitCount; + + bitCount -= bitsLeftInByte; + + uint8 firstHalf = (uint8)(~(((uint8)(1 << bitsLeftInByte) - 1) << bitPos)); + uint8 secondHalf = (uint8)((((uint8)(1 << bitsLeftInByte) - 1) & (uint8)(value >> bitCount)) << bitPos); + + if (_buffer.size() > (_writePos >> 3)) + _buffer[_writePos >> 3] = (uint8)((_buffer[_writePos >> 3] & firstHalf) | secondHalf); + else + _buffer.push_back(secondHalf); + + _writePos += bitsLeftInByte; + } + } + + void SetReadPos(uint32 bits) + { + if (bits >= _numBits) + throw BitStreamPositionException(true, bits, 0, _numBits); + + _readPos = bits; + } + + bool IsRead() const { return _readPos >= _numBits; } + + uint8* GetBuffer() { return _buffer.data(); } + + size_t GetSize() const { return _buffer.size(); } + + void FinishReading() { _readPos = _numBits; } + + private: + std::vector<uint8> _buffer; + uint32 _numBits; + uint32 _readPos; + uint32 _writePos; + }; +} + +#endif // __BATTLENETBITSTREAM_H__ diff --git a/src/server/authserver/Server/BattlenetManager.cpp b/src/server/authserver/Server/BattlenetManager.cpp new file mode 100644 index 00000000000..f470c365b56 --- /dev/null +++ b/src/server/authserver/Server/BattlenetManager.cpp @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "BattlenetManager.h" +#include "DatabaseEnv.h" + +BattlenetMgr::~BattlenetMgr() +{ + for (Battlenet::Component* component : _components) + delete component; + + for (auto const& m : _modules) + delete m.second; +} + +void BattlenetMgr::Load() +{ + LoadComponents(); + LoadModules(); +} + +void BattlenetMgr::LoadComponents() +{ + QueryResult result = LoginDatabase.Query("SELECT Program, Platform, Build FROM battlenet_components"); + if (result) + { + do + { + Field* fields = result->Fetch(); + Battlenet::Component* component = new Battlenet::Component(); + component->Program = fields[0].GetString(); + component->Platform = fields[1].GetString(); + component->Build = fields[2].GetUInt32(); + + _components.insert(component); + _programs.insert(component->Program); + _platforms.insert(component->Platform); + + } while (result->NextRow()); + } +} + +void BattlenetMgr::LoadModules() +{ + QueryResult result = LoginDatabase.Query("SELECT `Hash`, `Name`, `Type`, `System`, `Data` FROM battlenet_modules"); + if (result) + { + do + { + Field* fields = result->Fetch(); + Battlenet::ModuleInfo* module = new Battlenet::ModuleInfo(); + module->Type = fields[2].GetString(); + HexStrToByteArray(fields[0].GetString(), module->ModuleId); + std::string data = fields[4].GetString(); + module->DataSize = data.length() / 2; + if (module->DataSize) + { + module->Data = new uint8[data.length() / 2]; + HexStrToByteArray(data, module->Data); + } + + _modules[{ fields[3].GetString(), fields[1].GetString() }] = module; + } while (result->NextRow()); + } +} + +bool BattlenetMgr::HasComponent(Battlenet::Component const* component) const +{ + for (Battlenet::Component const* c : _components) + if (component->Program == c->Program && component->Platform == c->Platform && component->Build == c->Build) + return true; + + return false; +} + +Battlenet::ModuleInfo* BattlenetMgr::CreateModule(std::string const& os, std::string const& name) const +{ + Battlenet::ModuleKey key { os, name }; + ASSERT(_modules.count(key)); + + return new Battlenet::ModuleInfo(*_modules.at(key)); +} diff --git a/src/server/authserver/Server/BattlenetManager.h b/src/server/authserver/Server/BattlenetManager.h new file mode 100644 index 00000000000..3b8a145f4e9 --- /dev/null +++ b/src/server/authserver/Server/BattlenetManager.h @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __BATTLENETMANAGER_H__ +#define __BATTLENETMANAGER_H__ + +#include "Define.h" +#include <ace/Singleton.h> +#include <string> +#include <set> +#include <map> + +namespace Battlenet +{ + struct Component + { + std::string Program; + std::string Platform; + uint32 Build; + }; + + struct ModuleKey + { + std::string Platform; + std::string Name; + + bool operator<(ModuleKey const& right) const + { + int32 res = Platform.compare(right.Platform); + if (res < 0) + return true; + else if (res > 0) + return false; + + return Name < right.Name; + } + }; + + struct ModuleInfo + { + ModuleInfo() : Region("EU"), DataSize(0), Data(nullptr) { } + ModuleInfo(ModuleInfo const& right) : Type(right.Type), Region(right.Region), DataSize(right.DataSize), Data(nullptr) + { + memcpy(ModuleId, right.ModuleId, 32); + if (DataSize) + { + Data = new uint8[DataSize]; + memcpy(Data, right.Data, DataSize); + } + } + ~ModuleInfo() + { + delete Data; + } + + std::string Type; + std::string Region; + uint8 ModuleId[32]; + uint32 DataSize; + uint8* Data; + }; + + struct RealmId + { + uint8 Region; + uint8 Battlegroup; + uint32 Index; + uint32 Build; + }; +} + +class BattlenetMgr +{ + friend class ACE_Singleton<BattlenetMgr, ACE_Null_Mutex>; + BattlenetMgr() { } + ~BattlenetMgr(); + +public: + void Load(); + bool HasComponent(Battlenet::Component const* component) const; + bool HasProgram(std::string const& program) const { return _programs.count(program); } + bool HasPlatform(std::string const& platform) const { return _platforms.count(platform); } + Battlenet::ModuleInfo* CreateModule(std::string const& os, std::string const& name) const; + +private: + void LoadComponents(); + void LoadModules(); + + std::set<Battlenet::Component*> _components; + std::set<std::string> _programs; + std::set<std::string> _platforms; + std::map<Battlenet::ModuleKey, Battlenet::ModuleInfo*> _modules; +}; + +#define sBattlenetMgr ACE_Singleton<BattlenetMgr, ACE_Null_Mutex>::instance() + +#endif // __BATTLENETMANAGER_H__ diff --git a/src/server/authserver/Server/BattlenetPacketCrypt.cpp b/src/server/authserver/Server/BattlenetPacketCrypt.cpp new file mode 100644 index 00000000000..de4cf73f71c --- /dev/null +++ b/src/server/authserver/Server/BattlenetPacketCrypt.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "BattlenetPacketCrypt.h" +#include "Cryptography/HmacHash.h" +#include "Cryptography/BigNumber.h" + +Battlenet::PacketCrypt::PacketCrypt() : ::PacketCrypt(SHA256_DIGEST_LENGTH) +{ +} + +void Battlenet::PacketCrypt::Init(BigNumber* K) +{ + uint8 ServerEncryptionKey[SEED_KEY_SIZE] = { 0x68, 0xE0, 0xC7, 0x2E, 0xDD, 0xD6, 0xD2, 0xF3, 0x1E, 0x5A, 0xB1, 0x55, 0xB1, 0x8B, 0x63, 0x1E }; + uint8 ClientDecryptionKey[SEED_KEY_SIZE] = { 0xDE, 0xA9, 0x65, 0xAE, 0x54, 0x3A, 0x1E, 0x93, 0x9E, 0x69, 0x0C, 0xAA, 0x68, 0xDE, 0x78, 0x39 }; + + HmacSha256 serverEncryptHmac(K->GetNumBytes(), K->AsByteArray().get()); + serverEncryptHmac.UpdateData(ServerEncryptionKey, SEED_KEY_SIZE); + serverEncryptHmac.Finalize(); + + HmacSha256 clientDecryptHmac(K->GetNumBytes(), K->AsByteArray().get()); + clientDecryptHmac.UpdateData(ClientDecryptionKey, SEED_KEY_SIZE); + clientDecryptHmac.Finalize(); + + _clientDecrypt.Init(clientDecryptHmac.GetDigest()); + _serverEncrypt.Init(serverEncryptHmac.GetDigest()); + _initialized = true; +} diff --git a/src/server/authserver/Server/BattlenetPacketCrypt.h b/src/server/authserver/Server/BattlenetPacketCrypt.h new file mode 100644 index 00000000000..dde687651d3 --- /dev/null +++ b/src/server/authserver/Server/BattlenetPacketCrypt.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __BATTLENETPACKETCRYPT_H__ +#define __BATTLENETPACKETCRYPT_H__ + +#include "PacketCrypt.h" + +class BigNumber; + +namespace Battlenet +{ + class PacketCrypt : public ::PacketCrypt + { + public: + PacketCrypt(); + + void Init(BigNumber* K) override; + }; +} + +#endif // __BATTLENETPACKETCRYPT_H__ diff --git a/src/server/authserver/Server/BattlenetPackets.cpp b/src/server/authserver/Server/BattlenetPackets.cpp new file mode 100644 index 00000000000..6a8e09090ef --- /dev/null +++ b/src/server/authserver/Server/BattlenetPackets.cpp @@ -0,0 +1,449 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "BattlenetPackets.h" +#include "Common.h" +#include "Util.h" +#include <limits> +#include <sstream> + +std::string Battlenet::PacketHeader::ToString() const +{ + std::ostringstream stream; + stream << "Battlenet::PacketHeader opcode: " << Opcode << ", channel: " << Channel; + return stream.str(); +} + +Battlenet::ServerPacket::ServerPacket(PacketHeader const& header) : Packet(header, *new BitStream()) +{ + _stream.Write(header.Opcode, 6); + _stream.Write(1, 1); + _stream.Write(header.Channel, 4); +} + +Battlenet::ServerPacket::~ServerPacket() +{ + delete &_stream; +} + +void Battlenet::AuthChallenge::Read() +{ + Program = _stream.ReadFourCC(); + Platform = _stream.ReadFourCC(); + Locale = _stream.ReadFourCC(); + + Components.resize(_stream.Read<uint32>(6)); + for (size_t i = 0; i < Components.size(); ++i) + { + Component& component = Components[i]; + component.Program = _stream.ReadFourCC(); + component.Platform = _stream.ReadFourCC(); + component.Build = _stream.Read<uint32>(32); + } + + if (_stream.Read<uint32>(1)) + Login = _stream.ReadString(9, 3); +} + +std::string Battlenet::AuthChallenge::ToString() const +{ + std::ostringstream stream; + stream << "Battlenet::AuthChallenge Program: " << Program << ", Platform: " << Platform << ", Locale: " << Locale; + for (Component const& component : Components) + stream << std::endl << "Battlenet::Component Program: " << component.Program << ", Platform: " << component.Platform << ", Build: " << component.Build; + + if (!Login.empty()) + stream << std::endl << "Battlenet::AuthChallenge Login: " << Login; + + return stream.str(); +} + +void Battlenet::AuthResumeInfo::Read() +{ + Program = _stream.ReadFourCC(); + Platform = _stream.ReadFourCC(); + Locale = _stream.ReadFourCC(); + + Components.resize(_stream.Read<uint32>(6)); + for (size_t i = 0; i < Components.size(); ++i) + { + Component& component = Components[i]; + component.Program = _stream.ReadFourCC(); + component.Platform = _stream.ReadFourCC(); + component.Build = _stream.Read<uint32>(32); + } + + Login = _stream.ReadString(9, 3); + Region = _stream.Read<uint8>(8); + GameAccountName = _stream.ReadString(5, 1); +} + +std::string Battlenet::AuthResumeInfo::ToString() const +{ + std::ostringstream stream; + stream << "Battlenet::AuthReconnect Program: " << Program << ", Platform: " << Platform << ", Locale: " << Locale; + for (Component const& component : Components) + stream << std::endl << "Battlenet::Component Program: " << component.Program << ", Platform: " << component.Platform << ", Build: " << component.Build; + + stream << std::endl << "Battlenet::AuthReconnect Login: " << Login; + stream << std::endl << "Battlenet::AuthReconnect Region: " << uint32(Region); + stream << std::endl << "Battlenet::AuthReconnect GameAccountName: " << GameAccountName; + + return stream.str(); +} + +Battlenet::ProofRequest::~ProofRequest() +{ + for (size_t i = 0; i < Modules.size(); ++i) + delete Modules[i]; +} + +void Battlenet::ProofRequest::Write() +{ + _stream.Write(Modules.size(), 3); + for (ModuleInfo const* info : Modules) + { + _stream.WriteBytes(info->Type.c_str(), 4); + _stream.WriteFourCC(info->Region); + _stream.WriteBytes(info->ModuleId, 32); + _stream.Write(info->DataSize, 10); + _stream.WriteBytes(info->Data, info->DataSize); + } +} + +std::string Battlenet::ProofRequest::ToString() const +{ + std::ostringstream stream; + stream << "Battlenet::ProofRequest modules " << Modules.size(); + for (ModuleInfo const* module : Modules) + stream << std::endl << "Battlenet::ModuleInfo Locale " << module->Region.c_str() << ", ModuleId " << ByteArrayToHexStr(module->ModuleId, 32) << ", DataSize " << module->DataSize << ", Data " << ByteArrayToHexStr(module->Data, module->DataSize); + + return stream.str(); +} + +Battlenet::ProofResponse::~ProofResponse() +{ + for (size_t i = 0; i < Modules.size(); ++i) + delete Modules[i]; +} + +void Battlenet::ProofResponse::Read() +{ + Modules.resize(_stream.Read<uint32>(3)); + for (size_t i = 0; i < Modules.size(); ++i) + { + BitStream*& dataStream = Modules[i]; + dataStream = new BitStream(_stream.Read<uint32>(10)); + memcpy(dataStream->GetBuffer(), _stream.ReadBytes(dataStream->GetSize()).get(), dataStream->GetSize()); + } +} + +std::string Battlenet::ProofResponse::ToString() const +{ + std::ostringstream stream; + stream << "Battlenet::ProofResponse Modules " << Modules.size(); + for (BitStream* module : Modules) + { + std::string hexStr = ByteArrayToHexStr(module->GetBuffer(), module->GetSize()); + stream << std::endl << "Battlenet::ProofResponse::ModuleData Size: " << module->GetSize() << ", Data: " << hexStr; + } + + return stream.str(); +} + +Battlenet::AuthComplete::~AuthComplete() +{ + for (ModuleInfo* m : Modules) + delete m; +} + +void Battlenet::AuthComplete::Write() +{ + _stream.Write(Result != 0, 1); + if (Result == 0) + { + _stream.Write(Modules.size(), 3); + for (size_t i = 0; i < Modules.size(); ++i) + { + ModuleInfo* info = Modules[i]; + _stream.WriteBytes(info->Type.c_str(), 4); + _stream.WriteFourCC(info->Region); + _stream.WriteBytes(info->ModuleId, 32); + _stream.Write(info->DataSize, 10); + _stream.WriteBytes(info->Data, info->DataSize); + } + + _stream.Write(PingTimeout + std::numeric_limits<int32>::min(), 32); + _stream.Write(1, 1); + // if written == 1 + { + _stream.Write(1, 1); + // if written == 1 + { + _stream.Write(Threshold, 32); + _stream.Write(Rate, 32); + } + } + + _stream.WriteString(FirstName, 8); // First name + _stream.WriteString(LastName, 8); // Last name - not set for WoW + + _stream.Write(AccountId, 32); + _stream.Write(Region, 8); + _stream.Write(0, 64); + + _stream.Write(GameAccountRegion, 8); + _stream.WriteString(GameAccountName, 5, -1); + _stream.Write(GameAccountFlags, 64); + + _stream.Write(0, 32); + } + else + { + _stream.Write(!Modules.empty(), 1); + if (!Modules.empty()) + { + ModuleInfo* info = Modules[0]; + _stream.WriteBytes(info->Type.c_str(), 4); + _stream.WriteFourCC(info->Region); + _stream.WriteBytes(info->ModuleId, 32); + } + + _stream.Write(ErrorType, 2); + if (ErrorType == 1) + { + _stream.Write(Result, 16); + _stream.Write(0x80000000, 32); + } + } +} + +std::string Battlenet::AuthComplete::ToString() const +{ + std::ostringstream stream; + stream << "Battlenet::AuthComplete AuthResult " << Result << " PingTimeout " << PingTimeout << " Threshold " << Threshold << " Rate " << Rate + << " FirstName " << FirstName << " LastName " << LastName << " AccountId " << AccountId << " Region " << uint32(Region) << " GameAccountName " << GameAccountName + << " GameAccountFlags " << GameAccountFlags << " Modules " << Modules.size(); + + for (ModuleInfo const* module : Modules) + stream << std::endl << "Battlenet::ModuleInfo Locale " << module->Region.c_str() << ", ModuleId " << ByteArrayToHexStr(module->ModuleId, 32) << ", DataSize " << module->DataSize << ", Data " << ByteArrayToHexStr(module->Data, module->DataSize); + + return stream.str(); +} + +void Battlenet::AuthComplete::SetAuthResult(AuthResult result) +{ + ErrorType = result != AUTH_OK ? 1 : 0; + Result = result; +} + +Battlenet::AuthResume::~AuthResume() +{ + for (ModuleInfo* m : Modules) + delete m; +} + +void Battlenet::AuthResume::Write() +{ + _stream.Write(Result != 0, 1); + if (Result == 0) + { + _stream.Write(Modules.size(), 3); + for (size_t i = 0; i < Modules.size(); ++i) + { + ModuleInfo* info = Modules[i]; + _stream.WriteBytes(info->Type.c_str(), 4); + _stream.WriteFourCC(info->Region); + _stream.WriteBytes(info->ModuleId, 32); + _stream.Write(info->DataSize, 10); + _stream.WriteBytes(info->Data, info->DataSize); + } + + _stream.Write(PingTimeout + std::numeric_limits<int32>::min(), 32); + _stream.Write(1, 1); + // if written == 1 + { + _stream.Write(1, 1); + // if written == 1 + { + _stream.Write(Threshold, 32); + _stream.Write(Rate, 32); + } + } + } + else + { + _stream.Write(!Modules.empty(), 1); + if (!Modules.empty()) + { + ModuleInfo* info = Modules[0]; + _stream.WriteBytes(info->Type.c_str(), 4); + _stream.WriteFourCC(info->Region); + _stream.WriteBytes(info->ModuleId, 32); + } + + _stream.Write(ErrorType, 2); + if (ErrorType == 1) + { + _stream.Write(Result, 16); + _stream.Write(0x80000000, 32); + } + } +} + +std::string Battlenet::AuthResume::ToString() const +{ + std::ostringstream stream; + stream << "Battlenet::AuthResume AuthResult " << Result << " PingTimeout " << PingTimeout << " Threshold " << Threshold << " Rate " << Rate << " Modules " << Modules.size(); + for (ModuleInfo const* module : Modules) + stream << std::endl << "Battlenet::ModuleInfo Locale " << module->Region.c_str() << ", ModuleId " << ByteArrayToHexStr(module->ModuleId, 32) << ", DataSize " << module->DataSize << ", Data " << ByteArrayToHexStr(module->Data, module->DataSize); + + return stream.str(); +} + +void Battlenet::AuthResume::SetAuthResult(AuthResult result) +{ + ErrorType = result != AUTH_OK ? 1 : 0; + Result = result; +} + +Battlenet::RealmCharacterCounts::~RealmCharacterCounts() +{ + for (ServerPacket* realmData : RealmData) + delete realmData; +} + +void Battlenet::RealmCharacterCounts::Write() +{ + _stream.Write(false, 1); // failure + _stream.Write(CharacterCounts.size(), 7); + for (CharacterCountEntry const& entry : CharacterCounts) + { + _stream.Write(entry.Realm.Battlegroup, 8); + _stream.Write(entry.Realm.Index, 32); + _stream.Write(entry.Realm.Region, 8); + _stream.Write(entry.CharacterCount, 16); + } + + for (ServerPacket* realmData : RealmData) + { + realmData->Write(); + _stream.WriteBytes(realmData->GetData(), realmData->GetSize()); + } +} + +std::string Battlenet::RealmCharacterCounts::ToString() const +{ + std::ostringstream stream; + stream << "Battlenet::RealmCharacterCounts Realms " << CharacterCounts.size(); + + for (CharacterCountEntry const& entry : CharacterCounts) + stream << std::endl << "Region " << uint32(entry.Realm.Region) << " Battlegroup " << uint32(entry.Realm.Region) << " Index " << entry.Realm.Index << " Characters " << entry.CharacterCount; + + for (ServerPacket* realmData : RealmData) + stream << std::endl << realmData->ToString(); + + return stream.str().c_str(); +} + +void Battlenet::RealmUpdate::Write() +{ + _stream.Write(true, 1); // Success + _stream.Write(Type + -std::numeric_limits<int32>::min(), 32); + _stream.WriteFloat(Population); + _stream.Write(Flags, 8); + _stream.Write(Lock, 8); + _stream.Write(Timezone, 32); + _stream.Write(!Version.empty(), 1); + if (!Version.empty()) + { + _stream.WriteString(Version, 5); + _stream.Write(Build, 32); + + uint32 ip = Address.get_ip_address(); + uint16 port = Address.get_port_number(); + + EndianConvertReverse(ip); + EndianConvertReverse(port); + + _stream.WriteBytes(&ip, 4); + _stream.WriteBytes(&port, 2); + } + + _stream.WriteString(Name, 10); + + _stream.Write(Battlegroup, 8); + _stream.Write(Index, 32); + _stream.Write(Region, 8); +} + +std::string Battlenet::RealmUpdate::ToString() const +{ + std::ostringstream stream; + stream << "Battlenet::RealmUpdate Timezone " << Timezone << " Population " << Population << " Lock " << uint32(Lock) << " Type " << Type << " Name " << Name + << " Flags " << uint32(Flags) << " Region " << uint32(Region) << " Battlegroup " << uint32(Battlegroup) << " Index " << Index; + + if (!Version.empty()) + stream << " Version " << Version; + + return stream.str().c_str(); +} + +void Battlenet::RealmJoinRequest::Read() +{ + Realm.Battlegroup = _stream.Read<uint8>(8); + Realm.Index = _stream.Read<uint32>(32); + Realm.Region = _stream.Read<uint8>(8); + ClientSeed = _stream.Read<uint32>(32); +} + +std::string Battlenet::RealmJoinRequest::ToString() const +{ + std::ostringstream stream; + stream << "Battlenet::RealmJoinRequest ClientSeed " << ClientSeed << " Region " << uint32(Realm.Region) << " Battlegroup " << uint32(Realm.Battlegroup) << " Index " << Realm.Index; + return stream.str().c_str(); +} + +void Battlenet::RealmJoinResult::Write() +{ + _stream.Write(0, 27); + _stream.Write(0, 1); // Fail + _stream.Write(ServerSeed, 32); + _stream.Write(0, 5); // IPv6 addresses + _stream.Write(IPv4.size(), 5); + for (ACE_INET_Addr const& addr : IPv4) + { + uint32 ip = addr.get_ip_address(); + uint16 port = addr.get_port_number(); + + EndianConvertReverse(ip); + EndianConvertReverse(port); + + _stream.WriteBytes(&ip, 4); + _stream.WriteBytes(&port, 2); + } +} + +std::string Battlenet::RealmJoinResult::ToString() const +{ + std::ostringstream stream; + stream << "Battlenet::RealmJoinResult ServerSeed " << ServerSeed << " IPv4 Addresses " << IPv4.size(); + for (ACE_INET_Addr const& addr : IPv4) + stream << std::endl << "Battlenet::RealmJoinResult::Address " << GetAddressString(addr); + + return stream.str().c_str(); +} diff --git a/src/server/authserver/Server/BattlenetPackets.h b/src/server/authserver/Server/BattlenetPackets.h new file mode 100644 index 00000000000..1505f21cc39 --- /dev/null +++ b/src/server/authserver/Server/BattlenetPackets.h @@ -0,0 +1,361 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __BATTLENETPACKETS_H__ +#define __BATTLENETPACKETS_H__ + +#include "AuthCodes.h" +#include "BattlenetBitStream.h" +#include "BattlenetManager.h" +#include "Define.h" +#include "Errors.h" +#include <ace/INET_Addr.h> +#include <string> + +namespace Battlenet +{ + class BitStream; + + enum Channel + { + AUTHENTICATION = 0, + CREEP = 1, + WOW = 2 + }; + + enum AuthOpcode + { + CMSG_AUTH_CHALLENGE = 0x0, + CMSG_AUTH_RECONNECT = 0x1, + CMSG_AUTH_PROOF_RESPONSE = 0x2, + + SMSG_AUTH_COMPLETE = 0x0, + SMSG_AUTH_RESUME = 0x1, + SMSG_AUTH_PROOF_REQUEST = 0x2 + }; + + enum CreepOpcodes + { + CMSG_PING = 0x0, + CMSG_ENABLE_ENCRYPTION = 0x5, + CMSG_DISCONNECT = 0x6, + CMSG_INVALID_PACKET = 0x9, + + SMSG_PONG = 0x0 + }; + + enum WoWOpcodes + { + CMSG_REALM_UPDATE_SUBSCRIBE = 0x0, + CMSG_REALM_UPDATE_UNSUBSCRIBE = 0x1, + CMSG_JOIN_REQUEST = 0x8, + + SMSG_CHARACTER_COUNTS = 0x0, + SMSG_REALM_UPDATE = 0x2, + SMSG_REALM_UPDATE_END = 0x3, + SMSG_JOIN_RESULT = 0x8 + }; + + struct PacketHeader + { + PacketHeader(uint32 opcode, uint32 channel) : Opcode(opcode), Channel(channel) { } + PacketHeader() : Opcode(0), Channel(AUTHENTICATION) { } + + uint32 Opcode; + int32 Channel; + + bool operator<(PacketHeader const& right) const + { + if (Opcode < right.Opcode) + return true; + if (Opcode > right.Opcode) + return false; + + return Channel < right.Channel; + } + + bool operator==(PacketHeader const& right) const + { + return Opcode == right.Opcode && Channel == right.Channel; + } + + std::string ToString() const; + }; + + class Packet + { + public: + Packet(PacketHeader const& header, BitStream& stream) : _header(header), _stream(stream) { } + virtual ~Packet() { } + + PacketHeader const& GetHeader() const { return _header; } + + virtual void Write() = 0; + virtual void Read() = 0; + + virtual std::string ToString() const = 0; + + protected: + PacketHeader _header; + BitStream& _stream; + + private: + Packet(Packet const& right); + Packet& operator=(Packet const& right); + }; + + class ClientPacket : public Packet + { + public: + ClientPacket(PacketHeader const& header, BitStream& stream) : Packet(header, stream) { } + + void Write() override final { ASSERT(!"Write not implemented for this packet."); } + }; + + class ServerPacket : public Packet + { + public: + ServerPacket(PacketHeader const& header); + ~ServerPacket(); + + void Read() override final { ASSERT(!"Read not implemented for server packets."); } + + uint8 const* GetData() const { return _stream.GetBuffer(); } + size_t GetSize() const { return _stream.GetSize(); } + }; + + class AuthChallenge final : public ClientPacket + { + public: + AuthChallenge(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) + { + ASSERT(header == PacketHeader(CMSG_AUTH_CHALLENGE, AUTHENTICATION) && "Invalid packet header for AuthChallenge"); + } + + void Read() override; + std::string ToString() const override; + + std::string Program; + std::string Platform; + std::string Locale; + std::vector<Component> Components; + std::string Login; + }; + + class AuthResumeInfo final : public ClientPacket + { + public: + AuthResumeInfo(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) + { + ASSERT(header == PacketHeader(CMSG_AUTH_RECONNECT, AUTHENTICATION) && "Invalid packet header for AuthResumeInfo"); + } + + void Read() override; + std::string ToString() const override; + + std::string Program; + std::string Platform; + std::string Locale; + std::vector<Component> Components; + std::string Login; + uint8 Region; + std::string GameAccountName; + }; + + class ProofRequest final : public ServerPacket + { + public: + ProofRequest() : ServerPacket(PacketHeader(SMSG_AUTH_PROOF_REQUEST, AUTHENTICATION)) { } + ~ProofRequest(); + + void Write() override; + std::string ToString() const override; + + std::vector<ModuleInfo*> Modules; + }; + + class ProofResponse final : public ClientPacket + { + public: + ProofResponse(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) + { + ASSERT(header == PacketHeader(CMSG_AUTH_PROOF_RESPONSE, AUTHENTICATION) && "Invalid packet header for ProofResponse"); + } + + ~ProofResponse(); + + void Read() override; + std::string ToString() const override; + + std::vector<BitStream*> Modules; + }; + + class AuthComplete final : public ServerPacket + { + public: + AuthComplete() : ServerPacket(PacketHeader(SMSG_AUTH_COMPLETE, AUTHENTICATION)), + Result(AUTH_OK), ErrorType(0), PingTimeout(120000), Threshold(25000000), Rate(1000), + FirstName(""), LastName(""), AccountId(0), Region(2), GameAccountRegion(2), GameAccountName("") + { + } + + ~AuthComplete(); + + void Write() override; + std::string ToString() const override; + + std::vector<ModuleInfo*> Modules; + void SetAuthResult(AuthResult result); + AuthResult Result; + uint32 ErrorType; + + int32 PingTimeout; + uint32 Threshold; + uint32 Rate; + std::string FirstName; + std::string LastName; + uint32 AccountId; + uint8 Region; + uint8 GameAccountRegion; + std::string GameAccountName; + uint64 GameAccountFlags; + }; + + class AuthResume final : public ServerPacket + { + public: + AuthResume() : ServerPacket(PacketHeader(SMSG_AUTH_RESUME, AUTHENTICATION)), + Result(AUTH_OK), ErrorType(0), PingTimeout(120000), Threshold(25000000), Rate(1000) + { + } + + ~AuthResume(); + + void Write() override; + std::string ToString() const override; + + std::vector<ModuleInfo*> Modules; + void SetAuthResult(AuthResult result); + AuthResult Result; + uint32 ErrorType; + + int32 PingTimeout; + uint32 Threshold; + uint32 Rate; + }; + + class Pong final : public ServerPacket + { + public: + Pong() : ServerPacket(PacketHeader(SMSG_PONG, CREEP)) + { + } + + void Write() override { } + std::string ToString() const override { return "Battlenet::Pong"; } + }; + + class RealmCharacterCounts final : public ServerPacket + { + public: + RealmCharacterCounts() : ServerPacket(PacketHeader(SMSG_CHARACTER_COUNTS, WOW)) + { + } + ~RealmCharacterCounts(); + + struct CharacterCountEntry + { + RealmId Realm; + uint32 CharacterCount; + }; + + void Write() override; + std::string ToString() const override; + + std::vector<CharacterCountEntry> CharacterCounts; + std::vector<ServerPacket*> RealmData; + }; + + class RealmUpdate final : public ServerPacket + { + public: + RealmUpdate() : ServerPacket(PacketHeader(SMSG_REALM_UPDATE, WOW)), + Timezone(0), Population(0.0f), Lock(0), Type(0), Name(""), Version(""), + Address(), Flags(0), Region(0), Battlegroup(0), Index(0), Build(0) + { + } + + void Write() override; + std::string ToString() const override; + + uint32 Timezone; + float Population; + uint8 Lock; + uint32 Type; + std::string Name; + std::string Version; + ACE_INET_Addr Address; + uint8 Flags; + uint8 Region; + uint8 Battlegroup; + uint32 Index; + uint32 Build; + }; + + class RealmUpdateComplete final : public ServerPacket + { + public: + RealmUpdateComplete() : ServerPacket(PacketHeader(SMSG_REALM_UPDATE_END, WOW)) + { + } + + void Write() override { } + std::string ToString() const override { return "Battlenet::RealmUpdateComplete"; } + }; + + class RealmJoinRequest final : public ClientPacket + { + public: + RealmJoinRequest(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) + { + ASSERT(header == PacketHeader(CMSG_JOIN_REQUEST, WOW) && "Invalid packet header for RealmJoinRequest"); + } + + void Read() override; + std::string ToString() const override; + + uint32 ClientSeed; + uint32 Unknown; + RealmId Realm; + }; + + class RealmJoinResult final : public ServerPacket + { + public: + RealmJoinResult() : ServerPacket(PacketHeader(SMSG_JOIN_RESULT, WOW)), ServerSeed(0) + { + } + + void Write() override; + std::string ToString() const override; + + uint32 ServerSeed; + std::vector<ACE_INET_Addr> IPv4; + }; +} + +#endif // __BATTLENETPACKETS_H__ diff --git a/src/server/authserver/Server/BattlenetSocket.cpp b/src/server/authserver/Server/BattlenetSocket.cpp new file mode 100644 index 00000000000..dad52f64877 --- /dev/null +++ b/src/server/authserver/Server/BattlenetSocket.cpp @@ -0,0 +1,1014 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "AuthCodes.h" +#include "BattlenetBitStream.h" +#include "BattlenetSocket.h" +#include "Database/DatabaseEnv.h" +#include "HmacHash.h" +#include "Log.h" +#include "RealmList.h" +#include "SHA256.h" +#include <map> + +uint32 const Battlenet::Socket::SRP6_V_Size = 128; +uint32 const Battlenet::Socket::SRP6_S_Size = 32; + +std::map<Battlenet::PacketHeader, Battlenet::Socket::PacketHandler> InitHandlers() +{ + std::map<Battlenet::PacketHeader, Battlenet::Socket::PacketHandler> handlers; + + handlers[Battlenet::PacketHeader(Battlenet::CMSG_AUTH_CHALLENGE, Battlenet::AUTHENTICATION)] = &Battlenet::Socket::HandleAuthChallenge; + handlers[Battlenet::PacketHeader(Battlenet::CMSG_AUTH_RECONNECT, Battlenet::AUTHENTICATION)] = &Battlenet::Socket::HandleAuthReconnect; + handlers[Battlenet::PacketHeader(Battlenet::CMSG_AUTH_PROOF_RESPONSE, Battlenet::AUTHENTICATION)] = &Battlenet::Socket::HandleAuthProofResponse; + + handlers[Battlenet::PacketHeader(Battlenet::CMSG_PING, Battlenet::CREEP)] = &Battlenet::Socket::HandlePing; + handlers[Battlenet::PacketHeader(Battlenet::CMSG_ENABLE_ENCRYPTION, Battlenet::CREEP)] = &Battlenet::Socket::HandleEnableEncryption; + handlers[Battlenet::PacketHeader(Battlenet::CMSG_DISCONNECT, Battlenet::CREEP)] = &Battlenet::Socket::HandleDisconnect; + + handlers[Battlenet::PacketHeader(Battlenet::CMSG_REALM_UPDATE_SUBSCRIBE, Battlenet::WOW)] = &Battlenet::Socket::HandleRealmUpdateSubscribe; + handlers[Battlenet::PacketHeader(Battlenet::CMSG_JOIN_REQUEST, Battlenet::WOW)] = &Battlenet::Socket::HandleRealmJoinRequest; + + return handlers; +} + +std::map<Battlenet::PacketHeader, Battlenet::Socket::PacketHandler> Handlers = InitHandlers(); + +Battlenet::Socket::ModuleHandler const Battlenet::Socket::ModuleHandlers[MODULE_COUNT] = +{ + &Battlenet::Socket::HandlePasswordModule, + &Battlenet::Socket::UnhandledModule, + &Battlenet::Socket::UnhandledModule, + &Battlenet::Socket::HandleSelectGameAccountModule, + &Battlenet::Socket::HandleRiskFingerprintModule, + &Battlenet::Socket::HandleResumeModule, +}; + +Battlenet::Socket::Socket(RealmSocket& socket) : _socket(socket), _accountId(0), _accountName(), _locale(), + _os(), _build(0), _gameAccountId(0), _gameAccountIndex(0), _accountSecurityLevel(SEC_PLAYER), I(), s(), v(), b(), B(), K(), + _reconnectProof(), _crypt(), _authed(false) +{ + static uint8 const N_Bytes[] = + { + 0xAB, 0x24, 0x43, 0x63, 0xA9, 0xC2, 0xA6, 0xC3, 0x3B, 0x37, 0xE4, 0x61, 0x84, 0x25, 0x9F, 0x8B, + 0x3F, 0xCB, 0x8A, 0x85, 0x27, 0xFC, 0x3D, 0x87, 0xBE, 0xA0, 0x54, 0xD2, 0x38, 0x5D, 0x12, 0xB7, + 0x61, 0x44, 0x2E, 0x83, 0xFA, 0xC2, 0x21, 0xD9, 0x10, 0x9F, 0xC1, 0x9F, 0xEA, 0x50, 0xE3, 0x09, + 0xA6, 0xE5, 0x5E, 0x23, 0xA7, 0x77, 0xEB, 0x00, 0xC7, 0xBA, 0xBF, 0xF8, 0x55, 0x8A, 0x0E, 0x80, + 0x2B, 0x14, 0x1A, 0xA2, 0xD4, 0x43, 0xA9, 0xD4, 0xAF, 0xAD, 0xB5, 0xE1, 0xF5, 0xAC, 0xA6, 0x13, + 0x1C, 0x69, 0x78, 0x64, 0x0B, 0x7B, 0xAF, 0x9C, 0xC5, 0x50, 0x31, 0x8A, 0x23, 0x08, 0x01, 0xA1, + 0xF5, 0xFE, 0x31, 0x32, 0x7F, 0xE2, 0x05, 0x82, 0xD6, 0x0B, 0xED, 0x4D, 0x55, 0x32, 0x41, 0x94, + 0x29, 0x6F, 0x55, 0x7D, 0xE3, 0x0F, 0x77, 0x19, 0xE5, 0x6C, 0x30, 0xEB, 0xDE, 0xF6, 0xA7, 0x86 + }; + + N.SetBinary(N_Bytes, sizeof(N_Bytes)); + g.SetDword(2); + + SHA256Hash sha; + sha.UpdateBigNumbers(&N, &g, NULL); + sha.Finalize(); + k.SetBinary(sha.GetDigest(), sha.GetLength()); +} + +void Battlenet::Socket::_SetVSFields(std::string const& pstr) +{ + s.SetRand(SRP6_S_Size * 8); + + BigNumber p; + p.SetHexStr(pstr.c_str()); + + SHA256Hash sha; + sha.UpdateBigNumbers(&s, &p, NULL); + sha.Finalize(); + BigNumber x; + x.SetBinary(sha.GetDigest(), sha.GetLength()); + v = g.ModExp(x, N); + + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_VS_FIELDS); + stmt->setString(0, v.AsHexStr()); + stmt->setString(1, s.AsHexStr()); + stmt->setString(2, _accountName); + + LoginDatabase.Execute(stmt); +} + +bool Battlenet::Socket::HandleAuthChallenge(PacketHeader& header, BitStream& packet) +{ + // Verify that this IP is not in the ip_banned table + LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_EXPIRED_IP_BANS)); + + std::string const& ip_address = _socket.getRemoteAddress(); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP_BANNED); + stmt->setString(0, ip_address); + if (PreparedQueryResult result = LoginDatabase.Query(stmt)) + { + AuthComplete complete; + complete.SetAuthResult(LOGIN_BANNED); + Send(complete); + TC_LOG_DEBUG("server.battlenet", "[Battlenet::AuthChallenge] Banned ip '%s:%d' tries to login!", _socket.getRemoteAddress().c_str(), _socket.getRemotePort()); + return true; + } + + AuthChallenge info(header, packet); + info.Read(); + + if (info.Program != "WoW") + { + AuthComplete complete; + complete.SetAuthResult(AUTH_INVALID_PROGRAM); + Send(complete); + return true; + } + + if (!sBattlenetMgr->HasPlatform(info.Platform)) + { + AuthComplete complete; + complete.SetAuthResult(AUTH_INVALID_OS); + Send(complete); + return true; + } + + if (!sBattlenetMgr->HasPlatform(info.Locale)) + { + AuthComplete complete; + complete.SetAuthResult(AUTH_UNSUPPORTED_LANGUAGE); + Send(complete); + return true; + } + + for (Component const& component : info.Components) + { + if (!sBattlenetMgr->HasComponent(&component)) + { + AuthComplete complete; + if (!sBattlenetMgr->HasProgram(component.Program)) + complete.SetAuthResult(AUTH_INVALID_PROGRAM); + else if (!sBattlenetMgr->HasPlatform(component.Platform)) + complete.SetAuthResult(AUTH_INVALID_OS); + else + { + if (component.Program != "WoW" || AuthHelper::IsBuildSupportingBattlenet(component.Build)) + complete.SetAuthResult(AUTH_REGION_BAD_VERSION); + else + complete.SetAuthResult(AUTH_USE_GRUNT_LOGON); + } + + Send(complete); + return true; + } + + if (component.Platform == "base") + _build = component.Build; + } + + _accountName = info.Login; + _locale = info.Locale; + _os = info.Platform; + + Utf8ToUpperOnlyLatin(_accountName); + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_INFO); + stmt->setString(0, _accountName); + + PreparedQueryResult result = LoginDatabase.Query(stmt); + if (!result) + { + AuthComplete complete; + complete.SetAuthResult(AUTH_UNKNOWN_ACCOUNT); + Send(complete); + return true; + } + + Field* fields = result->Fetch(); + + _accountId = fields[1].GetUInt32(); + + // If the IP is 'locked', check that the player comes indeed from the correct IP address + if (fields[2].GetUInt8() == 1) // if ip is locked + { + TC_LOG_DEBUG("server.battlenet", "[Battlenet::AuthChallenge] Account '%s' is locked to IP - '%s' is logging in from '%s'", _accountName.c_str(), fields[4].GetCString(), ip_address.c_str()); + + if (strcmp(fields[4].GetCString(), ip_address.c_str()) != 0) + { + AuthComplete complete; + complete.SetAuthResult(AUTH_ACCOUNT_LOCKED); + Send(complete); + return true; + } + } + else + { + TC_LOG_DEBUG("server.battlenet", "[Battlenet::AuthChallenge] Account '%s' is not locked to ip", _accountName.c_str()); + std::string accountCountry = fields[3].GetString(); + if (accountCountry.empty() || accountCountry == "00") + TC_LOG_DEBUG("server.battlenet", "[Battlenet::AuthChallenge] Account '%s' is not locked to country", _accountName.c_str()); + else if (!accountCountry.empty()) + { + uint32 ip = inet_addr(ip_address.c_str()); + EndianConvertReverse(ip); + + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LOGON_COUNTRY); + stmt->setUInt32(0, ip); + if (PreparedQueryResult sessionCountryQuery = LoginDatabase.Query(stmt)) + { + std::string loginCountry = (*sessionCountryQuery)[0].GetString(); + TC_LOG_DEBUG("server.battlenet", "[Battlenet::AuthChallenge] Account '%s' is locked to country: '%s' Player country is '%s'", _accountName.c_str(), accountCountry.c_str(), loginCountry.c_str()); + if (loginCountry != accountCountry) + { + AuthComplete complete; + complete.SetAuthResult(AUTH_ACCOUNT_LOCKED); + Send(complete); + return true; + } + } + } + } + + //set expired bans to inactive + LoginDatabase.DirectExecute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_BNET_EXPIRED_BANS)); + + // If the account is banned, reject the logon attempt + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACTIVE_ACCOUNT_BAN); + stmt->setUInt32(0, _accountId); + PreparedQueryResult banresult = LoginDatabase.Query(stmt); + if (banresult) + { + Field* fields = banresult->Fetch(); + if (fields[0].GetUInt32() == fields[1].GetUInt32()) + { + AuthComplete complete; + complete.SetAuthResult(LOGIN_BANNED); + Send(complete); + TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::AuthChallenge] Banned account %s tried to login!", _socket.getRemoteAddress().c_str(), _socket.getRemotePort(), _accountName.c_str()); + return true; + } + else + { + AuthComplete complete; + complete.SetAuthResult(LOGIN_SUSPENDED); + Send(complete); + TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::AuthChallenge] Temporarily banned account %s tried to login!", _socket.getRemoteAddress().c_str(), _socket.getRemotePort(), _accountName.c_str()); + return true; + } + } + + SHA256Hash sha; + sha.UpdateData(_accountName); + sha.Finalize(); + + I.SetBinary(sha.GetDigest(), sha.GetLength()); + + ModuleInfo* password = sBattlenetMgr->CreateModule(_os, "Password"); + ModuleInfo* thumbprint = sBattlenetMgr->CreateModule(_os, "Thumbprint"); + + std::string pStr = fields[0].GetString(); + + std::string databaseV = fields[5].GetString(); + std::string databaseS = fields[6].GetString(); + + if (databaseV.size() != SRP6_V_Size * 2 || databaseS.size() != SRP6_S_Size * 2) + _SetVSFields(pStr); + else + { + s.SetHexStr(databaseS.c_str()); + v.SetHexStr(databaseV.c_str()); + } + + b.SetRand(128 * 8); + B = ((v * k) + g.ModExp(b, N)) % N; + BigNumber unk; + unk.SetRand(128 * 8); + + BitStream passwordData; + uint8 state = 0; + passwordData.WriteBytes(&state, 1); + passwordData.WriteBytes(I.AsByteArray(32).get(), 32); + passwordData.WriteBytes(s.AsByteArray(32).get(), 32); + passwordData.WriteBytes(B.AsByteArray(128).get(), 128); + passwordData.WriteBytes(unk.AsByteArray(128).get(), 128); + + password->DataSize = passwordData.GetSize(); + password->Data = new uint8[password->DataSize]; + memcpy(password->Data, passwordData.GetBuffer(), password->DataSize); + + _modulesWaitingForData.push(MODULE_PASSWORD); + + ProofRequest request; + request.Modules.push_back(password); + // if has authenticator, send Token module + request.Modules.push_back(thumbprint); + Send(request); + return true; +} + +bool Battlenet::Socket::HandleAuthReconnect(PacketHeader& header, BitStream& packet) +{ + AuthResumeInfo reconnect(header, packet); + reconnect.Read(); + + TC_LOG_DEBUG("server.battlenet", "%s", reconnect.ToString().c_str()); + + _accountName = reconnect.Login; + _locale = reconnect.Locale; + _os = reconnect.Platform; + auto baseComponent = std::find_if(reconnect.Components.begin(), reconnect.Components.end(), [](Component const& c) { return c.Program == "base"; }); + if (baseComponent != reconnect.Components.end()) + _build = baseComponent->Build; + + uint8 accountIndex = atol(reconnect.GameAccountName.substr(reconnect.GameAccountName.find_last_of('#') + 1).c_str()); + + Utf8ToUpperOnlyLatin(_accountName); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_RECONNECT_INFO); + stmt->setString(0, _accountName); + stmt->setUInt8(1, accountIndex); + PreparedQueryResult result = LoginDatabase.Query(stmt); + if (!result) + { + AuthResume resume; + resume.SetAuthResult(AUTH_UNKNOWN_ACCOUNT); + Send(resume); + return false; + } + + Field* fields = result->Fetch(); + + _accountId = fields[0].GetUInt32(); + K.SetHexStr(fields[1].GetString().c_str()); + _gameAccountId = fields[2].GetUInt32(); + _gameAccountIndex = accountIndex; + + ModuleInfo* thumbprint = sBattlenetMgr->CreateModule(_os, "Thumbprint"); + ModuleInfo* resume = sBattlenetMgr->CreateModule(_os, "Resume"); + BitStream resumeData; + uint8 state = 0; + _reconnectProof.SetRand(16 * 8); + + resumeData.WriteBytes(&state, 1); + resumeData.WriteBytes(_reconnectProof.AsByteArray().get(), 16); + + resume->DataSize = resumeData.GetSize(); + resume->Data = new uint8[resume->DataSize]; + memcpy(resume->Data, resumeData.GetBuffer(), resume->DataSize); + + _modulesWaitingForData.push(MODULE_RESUME); + + ProofRequest request; + request.Modules.push_back(thumbprint); + request.Modules.push_back(resume); + Send(request); + return true; +} + +bool Battlenet::Socket::HandleAuthProofResponse(PacketHeader& header, BitStream& packet) +{ + ProofResponse proof(header, packet); + proof.Read(); + + if (_modulesWaitingForData.size() < proof.Modules.size()) + { + AuthComplete complete; + complete.SetAuthResult(AUTH_CORRUPTED_MODULE); + Send(complete); + return true; + } + + ServerPacket* response = nullptr; + for (size_t i = 0; i < proof.Modules.size(); ++i) + { + if (!(this->*(ModuleHandlers[_modulesWaitingForData.front()]))(proof.Modules[i], &response)) + break; + + _modulesWaitingForData.pop(); + } + + if (!response) + { + response = new AuthComplete(); + static_cast<AuthComplete*>(response)->SetAuthResult(AUTH_INTERNAL_ERROR); + } + + Send(*response); + delete response; + return true; +} + +bool Battlenet::Socket::HandlePing(PacketHeader& /*header*/, BitStream& /*packet*/) +{ + Pong pong; + Send(pong); + return true; +} + +bool Battlenet::Socket::HandleEnableEncryption(PacketHeader& /*header*/, BitStream& /*packet*/) +{ + _crypt.Init(&K); + return true; +} + +bool Battlenet::Socket::HandleDisconnect(PacketHeader& /*header*/, BitStream& /*packet*/) +{ + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_SESSION_KEY); + stmt->setString(0, ""); + stmt->setBool(1, false); + stmt->setUInt32(2, _accountId); + LoginDatabase.Execute(stmt); + return true; +} + +bool Battlenet::Socket::HandleRealmUpdateSubscribe(PacketHeader& /*header*/, BitStream& /*packet*/) +{ + sRealmList->UpdateIfNeed(); + + RealmCharacterCounts counts; + + ACE_INET_Addr clientAddr; + _socket.peer().get_remote_addr(clientAddr); + + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_CHARACTER_COUNTS); + stmt->setUInt32(0, _gameAccountId); + + if (PreparedQueryResult countResult = LoginDatabase.Query(stmt)) + { + do + { + Field* fields = countResult->Fetch(); + uint32 build = fields[4].GetUInt32(); + counts.CharacterCounts.push_back({ { fields[2].GetUInt8(), fields[3].GetUInt8(), fields[1].GetUInt32(), (_build != build ? build : 0) }, fields[0].GetUInt8() }); + } while (countResult->NextRow()); + } + + for (RealmList::RealmMap::const_iterator i = sRealmList->begin(); i != sRealmList->end(); ++i) + { + Realm const& realm = i->second; + + uint32 flag = realm.flag; + RealmBuildInfo const* buildInfo = AuthHelper::GetBuildInfo(realm.gamebuild); + if (realm.gamebuild != _build) + { + if (!buildInfo) + continue; + + flag |= REALM_FLAG_OFFLINE | REALM_FLAG_SPECIFYBUILD; // tell the client what build the realm is for + } + + if (!buildInfo) + flag &= ~REALM_FLAG_SPECIFYBUILD; + + RealmUpdate* update = new RealmUpdate(); + update->Timezone = realm.timezone; + update->Population = realm.populationLevel; + update->Lock = (realm.allowedSecurityLevel > _accountSecurityLevel) ? 1 : 0; + update->Type = realm.icon; + update->Name = realm.name; + + if (flag & REALM_FLAG_SPECIFYBUILD) + { + std::ostringstream version; + version << buildInfo->MajorVersion << '.' << buildInfo->MinorVersion << '.' << buildInfo->BugfixVersion << '.' << buildInfo->Build; + + update->Version = version.str(); + update->Address = realm.GetAddressForClient(clientAddr); + update->Build = buildInfo->Build; + } + + update->Flags = flag; + update->Region = realm.Region; + update->Battlegroup = realm.Battlegroup; + update->Index = realm.m_ID; + + counts.RealmData.push_back(update); + } + + counts.RealmData.push_back(new RealmUpdateComplete()); + + Send(counts); + return true; +} + +bool Battlenet::Socket::HandleRealmJoinRequest(PacketHeader& header, BitStream& packet) +{ + RealmJoinRequest join(header, packet); + join.Read(); + + RealmJoinResult result; + Realm const* realm = sRealmList->GetRealm(join.Realm); + if (!realm || realm->flag & (REALM_FLAG_INVALID | REALM_FLAG_OFFLINE)) + { + Send(result); + return true; + } + + result.ServerSeed = uint32(rand32()); + + uint8 sessionKey[40]; + HmacSha1 hmac(K.GetNumBytes(), K.AsByteArray().get()); + hmac.UpdateData((uint8*)"WoW\0", 4); + hmac.UpdateData((uint8*)&join.ClientSeed, 4); + hmac.UpdateData((uint8*)&result.ServerSeed, 4); + hmac.Finalize(); + + memcpy(sessionKey, hmac.GetDigest(), hmac.GetLength()); + + HmacSha1 hmac2(K.GetNumBytes(), K.AsByteArray().get()); + hmac2.UpdateData((uint8*)"WoW\0", 4); + hmac2.UpdateData((uint8*)&result.ServerSeed, 4); + hmac2.UpdateData((uint8*)&join.ClientSeed, 4); + hmac2.Finalize(); + + memcpy(sessionKey + hmac.GetLength(), hmac2.GetDigest(), hmac2.GetLength()); + + LoginDatabase.DirectPExecute("UPDATE account SET sessionkey = '%s', last_ip = '%s', last_login = NOW(), locale = %u, failed_logins = 0, os = '%s' WHERE id = %u", + ByteArrayToHexStr(sessionKey, 40, true).c_str(), _socket.getRemoteAddress().c_str(), GetLocaleByName(_locale), _os.c_str(), _gameAccountId); + + result.IPv4.push_back(realm->ExternalAddress); + if (realm->ExternalAddress != realm->LocalAddress) + result.IPv4.push_back(realm->LocalAddress); + + Send(result); + return true; +} + +void Battlenet::Socket::OnRead() +{ + size_t length = _socket.recv_len(); + if (!length) + return; + + BitStream packet(length); + if (!_socket.recv((char*)packet.GetBuffer(), length)) + return; + + _crypt.DecryptRecv(packet.GetBuffer(), length); + + while (!packet.IsRead()) + { + try + { + PacketHeader header; + header.Opcode = packet.Read<uint32>(6); + if (packet.Read<bool>(1)) + header.Channel = packet.Read<int32>(4); + + if (header.Channel != AUTHENTICATION && !_authed) + { + TC_LOG_DEBUG("server.battlenet", "Battlenet::Socket::OnRead Received not allowed packet %s", header.ToString().c_str()); + _socket.shutdown(); + return; + } + + TC_LOG_TRACE("server.battlenet", "Battlenet::Socket::OnRead %s", header.ToString().c_str()); + std::map<PacketHeader, PacketHandler>::const_iterator itr = Handlers.find(header); + if (itr != Handlers.end()) + { + if ((this->*(itr->second))(header, packet)) + break; + } + else + { + TC_LOG_DEBUG("server.battlenet", "Battlenet::Socket::OnRead Unhandled opcode %s", header.ToString().c_str()); + return; + } + + packet.AlignToNextByte(); + } + catch (BitStreamPositionException const& e) + { + TC_LOG_ERROR("server.battlenet", "Battlenet::Socket::OnRead Exception: %s", e.what()); + _socket.shutdown(); + return; + } + } +} + +void Battlenet::Socket::OnAccept() +{ + TC_LOG_TRACE("server.battlenet", "Battlenet::Socket::OnAccept"); +} + +void Battlenet::Socket::OnClose() +{ + TC_LOG_TRACE("server.battlenet", "Battlenet::Socket::OnClose"); +} + +void Battlenet::Socket::Send(ServerPacket& packet) +{ + TC_LOG_TRACE("server.battlenet", "Battlenet::Socket::Send %s", packet.ToString().c_str()); + + packet.Write(); + + _crypt.EncryptSend(const_cast<uint8*>(packet.GetData()), packet.GetSize()); + _socket.send(reinterpret_cast<char const*>(packet.GetData()), packet.GetSize()); +} + +inline void ReplaceResponse(Battlenet::ServerPacket** oldResponse, Battlenet::ServerPacket* newResponse) +{ + if (*oldResponse) + delete *oldResponse; + + *oldResponse = newResponse; +} + +bool Battlenet::Socket::HandlePasswordModule(BitStream* dataStream, ServerPacket** response) +{ + if (dataStream->GetSize() != 1 + 128 + 32 + 128) + { + AuthComplete* complete = new AuthComplete(); + complete->SetAuthResult(AUTH_CORRUPTED_MODULE); + ReplaceResponse(response, complete); + return false; + } + + if (dataStream->Read<uint8>(8) != 2) // State + { + AuthComplete* complete = new AuthComplete(); + complete->SetAuthResult(AUTH_CORRUPTED_MODULE); + ReplaceResponse(response, complete); + return false; + } + + + BigNumber A, clientM1, clientChallenge; + A.SetBinary(dataStream->ReadBytes(128).get(), 128); + clientM1.SetBinary(dataStream->ReadBytes(32).get(), 32); + clientChallenge.SetBinary(dataStream->ReadBytes(128).get(), 128); + + if (A.isZero()) + { + AuthComplete* complete = new AuthComplete(); + complete->SetAuthResult(AUTH_CORRUPTED_MODULE); + ReplaceResponse(response, complete); + return false; + } + + SHA256Hash sha; + sha.UpdateBigNumbers(&A, &B, NULL); + sha.Finalize(); + + BigNumber u; + u.SetBinary(sha.GetDigest(), sha.GetLength()); + + BigNumber S = ((A * v.ModExp(u, N)) % N).ModExp(b, N); + + uint8 S_bytes[128]; + memcpy(S_bytes, S.AsByteArray(128).get(), 128); + + uint8 part1[64]; + uint8 part2[64]; + + for (int i = 0; i < 64; ++i) + { + part1[i] = S_bytes[i * 2]; + part2[i] = S_bytes[i * 2 + 1]; + } + + SHA256Hash part1sha, part2sha; + part1sha.UpdateData(part1, 64); + part1sha.Finalize(); + part2sha.UpdateData(part2, 64); + part2sha.Finalize(); + + uint8 sessionKey[SHA256_DIGEST_LENGTH * 2]; + for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i) + { + sessionKey[i * 2] = part1sha.GetDigest()[i]; + sessionKey[i * 2 + 1] = part2sha.GetDigest()[i]; + } + + K.SetBinary(sessionKey, SHA256_DIGEST_LENGTH * 2); + + BigNumber M1; + + uint8 hash[SHA256_DIGEST_LENGTH]; + sha.Initialize(); + sha.UpdateBigNumbers(&N, NULL); + sha.Finalize(); + memcpy(hash, sha.GetDigest(), sha.GetLength()); + + sha.Initialize(); + sha.UpdateBigNumbers(&g, NULL); + sha.Finalize(); + + for (int i = 0; i < sha.GetLength(); ++i) + hash[i] ^= sha.GetDigest()[i]; + + SHA256Hash shaI; + shaI.UpdateData(ByteArrayToHexStr(I.AsByteArray().get(), 32)); + shaI.Finalize(); + + // Concat all variables for M1 hash + sha.Initialize(); + sha.UpdateData(hash, SHA256_DIGEST_LENGTH); + sha.UpdateData(shaI.GetDigest(), shaI.GetLength()); + sha.UpdateBigNumbers(&s, &A, &B, &K, NULL); + sha.Finalize(); + + M1.SetBinary(sha.GetDigest(), sha.GetLength()); + + if (memcmp(M1.AsByteArray().get(), clientM1.AsByteArray().get(), 32)) + { + AuthComplete* complete = new AuthComplete(); + complete->SetAuthResult(AUTH_UNKNOWN_ACCOUNT); + ReplaceResponse(response, complete); + return false; + } + + uint64 numAccounts = 0; + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_GAME_ACCOUNTS); + stmt->setUInt32(0, _accountId); + PreparedQueryResult result = LoginDatabase.Query(stmt); + if (result) + numAccounts = result->GetRowCount(); + + if (!numAccounts) + { + AuthComplete* noAccounts = new AuthComplete(); + noAccounts->SetAuthResult(LOGIN_NO_GAME_ACCOUNT); + ReplaceResponse(response, noAccounts); + return false; + } + + Field* fields = result->Fetch(); + + //set expired game account bans to inactive + LoginDatabase.DirectExecute(LoginDatabase.GetPreparedStatement(LOGIN_UPD_EXPIRED_ACCOUNT_BANS)); + + BigNumber M; + sha.Initialize(); + sha.UpdateBigNumbers(&A, &M1, &K, NULL); + sha.Finalize(); + M.SetBinary(sha.GetDigest(), sha.GetLength()); + + BigNumber serverProof; + serverProof.SetRand(128 * 8); // just send garbage, server signature check is patched out in client + + BitStream stream; + ModuleInfo* password = sBattlenetMgr->CreateModule(_os, "Password"); + uint8 state = 3; + + stream.WriteBytes(&state, 1); + stream.WriteBytes(M.AsByteArray(32).get(), 32); + stream.WriteBytes(serverProof.AsByteArray(128).get(), 128); + + password->DataSize = stream.GetSize(); + password->Data = new uint8[password->DataSize]; + memcpy(password->Data, stream.GetBuffer(), password->DataSize); + + ProofRequest* request = new ProofRequest(); + request->Modules.push_back(password); + if (numAccounts > 1) + { + BitStream accounts; + state = 0; + accounts.WriteBytes(&state, 1); + accounts.Write(numAccounts, 8); + do + { + fields = result->Fetch(); + std::ostringstream name; + name << "WoW" << uint32(fields[0].GetUInt8()); + accounts.Write(2, 8); + accounts.WriteString(name.str(), 8); + } while (result->NextRow()); + + ModuleInfo* selectGameAccount = sBattlenetMgr->CreateModule(_os, "SelectGameAccount"); + selectGameAccount->DataSize = accounts.GetSize(); + selectGameAccount->Data = new uint8[selectGameAccount->DataSize]; + memcpy(selectGameAccount->Data, accounts.GetBuffer(), selectGameAccount->DataSize); + request->Modules.push_back(selectGameAccount); + _modulesWaitingForData.push(MODULE_SELECT_GAME_ACCOUNT); + } + else + { + if (fields[4].GetBool()) + { + delete request; + + AuthComplete* complete = new AuthComplete(); + if (fields[2].GetUInt32() == fields[3].GetUInt32()) + { + complete->SetAuthResult(LOGIN_BANNED); + TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::AuthChallenge] Banned account %s tried to login!", _socket.getRemoteAddress().c_str(), _socket.getRemotePort(), _accountName.c_str()); + } + else + { + complete->SetAuthResult(LOGIN_SUSPENDED); + TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::AuthChallenge] Temporarily banned account %s tried to login!", _socket.getRemoteAddress().c_str(), _socket.getRemotePort(), _accountName.c_str()); + } + + ReplaceResponse(response, complete); + return false; + } + + _gameAccountId = fields[1].GetUInt32(); + _gameAccountIndex = fields[0].GetUInt8(); + + request->Modules.push_back(sBattlenetMgr->CreateModule(_os, "RiskFingerprint")); + _modulesWaitingForData.push(MODULE_RISK_FINGERPRINT); + } + + ReplaceResponse(response, request); + return true; +} + +bool Battlenet::Socket::HandleSelectGameAccountModule(BitStream* dataStream, ServerPacket** response) +{ + if (dataStream->Read<uint8>(8) != 1) + { + AuthComplete* complete = new AuthComplete(); + complete->SetAuthResult(AUTH_CORRUPTED_MODULE); + ReplaceResponse(response, complete); + return false; + } + + dataStream->Read<uint8>(8); + std::string account = dataStream->ReadString(8); + if (account.length() < 4) + { + AuthComplete* complete = new AuthComplete(); + complete->SetAuthResult(LOGIN_NO_GAME_ACCOUNT); + ReplaceResponse(response, complete); + return false; + } + + uint8 accountIndex = atol(account.substr(3).c_str()); + + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_GAME_ACCOUNT); + stmt->setUInt8(0, accountIndex); + stmt->setUInt32(1, _accountId); + PreparedQueryResult result = LoginDatabase.Query(stmt); + if (!result) + { + AuthComplete* complete = new AuthComplete(); + complete->SetAuthResult(LOGIN_NO_GAME_ACCOUNT); + ReplaceResponse(response, complete); + return false; + } + + Field* fields = result->Fetch(); + if (fields[3].GetBool()) + { + AuthComplete* complete = new AuthComplete(); + if (fields[1].GetUInt32() == fields[2].GetUInt32()) + { + complete->SetAuthResult(LOGIN_BANNED); + TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::SelectGameAccount] Banned account %s tried to login!", _socket.getRemoteAddress().c_str(), _socket.getRemotePort(), _accountName.c_str()); + } + else + { + complete->SetAuthResult(LOGIN_SUSPENDED); + TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::SelectGameAccount] Temporarily banned account %s tried to login!", _socket.getRemoteAddress().c_str(), _socket.getRemotePort(), _accountName.c_str()); + } + + ReplaceResponse(response, complete); + return false; + } + + _gameAccountId = fields[0].GetUInt32(); + _gameAccountIndex = accountIndex; + + ProofRequest* request = new ProofRequest(); + request->Modules.push_back(sBattlenetMgr->CreateModule(_os, "RiskFingerprint")); + ReplaceResponse(response, request); + + _modulesWaitingForData.push(MODULE_RISK_FINGERPRINT); + return true; +} + +bool Battlenet::Socket::HandleRiskFingerprintModule(BitStream* dataStream, ServerPacket** response) +{ + AuthComplete* complete = new AuthComplete(); + if (dataStream->Read<uint8>(8) == 1) + { + std::ostringstream str; + str << _accountId << "#" << uint32(_gameAccountIndex); + + complete->AccountId = _accountId; + complete->GameAccountName = str.str(); + complete->GameAccountFlags = GAMEACCOUNT_FLAG_PROPASS_LOCK; + + SQLTransaction trans = LoginDatabase.BeginTransaction(); + + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_LAST_LOGIN_INFO); + stmt->setString(0, _socket.getRemoteAddress()); + stmt->setUInt8(1, GetLocaleByName(_locale)); + stmt->setString(2, _os); + stmt->setUInt32(3, _accountId); + trans->Append(stmt); + + stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_SESSION_KEY); + stmt->setString(0, K.AsHexStr()); + stmt->setBool(1, true); + stmt->setUInt32(2, _accountId); + trans->Append(stmt); + + LoginDatabase.CommitTransaction(trans); + + _authed = true; + } + else + complete->SetAuthResult(AUTH_BAD_VERSION_HASH); + + ReplaceResponse(response, complete); + return true; +} + +bool Battlenet::Socket::HandleResumeModule(BitStream* dataStream, ServerPacket** response) +{ + if (dataStream->Read<uint8>(8) != 1) + { + AuthResume* complete = new AuthResume(); + complete->SetAuthResult(AUTH_CORRUPTED_MODULE); + ReplaceResponse(response, complete); + return false; + } + + static uint8 const ResumeClient = 0; + static uint8 const ResumeServer = 1; + + ACE_Auto_Array_Ptr<uint8>&& clientChallenge = dataStream->ReadBytes(16); + ACE_Auto_Array_Ptr<uint8>&& clientProof = dataStream->ReadBytes(32); + ACE_Auto_Array_Ptr<uint8>&& serverChallenge = _reconnectProof.AsByteArray(); + ACE_Auto_Array_Ptr<uint8>&& sessionKey = K.AsByteArray(); + + HmacSha256 clientPart(64, sessionKey.get()); + clientPart.UpdateData(&ResumeClient, 1); + clientPart.UpdateData(clientChallenge.get(), 16); + clientPart.UpdateData(serverChallenge.get(), 16); + clientPart.Finalize(); + + HmacSha256 serverPart(64, sessionKey.get()); + serverPart.UpdateData(&ResumeServer, 1); + serverPart.UpdateData(serverChallenge.get(), 16); + serverPart.UpdateData(clientChallenge.get(), 16); + serverPart.Finalize(); + + uint8 newSessionKey[64]; + memcpy(&newSessionKey[0], clientPart.GetDigest(), clientPart.GetLength()); + memcpy(&newSessionKey[32], serverPart.GetDigest(), serverPart.GetLength()); + + K.SetBinary(newSessionKey, 64); + + HmacSha256 proof(64, newSessionKey); + proof.UpdateData(&ResumeClient, 1); + proof.UpdateData(clientChallenge.get(), 16); + proof.UpdateData(serverChallenge.get(), 16); + proof.Finalize(); + + if (memcmp(proof.GetDigest(), clientProof.get(), serverPart.GetLength())) + { + TC_LOG_DEBUG("server.battlenet", "[Battlenet::Resume] Invalid proof!"); + AuthResume* result = new AuthResume(); + result->SetAuthResult(AUTH_UNKNOWN_ACCOUNT); + ReplaceResponse(response, result); + return false; + } + + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_SESSION_KEY); + stmt->setString(0, K.AsHexStr()); + stmt->setBool(1, true); + stmt->setUInt32(2, _accountId); + LoginDatabase.Execute(stmt); + + HmacSha256 serverProof(64, newSessionKey); + serverProof.UpdateData(&ResumeServer, 1); + serverProof.UpdateData(serverChallenge.get(), 16); + serverProof.UpdateData(clientChallenge.get(), 16); + serverProof.Finalize(); + + ModuleInfo* resume = sBattlenetMgr->CreateModule(_os, "Resume"); + + BitStream resumeData; + uint8 state = 2; + resumeData.WriteBytes(&state, 1); + resumeData.WriteBytes(serverProof.GetDigest(), serverProof.GetLength()); + + resume->DataSize = resumeData.GetSize(); + resume->Data = new uint8[resume->DataSize]; + memcpy(resume->Data, resumeData.GetBuffer(), resume->DataSize); + + AuthResume* result = new AuthResume(); + result->Modules.push_back(resume); + ReplaceResponse(response, result); + _authed = true; + return true; +} + +bool Battlenet::Socket::UnhandledModule(BitStream* /*dataStream*/, ServerPacket** response) +{ + AuthComplete* complete = new AuthComplete(); + complete->SetAuthResult(AUTH_CORRUPTED_MODULE); + ReplaceResponse(response, complete); + return false; +} diff --git a/src/server/authserver/Server/BattlenetSocket.h b/src/server/authserver/Server/BattlenetSocket.h new file mode 100644 index 00000000000..ee399e26b09 --- /dev/null +++ b/src/server/authserver/Server/BattlenetSocket.h @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _BATTLENETSOCKET_H +#define _BATTLENETSOCKET_H + +#include "RealmSocket.h" +#include "BattlenetPackets.h" +#include "BattlenetPacketCrypt.h" +#include "BigNumber.h" + +class ACE_INET_Addr; + +namespace Battlenet +{ + struct PacketHeader; + class BitStream; + + enum ModuleType + { + MODULE_PASSWORD, + MODULE_TOKEN, + MODULE_THUMBPRINT, + MODULE_SELECT_GAME_ACCOUNT, + MODULE_RISK_FINGERPRINT, + MODULE_RESUME, + + MODULE_COUNT + }; + + class Socket : public RealmSocket::Session + { + public: + static uint32 const SRP6_V_Size; + static uint32 const SRP6_S_Size; + + explicit Socket(RealmSocket& socket); + + typedef bool(Socket::*PacketHandler)(PacketHeader& socket, BitStream& packet); + + // Auth + bool HandleAuthChallenge(PacketHeader& header, BitStream& packet); + bool HandleAuthReconnect(PacketHeader& header, BitStream& packet); + bool HandleAuthProofResponse(PacketHeader& header, BitStream& packet); + + // Creep + bool HandlePing(PacketHeader& header, BitStream& packet); + bool HandleEnableEncryption(PacketHeader& header, BitStream& packet); + bool HandleDisconnect(PacketHeader& header, BitStream& packet); + + // WoW + bool HandleRealmUpdateSubscribe(PacketHeader& header, BitStream& packet); + bool HandleRealmJoinRequest(PacketHeader& header, BitStream& packet); + + void OnRead() override; + void OnAccept() override; + void OnClose() override; + + void Send(ServerPacket& packet); + + private: + void _SetVSFields(std::string const& rI); + + typedef bool(Socket::*ModuleHandler)(BitStream* dataStream, ServerPacket** response); + static ModuleHandler const ModuleHandlers[MODULE_COUNT]; + + bool HandlePasswordModule(BitStream* dataStream, ServerPacket** response); + bool HandleSelectGameAccountModule(BitStream* dataStream, ServerPacket** response); + bool HandleRiskFingerprintModule(BitStream* dataStream, ServerPacket** response); + bool HandleResumeModule(BitStream* dataStream, ServerPacket** response); + bool UnhandledModule(BitStream* dataStream, ServerPacket** response); + + RealmSocket& _socket; + + uint32 _accountId; + std::string _accountName; + std::string _locale; + std::string _os; + uint32 _build; + uint32 _gameAccountId; + uint8 _gameAccountIndex; + AccountTypes _accountSecurityLevel; + + BigNumber N; + BigNumber g; + BigNumber k; + + BigNumber I; + BigNumber s; + BigNumber v; + + BigNumber b; + BigNumber B; + BigNumber K; // session key + + BigNumber _reconnectProof; + + std::queue<ModuleType> _modulesWaitingForData; + + PacketCrypt _crypt; + bool _authed; + }; + +} + +#endif // _BATTLENETSOCKET_H diff --git a/src/server/authserver/Server/RealmAcceptor.h b/src/server/authserver/Server/RealmAcceptor.h index e89135c4896..2089b0c7a22 100644 --- a/src/server/authserver/Server/RealmAcceptor.h +++ b/src/server/authserver/Server/RealmAcceptor.h @@ -24,7 +24,9 @@ #include "RealmSocket.h" #include "AuthSocket.h" +#include "BattlenetSocket.h" +template<class LoginType> class RealmAcceptor : public ACE_Acceptor<RealmSocket, ACE_SOCK_Acceptor> { public: @@ -42,7 +44,7 @@ protected: ACE_NEW_RETURN(sh, RealmSocket, -1); sh->reactor(reactor()); - sh->set_session(new AuthSocket(*sh)); + sh->set_session(new LoginType(*sh)); return 0; } diff --git a/src/server/game/AI/CoreAI/PetAI.cpp b/src/server/game/AI/CoreAI/PetAI.cpp index 7c640f9a66d..8032568434f 100644 --- a/src/server/game/AI/CoreAI/PetAI.cpp +++ b/src/server/game/AI/CoreAI/PetAI.cpp @@ -183,7 +183,11 @@ void PetAI::UpdateAI(uint32 diff) } if (spellInfo->HasEffect(SPELL_EFFECT_JUMP_DEST)) + { + if (!spellUsed) + delete spell; continue; // Pets must only jump to target + } // No enemy, check friendly if (!spellUsed) diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 810d9b5d7ea..140bb5507b4 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -488,9 +488,6 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u } case SMART_ACTION_CAST: { - if (!me) - break; - ObjectList* targets = GetTargets(e, unit); if (!targets) break; @@ -502,31 +499,36 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u if (!(e.action.cast.flags & SMARTCAST_AURA_NOT_PRESENT) || !(*itr)->ToUnit()->HasAura(e.action.cast.spell)) { - if (e.action.cast.flags & SMARTCAST_INTERRUPT_PREVIOUS) - me->InterruptNonMeleeSpells(false); - - if (e.action.cast.flags & SMARTCAST_COMBAT_MOVE) + if (me) { - // If cast flag SMARTCAST_COMBAT_MOVE is set combat movement will not be allowed - // unless target is outside spell range, out of mana, or LOS. + if (e.action.cast.flags & SMARTCAST_INTERRUPT_PREVIOUS) + me->InterruptNonMeleeSpells(false); - bool _allowMove = false; - SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(e.action.cast.spell); - int32 mana = me->GetPower(POWER_MANA); + if (e.action.cast.flags & SMARTCAST_COMBAT_MOVE) + { + // If cast flag SMARTCAST_COMBAT_MOVE is set combat movement will not be allowed + // unless target is outside spell range, out of mana, or LOS. + + bool _allowMove = false; + SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(e.action.cast.spell); + int32 mana = me->GetPower(POWER_MANA); - if (me->GetDistance(*itr) > spellInfo->GetMaxRange(true) || - me->GetDistance(*itr) < spellInfo->GetMinRange(true) || - !me->IsWithinLOSInMap(*itr) || - mana < spellInfo->CalcPowerCost(me, spellInfo->GetSchoolMask())) + if (me->GetDistance(*itr) > spellInfo->GetMaxRange(true) || + me->GetDistance(*itr) < spellInfo->GetMinRange(true) || + !me->IsWithinLOSInMap(*itr) || + mana < spellInfo->CalcPowerCost(me, spellInfo->GetSchoolMask())) _allowMove = true; - CAST_AI(SmartAI, me->AI())->SetCombatMove(_allowMove); - } + CAST_AI(SmartAI, me->AI())->SetCombatMove(_allowMove); + } - me->CastSpell((*itr)->ToUnit(), e.action.cast.spell, (e.action.cast.flags & SMARTCAST_TRIGGERED)); + me->CastSpell((*itr)->ToUnit(), e.action.cast.spell, (e.action.cast.flags & SMARTCAST_TRIGGERED)); + } + else if (go) + go->CastSpell((*itr)->ToUnit(), e.action.cast.spell, (e.action.cast.flags & SMARTCAST_TRIGGERED)); - TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_CAST:: Creature %u casts spell %u on target %u with castflags %u", - me->GetGUIDLow(), e.action.cast.spell, (*itr)->GetGUIDLow(), e.action.cast.flags); + TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_CAST:: %s: %u casts spell %u on target %u with castflags %u", + GetLogNameForGuid(me ? me->GetGUID() : go->GetGUID()), me ? me->GetGUIDLow() : go->GetGUIDLow(), e.action.cast.spell, (*itr)->GetGUIDLow(), e.action.cast.flags); } else TC_LOG_DEBUG("scripts.ai", "Spell %u not cast because it has flag SMARTCAST_AURA_NOT_PRESENT and the target (Guid: " UI64FMTD " Entry: %u Type: %u) already has the aura", e.action.cast.spell, (*itr)->GetGUID(), (*itr)->GetEntry(), uint32((*itr)->GetTypeId())); diff --git a/src/server/game/Accounts/AccountMgr.cpp b/src/server/game/Accounts/AccountMgr.cpp index 773e169e5c2..59a8f046a6b 100644 --- a/src/server/game/Accounts/AccountMgr.cpp +++ b/src/server/game/Accounts/AccountMgr.cpp @@ -32,17 +32,17 @@ AccountMgr::~AccountMgr() ClearRBAC(); } -AccountOpResult AccountMgr::CreateAccount(std::string username, std::string password, std::string email = "") +AccountOpResult AccountMgr::CreateAccount(std::string username, std::string password, std::string email /*= ""*/) { if (utf8length(username) > MAX_ACCOUNT_STR) - return AOR_NAME_TOO_LONG; // username's too long + return AccountOpResult::AOR_NAME_TOO_LONG; // username's too long - normalizeString(username); - normalizeString(password); - normalizeString(email); + Utf8ToUpperOnlyLatin(username); + Utf8ToUpperOnlyLatin(password); + Utf8ToUpperOnlyLatin(email); if (GetId(username)) - return AOR_NAME_ALREADY_EXIST; // username does already exist + return AccountOpResult::AOR_NAME_ALREADY_EXIST; // username does already exist PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT); @@ -56,7 +56,7 @@ AccountOpResult AccountMgr::CreateAccount(std::string username, std::string pass stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_REALM_CHARACTERS_INIT); LoginDatabase.Execute(stmt); - return AOR_OK; // everything's fine + return AccountOpResult::AOR_OK; // everything's fine } AccountOpResult AccountMgr::DeleteAccount(uint32 accountId) @@ -67,7 +67,7 @@ AccountOpResult AccountMgr::DeleteAccount(uint32 accountId) PreparedQueryResult result = LoginDatabase.Query(stmt); if (!result) - return AOR_NAME_NOT_EXIST; + return AccountOpResult::AOR_NAME_NOT_EXIST; // Obtain accounts characters stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARS_BY_ACCOUNT_ID); @@ -128,7 +128,7 @@ AccountOpResult AccountMgr::DeleteAccount(uint32 accountId) LoginDatabase.CommitTransaction(trans); - return AOR_OK; + return AccountOpResult::AOR_OK; } AccountOpResult AccountMgr::ChangeUsername(uint32 accountId, std::string newUsername, std::string newPassword) @@ -139,16 +139,16 @@ AccountOpResult AccountMgr::ChangeUsername(uint32 accountId, std::string newUser PreparedQueryResult result = LoginDatabase.Query(stmt); if (!result) - return AOR_NAME_NOT_EXIST; + return AccountOpResult::AOR_NAME_NOT_EXIST; if (utf8length(newUsername) > MAX_ACCOUNT_STR) - return AOR_NAME_TOO_LONG; + return AccountOpResult::AOR_NAME_TOO_LONG; if (utf8length(newPassword) > MAX_ACCOUNT_STR) - return AOR_PASS_TOO_LONG; + return AccountOpResult::AOR_PASS_TOO_LONG; - normalizeString(newUsername); - normalizeString(newPassword); + Utf8ToUpperOnlyLatin(newUsername); + Utf8ToUpperOnlyLatin(newPassword); stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_USERNAME); @@ -158,7 +158,7 @@ AccountOpResult AccountMgr::ChangeUsername(uint32 accountId, std::string newUser LoginDatabase.Execute(stmt); - return AOR_OK; + return AccountOpResult::AOR_OK; } AccountOpResult AccountMgr::ChangePassword(uint32 accountId, std::string newPassword) @@ -166,13 +166,13 @@ AccountOpResult AccountMgr::ChangePassword(uint32 accountId, std::string newPass std::string username; if (!GetName(accountId, username)) - return AOR_NAME_NOT_EXIST; // account doesn't exist + return AccountOpResult::AOR_NAME_NOT_EXIST; // account doesn't exist if (utf8length(newPassword) > MAX_ACCOUNT_STR) - return AOR_PASS_TOO_LONG; + return AccountOpResult::AOR_PASS_TOO_LONG; - normalizeString(username); - normalizeString(newPassword); + Utf8ToUpperOnlyLatin(username); + Utf8ToUpperOnlyLatin(newPassword); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_PASSWORD); @@ -189,7 +189,7 @@ AccountOpResult AccountMgr::ChangePassword(uint32 accountId, std::string newPass LoginDatabase.Execute(stmt); - return AOR_OK; + return AccountOpResult::AOR_OK; } AccountOpResult AccountMgr::ChangeEmail(uint32 accountId, std::string newEmail) @@ -197,13 +197,13 @@ AccountOpResult AccountMgr::ChangeEmail(uint32 accountId, std::string newEmail) std::string username; if (!GetName(accountId, username)) - return AOR_NAME_NOT_EXIST; // account doesn't exist + return AccountOpResult::AOR_NAME_NOT_EXIST; // account doesn't exist if (utf8length(newEmail) > MAX_EMAIL_STR) - return AOR_EMAIL_TOO_LONG; + return AccountOpResult::AOR_EMAIL_TOO_LONG; - normalizeString(username); - normalizeString(newEmail); + Utf8ToUpperOnlyLatin(username); + Utf8ToUpperOnlyLatin(newEmail); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_EMAIL); @@ -212,7 +212,7 @@ AccountOpResult AccountMgr::ChangeEmail(uint32 accountId, std::string newEmail) LoginDatabase.Execute(stmt); - return AOR_OK; + return AccountOpResult::AOR_OK; } AccountOpResult AccountMgr::ChangeRegEmail(uint32 accountId, std::string newEmail) @@ -220,13 +220,13 @@ AccountOpResult AccountMgr::ChangeRegEmail(uint32 accountId, std::string newEmai std::string username; if (!GetName(accountId, username)) - return AOR_NAME_NOT_EXIST; // account doesn't exist + return AccountOpResult::AOR_NAME_NOT_EXIST; // account doesn't exist if (utf8length(newEmail) > MAX_EMAIL_STR) - return AOR_EMAIL_TOO_LONG; + return AccountOpResult::AOR_EMAIL_TOO_LONG; - normalizeString(username); - normalizeString(newEmail); + Utf8ToUpperOnlyLatin(username); + Utf8ToUpperOnlyLatin(newEmail); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_REG_EMAIL); @@ -235,7 +235,7 @@ AccountOpResult AccountMgr::ChangeRegEmail(uint32 accountId, std::string newEmai LoginDatabase.Execute(stmt); - return AOR_OK; + return AccountOpResult::AOR_OK; } uint32 AccountMgr::GetId(std::string const& username) @@ -303,8 +303,8 @@ bool AccountMgr::CheckPassword(uint32 accountId, std::string password) if (!GetName(accountId, username)) return false; - normalizeString(username); - normalizeString(password); + Utf8ToUpperOnlyLatin(username); + Utf8ToUpperOnlyLatin(password); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_CHECK_PASSWORD); stmt->setUInt32(0, accountId); @@ -322,8 +322,8 @@ bool AccountMgr::CheckEmail(uint32 accountId, std::string newEmail) if (!GetEmail(accountId, oldEmail)) return false; - normalizeString(oldEmail); - normalizeString(newEmail); + Utf8ToUpperOnlyLatin(oldEmail); + Utf8ToUpperOnlyLatin(newEmail); if (strcmp(oldEmail.c_str(), newEmail.c_str()) == 0) return true; @@ -341,19 +341,6 @@ uint32 AccountMgr::GetCharactersCount(uint32 accountId) return (result) ? (*result)[0].GetUInt64() : 0; } -bool AccountMgr::normalizeString(std::string& utf8String) -{ - wchar_t buffer[MAX_ACCOUNT_STR+1]; - - size_t maxLength = MAX_ACCOUNT_STR; - if (!Utf8toWStr(utf8String, buffer, maxLength)) - return false; - - std::transform(&buffer[0], buffer+maxLength, &buffer[0], wcharToUpperOnlyLatin); - - return WStrToUtf8(buffer, maxLength, utf8String); -} - std::string AccountMgr::CalculateShaPassHash(std::string const& name, std::string const& password) { SHA1Hash sha; diff --git a/src/server/game/Accounts/AccountMgr.h b/src/server/game/Accounts/AccountMgr.h index b3012ace177..f39873f0ebf 100644 --- a/src/server/game/Accounts/AccountMgr.h +++ b/src/server/game/Accounts/AccountMgr.h @@ -22,7 +22,7 @@ #include "RBAC.h" #include <ace/Singleton.h> -enum AccountOpResult +enum class AccountOpResult : uint8 { AOR_OK, AOR_NAME_TOO_LONG, @@ -40,6 +40,7 @@ enum PasswordChangeSecurity PW_RBAC }; +#define MAX_PASS_STR 16 #define MAX_ACCOUNT_STR 16 #define MAX_EMAIL_STR 64 @@ -58,7 +59,7 @@ class AccountMgr ~AccountMgr(); public: - AccountOpResult CreateAccount(std::string username, std::string password, std::string email); + AccountOpResult CreateAccount(std::string username, std::string password, std::string email = ""); static AccountOpResult DeleteAccount(uint32 accountId); static AccountOpResult ChangeUsername(uint32 accountId, std::string newUsername, std::string newPassword); static AccountOpResult ChangePassword(uint32 accountId, std::string newPassword); @@ -75,7 +76,6 @@ class AccountMgr static uint32 GetCharactersCount(uint32 accountId); static std::string CalculateShaPassHash(std::string const& name, std::string const& password); - static bool normalizeString(std::string& utf8String); static bool IsPlayerAccount(uint32 gmlevel); static bool IsAdminAccount(uint32 gmlevel); static bool IsConsoleAccount(uint32 gmlevel); diff --git a/src/server/game/Accounts/BattlenetAccountMgr.cpp b/src/server/game/Accounts/BattlenetAccountMgr.cpp new file mode 100644 index 00000000000..00cf1f88298 --- /dev/null +++ b/src/server/game/Accounts/BattlenetAccountMgr.cpp @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "AccountMgr.h" +#include "BattlenetAccountMgr.h" +#include "DatabaseEnv.h" +#include "Util.h" +#include "SHA256.h" + +AccountOpResult Battlenet::AccountMgr::CreateBattlenetAccount(std::string email, std::string password) +{ + if (utf8length(email) > MAX_BNET_EMAIL_STR) + return AccountOpResult::AOR_NAME_TOO_LONG; + + if (utf8length(password) > MAX_PASS_STR) + return AccountOpResult::AOR_PASS_TOO_LONG; + + Utf8ToUpperOnlyLatin(email); + Utf8ToUpperOnlyLatin(password); + + if (GetId(email)) + return AccountOpResult::AOR_NAME_ALREADY_EXIST; + + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_BNET_ACCOUNT); + stmt->setString(0, email); + stmt->setString(1, CalculateShaPassHash(email, password)); + LoginDatabase.Execute(stmt); + + return AccountOpResult::AOR_OK; +} + +AccountOpResult Battlenet::AccountMgr::ChangePassword(uint32 accountId, std::string newPassword) +{ + std::string username; + if (!GetName(accountId, username)) + return AccountOpResult::AOR_NAME_NOT_EXIST; // account doesn't exist + + Utf8ToUpperOnlyLatin(username); + Utf8ToUpperOnlyLatin(newPassword); + if (utf8length(newPassword) > MAX_PASS_STR) + return AccountOpResult::AOR_PASS_TOO_LONG; + + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_PASSWORD); + stmt->setString(0, username); + stmt->setString(1, CalculateShaPassHash(username, newPassword)); + stmt->setUInt32(2, accountId); + LoginDatabase.Execute(stmt); + + return AccountOpResult::AOR_OK; +} + +uint32 Battlenet::AccountMgr::GetId(std::string const& username) +{ + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_ID_BY_EMAIL); + stmt->setString(0, username); + if (PreparedQueryResult result = LoginDatabase.Query(stmt)) + return (*result)[0].GetUInt32(); + + return 0; +} + +uint32 Battlenet::AccountMgr::GetIdByGameAccount(uint32 gameAccountId) +{ + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_ID_BY_GAME_ACCOUNT); + stmt->setUInt32(0, gameAccountId); + if (PreparedQueryResult result = LoginDatabase.Query(stmt)) + return (*result)[0].GetUInt32(); + + return 0; +} + +bool Battlenet::AccountMgr::GetName(uint32 accountId, std::string& name) +{ + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_EMAIL_BY_ID); + stmt->setUInt32(0, accountId); + if (PreparedQueryResult result = LoginDatabase.Query(stmt)) + { + name = (*result)[0].GetString(); + return true; + } + + return false; +} + +bool Battlenet::AccountMgr::CheckPassword(uint32 accountId, std::string password) +{ + std::string username; + + if (!GetName(accountId, username)) + return false; + + Utf8ToUpperOnlyLatin(username); + Utf8ToUpperOnlyLatin(password); + + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_CHECK_PASSWORD); + stmt->setUInt32(0, accountId); + stmt->setString(1, CalculateShaPassHash(username, password)); + PreparedQueryResult result = LoginDatabase.Query(stmt); + + return !result.null(); +} + +std::string Battlenet::AccountMgr::CalculateShaPassHash(std::string const& name, std::string const& password) +{ + SHA256Hash email; + email.UpdateData(name); + email.Finalize(); + + SHA256Hash sha; + sha.UpdateData(ByteArrayToHexStr(email.GetDigest(), email.GetLength())); + sha.UpdateData(":"); + sha.UpdateData(password); + sha.Finalize(); + + return ByteArrayToHexStr(sha.GetDigest(), sha.GetLength(), true); +} + +bool Battlenet::AccountMgr::GetAccountIdAndIndex(std::string const& account, uint32* battlenetAccountId, uint8* battlenetAccountIndex) +{ + Tokenizer tokens(account, '#'); + if (tokens.size() != 2) + return false; + + if (!battlenetAccountId) + return false; + + *battlenetAccountId = atol(tokens[0]); + if (!*battlenetAccountId) + return false; + + if (battlenetAccountIndex) + { + *battlenetAccountIndex = atol(tokens[1]); + if (!*battlenetAccountIndex) + return false; + } + + return true; +} diff --git a/src/server/game/Accounts/BattlenetAccountMgr.h b/src/server/game/Accounts/BattlenetAccountMgr.h new file mode 100644 index 00000000000..61bfd044b68 --- /dev/null +++ b/src/server/game/Accounts/BattlenetAccountMgr.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef BattlenetAccountMgr_h__ +#define BattlenetAccountMgr_h__ + +#include "Define.h" +#include <string> +#include <ace/Singleton.h> + +enum class AccountOpResult : uint8; + +#define MAX_BNET_EMAIL_STR 320 + +namespace Battlenet +{ + namespace AccountMgr + { + AccountOpResult CreateBattlenetAccount(std::string email, std::string password); + AccountOpResult ChangePassword(uint32 accountId, std::string newPassword); + bool CheckPassword(uint32 accountId, std::string password); + + uint32 GetId(std::string const& username); + bool GetName(uint32 accountId, std::string& name); + uint32 GetIdByGameAccount(uint32 gameAccountId); + + std::string CalculateShaPassHash(std::string const& name, std::string const& password); + bool GetAccountIdAndIndex(std::string const& account, uint32* battlenetAccountId, uint8* battlenetAccountIndex); + } +} + +#endif // BattlenetAccountMgr_h__ diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h index 9ce1f9bb67a..f8d967c3e3a 100644 --- a/src/server/game/Accounts/RBAC.h +++ b/src/server/game/Accounts/RBAC.h @@ -110,13 +110,13 @@ enum RBACPermissions RBAC_PERM_COMMAND_RBAC_ACC_PERM_DENY = 204, RBAC_PERM_COMMAND_RBAC_ACC_PERM_REVOKE = 205, RBAC_PERM_COMMAND_RBAC_LIST = 206, - // 207 - reuse - // 208 - reuse - // 209 - reuse - // 210 - reuse - // 211 - reuse - // 212 - reuse - // 213 - reuse + RBAC_PERM_COMMAND_BNET_ACCOUNT = 207, + RBAC_PERM_COMMAND_BNET_ACCOUNT_CREATE = 208, + RBAC_PERM_COMMAND_BNET_ACCOUNT_LOCK_COUNTRY = 209, + RBAC_PERM_COMMAND_BNET_ACCOUNT_LOCK_IP = 210, + RBAC_PERM_COMMAND_BNET_ACCOUNT_PASSWORD = 211, + RBAC_PERM_COMMAND_BNET_ACCOUNT_SET = 212, + RBAC_PERM_COMMAND_BNET_ACCOUNT_SET_PASSWORD = 213, // 214 - reuse // 215 - reuse // 216 - reuse diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp index 9e9cc6c63ee..faa71fd2ffa 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp @@ -80,12 +80,11 @@ void BattlegroundIC::DoAction(uint32 action, uint64 var) if (!player) return; - player->SetTransport(player->GetTeamId() == TEAM_ALLIANCE ? gunshipAlliance : gunshipHorde); + (player->GetTeamId() == TEAM_ALLIANCE ? gunshipAlliance : gunshipHorde)->AddPassenger(player); player->m_movementInfo.transport.pos.m_positionX = TransportMovementInfo.GetPositionX(); player->m_movementInfo.transport.pos.m_positionY = TransportMovementInfo.GetPositionY(); player->m_movementInfo.transport.pos.m_positionZ = TransportMovementInfo.GetPositionZ(); - player->m_movementInfo.transport.guid = (player->GetTeamId() == TEAM_ALLIANCE ? gunshipAlliance : gunshipHorde)->GetGUID(); if (player->TeleportTo(GetMapId(), TeleportToTransportPosition.GetPositionX(), TeleportToTransportPosition.GetPositionY(), diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h index c3cebcdaeb1..08de27010db 100644 --- a/src/server/game/DataStores/DBCEnums.h +++ b/src/server/game/DataStores/DBCEnums.h @@ -550,6 +550,7 @@ enum VehicleSeatFlagsB VEHICLE_SEAT_FLAG_B_EJECTABLE = 0x00000020, // ejectable VEHICLE_SEAT_FLAG_B_USABLE_FORCED_2 = 0x00000040, VEHICLE_SEAT_FLAG_B_USABLE_FORCED_3 = 0x00000100, + VEHICLE_SEAT_FLAG_B_KEEP_PET = 0x00020000, VEHICLE_SEAT_FLAG_B_USABLE_FORCED_4 = 0x02000000, VEHICLE_SEAT_FLAG_B_CAN_SWITCH = 0x04000000, VEHICLE_SEAT_FLAG_B_VEHICLE_PLAYERFRAME_UI = 0x80000000 // Lua_UnitHasVehiclePlayerFrameUI - actually checked for flagsb &~ 0x80000000 diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 7ca34f02963..f976fb2c3e4 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -568,13 +568,13 @@ void Creature::Update(uint32 diff) if (!IsInEvadeMode() && (!bInCombat || IsPolymorphed())) // regenerate health if not in combat or if polymorphed RegenerateHealth(); - if (getPowerType() == POWER_ENERGY) + if (HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_REGENERATE_POWER)) { - if (!IsVehicle() || GetVehicleKit()->GetVehicleInfo()->m_powerDisplayId != POWER_PYRITE) + if (getPowerType() == POWER_ENERGY) Regenerate(POWER_ENERGY); + else + RegenerateMana(); } - else - RegenerateMana(); /*if (!bIsPolymorphed) // only increase the timer if not polymorphed m_regenTimer += CREATURE_REGEN_INTERVAL - diff; @@ -1186,14 +1186,22 @@ bool Creature::CreateFromProto(uint32 guidlow, uint32 entry, CreatureData const* SetOriginalEntry(entry); - if (!vehId) - vehId = cinfo->VehicleId; - - Object::_Create(guidlow, entry, vehId ? HIGHGUID_VEHICLE : HIGHGUID_UNIT); + Object::_Create(guidlow, entry, (vehId || cinfo->VehicleId) ? HIGHGUID_VEHICLE : HIGHGUID_UNIT); if (!UpdateEntry(entry, data)) return false; + if (!vehId) + { + if (GetCreatureTemplate()->VehicleId) + { + vehId = GetCreatureTemplate()->VehicleId; + entry = GetCreatureTemplate()->Entry; + } + else + vehId = cinfo->VehicleId; + } + if (vehId) CreateVehicleKit(vehId, entry); diff --git a/src/server/game/Entities/DynamicObject/DynamicObject.cpp b/src/server/game/Entities/DynamicObject/DynamicObject.cpp index 47ec8fceb0f..00d555c5e9c 100644 --- a/src/server/game/Entities/DynamicObject/DynamicObject.cpp +++ b/src/server/game/Entities/DynamicObject/DynamicObject.cpp @@ -48,18 +48,6 @@ DynamicObject::~DynamicObject() delete _removedAura; } -void DynamicObject::CleanupsBeforeDelete(bool finalCleanup /* = true */) -{ - WorldObject::CleanupsBeforeDelete(finalCleanup); - - if (Transport* transport = GetTransport()) - { - transport->RemovePassenger(this); - SetTransport(NULL); - m_movementInfo.transport.Reset(); - } -} - void DynamicObject::AddToWorld() { ///- Register the dynamicObject for guid lookup and for caster @@ -118,14 +106,11 @@ bool DynamicObject::CreateDynamicObject(uint32 guidlow, Unit* caster, SpellInfo Transport* transport = caster->GetTransport(); if (transport) { - m_movementInfo.transport.guid = GetGUID(); - float x, y, z, o; pos.GetPosition(x, y, z, o); transport->CalculatePassengerOffset(x, y, z, &o); m_movementInfo.transport.pos.Relocate(x, y, z, o); - SetTransport(transport); // This object must be added to transport before adding to map for the client to properly display it transport->AddPassenger(this); } diff --git a/src/server/game/Entities/DynamicObject/DynamicObject.h b/src/server/game/Entities/DynamicObject/DynamicObject.h index 735199db484..ed9b5a3af68 100644 --- a/src/server/game/Entities/DynamicObject/DynamicObject.h +++ b/src/server/game/Entities/DynamicObject/DynamicObject.h @@ -41,8 +41,6 @@ class DynamicObject : public WorldObject, public GridObject<DynamicObject>, publ void AddToWorld(); void RemoveFromWorld(); - void CleanupsBeforeDelete(bool finalCleanup = true) override; - bool CreateDynamicObject(uint32 guidlow, Unit* caster, SpellInfo const* spell, Position const& pos, float radius, DynamicObjectType type); void Update(uint32 p_time); void Remove(); diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index d07c3cb4bad..a2528c78516 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -98,20 +98,12 @@ std::string GameObject::GetAIName() const return ""; } -void GameObject::CleanupsBeforeDelete(bool /*finalCleanup*/) +void GameObject::CleanupsBeforeDelete(bool finalCleanup) { - if (IsInWorld()) - RemoveFromWorld(); + WorldObject::CleanupsBeforeDelete(finalCleanup); if (m_uint32Values) // field array can be not exist if GameOBject not loaded RemoveFromOwner(); - - if (GetTransport() && !ToTransport()) - { - GetTransport()->RemovePassenger(this); - SetTransport(NULL); - m_movementInfo.transport.Reset(); - } } void GameObject::RemoveFromOwner() @@ -695,12 +687,39 @@ void GameObject::getFishLoot(Loot* fishloot, Player* loot_owner) fishloot->clear(); uint32 zone, subzone; + uint32 defaultzone = 1; GetZoneAndAreaId(zone, subzone); // if subzone loot exist use it - if (!fishloot->FillLoot(subzone, LootTemplates_Fishing, loot_owner, true, true)) - // else use zone loot (must exist in like case) - fishloot->FillLoot(zone, LootTemplates_Fishing, loot_owner, true); + fishloot->FillLoot(subzone, LootTemplates_Fishing, loot_owner, true, true); + if (fishloot->empty()) //use this becase if zone or subzone has set LOOT_MODE_JUNK_FISH,Even if no normal drop, fishloot->FillLoot return true. it wrong. + { + //subzone no result,use zone loot + fishloot->FillLoot(zone, LootTemplates_Fishing, loot_owner, true, true); + //use zone 1 as default, somewhere fishing got nothing,becase subzone and zone not set, like Off the coast of Storm Peaks. + if (fishloot->empty()) + fishloot->FillLoot(defaultzone, LootTemplates_Fishing, loot_owner, true, true); + } +} + +void GameObject::getFishLootJunk(Loot* fishloot, Player* loot_owner) +{ + fishloot->clear(); + + uint32 zone, subzone; + uint32 defaultzone = 1; + GetZoneAndAreaId(zone, subzone); + + // if subzone loot exist use it + fishloot->FillLoot(subzone, LootTemplates_Fishing, loot_owner, true, true, LOOT_MODE_JUNK_FISH); + if (fishloot->empty()) //use this becase if zone or subzone has normal mask drop, then fishloot->FillLoot return true. + { + //use zone loot + fishloot->FillLoot(zone, LootTemplates_Fishing, loot_owner, true, true, LOOT_MODE_JUNK_FISH); + if (fishloot->empty()) + //use zone 1 as default + fishloot->FillLoot(defaultzone, LootTemplates_Fishing, loot_owner, true, true, LOOT_MODE_JUNK_FISH); + } } void GameObject::SaveToDB() @@ -1425,10 +1444,8 @@ void GameObject::Use(Unit* user) else player->SendLoot(GetGUID(), LOOT_FISHING); } - /// @todo else: junk - else - m_respawnTime = time(NULL); - + else // else: junk + player->SendLoot(GetGUID(), LOOT_FISHING_JUNK); break; } case GO_JUST_DEACTIVATED: // nothing to do, will be deleted at next update @@ -1739,7 +1756,7 @@ void GameObject::Use(Unit* user) CastSpell(user, spellId); } -void GameObject::CastSpell(Unit* target, uint32 spellId) +void GameObject::CastSpell(Unit* target, uint32 spellId, bool triggered /*= true*/) { SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); if (!spellInfo) @@ -1758,7 +1775,7 @@ void GameObject::CastSpell(Unit* target, uint32 spellId) if (self) { if (target) - target->CastSpell(target, spellInfo, true); + target->CastSpell(target, spellInfo, triggered); return; } @@ -1772,14 +1789,14 @@ void GameObject::CastSpell(Unit* target, uint32 spellId) trigger->setFaction(owner->getFaction()); // needed for GO casts for proper target validation checks trigger->SetOwnerGUID(owner->GetGUID()); - trigger->CastSpell(target ? target : trigger, spellInfo, true, 0, 0, owner->GetGUID()); + trigger->CastSpell(target ? target : trigger, spellInfo, triggered, 0, 0, owner->GetGUID()); } else { trigger->setFaction(14); // Set owner guid for target if no owner available - needed by trigger auras // - trigger gets despawned and there's no caster avalible (see AuraEffect::TriggerSpell()) - trigger->CastSpell(target ? target : trigger, spellInfo, true, 0, 0, target ? target->GetGUID() : 0); + trigger->CastSpell(target ? target : trigger, spellInfo, triggered, 0, 0, target ? target->GetGUID() : 0); } } diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index 32ef5a44d6c..11df5a17409 100644 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -716,6 +716,7 @@ class GameObject : public WorldObject, public GridObject<GameObject>, public Map void Refresh(); void Delete(); void getFishLoot(Loot* loot, Player* loot_owner); + void getFishLootJunk(Loot* loot, Player* loot_owner); GameobjectTypes GetGoType() const { return GameobjectTypes(GetByteValue(GAMEOBJECT_BYTES_1, 1)); } void SetGoType(GameobjectTypes type) { SetByteValue(GAMEOBJECT_BYTES_1, 1, type); } GOState GetGoState() const { return GOState(GetByteValue(GAMEOBJECT_BYTES_1, 0)); } @@ -793,7 +794,7 @@ class GameObject : public WorldObject, public GridObject<GameObject>, public Map GameObject* LookupFishingHoleAround(float range); - void CastSpell(Unit* target, uint32 spell); + void CastSpell(Unit* target, uint32 spell, bool triggered = true); void SendCustomAnim(uint32 anim); bool IsInRange(float x, float y, float z, float radius) const; diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h index 8a10784b3c2..211b5beaf04 100644 --- a/src/server/game/Entities/Item/Item.h +++ b/src/server/game/Entities/Item/Item.h @@ -231,6 +231,7 @@ class Item : public Object void SetBinding(bool val) { ApplyModFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_SOULBOUND, val); } bool IsSoulBound() const { return HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_SOULBOUND); } bool IsBoundAccountWide() const { return (GetTemplate()->Flags & ITEM_PROTO_FLAG_BIND_TO_ACCOUNT) != 0; } + bool IsBattlenetAccountBound() const { return GetTemplate()->Flags2 & ITEM_FLAGS_EXTRA_BNET_ACCOUNT_BOUND; } bool IsBindedNotWith(Player const* player) const; bool IsBoundByEnchant() const; virtual void SaveToDB(SQLTransaction& trans); diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index ee5e6a0faab..38f1469f7bd 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -1335,6 +1335,9 @@ void WorldObject::CleanupsBeforeDelete(bool /*finalCleanup*/) { if (IsInWorld()) RemoveFromWorld(); + + if (Transport* transport = GetTransport()) + transport->RemovePassenger(this); } void WorldObject::_Create(uint32 guidlow, HighGuid guidhigh, uint32 phaseMask) @@ -1387,7 +1390,7 @@ bool WorldObject::_IsWithinDist(WorldObject const* obj, float dist2compare, bool float sizefactor = GetObjectSize() + obj->GetObjectSize(); float maxdist = dist2compare + sizefactor; - if (m_transport && obj->GetTransport() && obj->GetTransport()->GetGUIDLow() == m_transport->GetGUIDLow()) + if (GetTransport() && obj->GetTransport() && obj->GetTransport()->GetGUIDLow() == GetTransport()->GetGUIDLow()) { float dtx = m_movementInfo.transport.pos.m_positionX - obj->m_movementInfo.transport.pos.m_positionX; float dty = m_movementInfo.transport.pos.m_positionY - obj->m_movementInfo.transport.pos.m_positionY; diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp index 4a2e9968c1a..c1b0ef43dbf 100644 --- a/src/server/game/Entities/Pet/Pet.cpp +++ b/src/server/game/Entities/Pet/Pet.cpp @@ -1879,6 +1879,8 @@ bool Pet::Create(uint32 guidlow, Map* map, uint32 phaseMask, uint32 Entry, uint3 if (!InitEntry(Entry)) return false; + // Force regen flag for player pets, just like we do for players themselves + SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_REGENERATE_POWER); SetSheath(SHEATH_STATE_MELEE); return true; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 283d4ead1a7..9c05f77cdf1 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -2150,11 +2150,9 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati { TC_LOG_DEBUG("maps", "Player %s using client without required expansion tried teleport to non accessible map %u", GetName().c_str(), mapid); - if (GetTransport()) + if (Transport* transport = GetTransport()) { - m_transport->RemovePassenger(this); - m_transport = NULL; - m_movementInfo.ResetTransport(); + transport->RemovePassenger(this); RepopAtGraveyard(); // teleport to near graveyard if on transport, looks blizz like :) } @@ -2173,14 +2171,10 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati m_movementInfo.ResetJump(); DisableSpline(); - if (m_transport) + if (Transport* transport = GetTransport()) { if (!(options & TELE_TO_NOT_LEAVE_TRANSPORT)) - { - m_transport->RemovePassenger(this); - m_transport = NULL; - m_movementInfo.ResetTransport(); - } + transport->RemovePassenger(this); } // The player was ported to another map and loses the duel immediately. @@ -2314,10 +2308,10 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati // send transfer packets WorldPacket data(SMSG_TRANSFER_PENDING, 4 + 4 + 4); data.WriteBit(0); // unknown - if (m_transport) + if (Transport* transport = GetTransport()) { data.WriteBit(1); // has transport - data << GetMapId() << m_transport->GetEntry(); + data << GetMapId() << transport->GetEntry(); } else data.WriteBit(0); // has transport @@ -7798,7 +7792,8 @@ void Player::UpdateArea(uint32 newArea) { SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY); pvpInfo.IsInNoPvPArea = true; - CombatStopWithPets(); + if (!duel) + CombatStopWithPets(); } else RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY); @@ -9002,7 +8997,7 @@ void Player::SendLoot(uint64 guid, LootType loot_type) // not check distance for GO in case owned GO (fishing bobber case, for example) // And permit out of range GO with no owner in case fishing hole - if (!go || (loot_type != LOOT_FISHINGHOLE && (loot_type != LOOT_FISHING || go->GetOwnerGUID() != GetGUID()) && !go->IsWithinDistInMap(this, INTERACTION_DISTANCE)) || (loot_type == LOOT_CORPSE && go->GetRespawnTime() && go->isSpawnedByDefault())) + if (!go || (loot_type != LOOT_FISHINGHOLE && ((loot_type != LOOT_FISHING && loot_type != LOOT_FISHING_JUNK) || go->GetOwnerGUID() != GetGUID()) && !go->IsWithinDistInMap(this, INTERACTION_DISTANCE)) || (loot_type == LOOT_CORPSE && go->GetRespawnTime() && go->isSpawnedByDefault())) { SendLootRelease(guid); return; @@ -9040,6 +9035,8 @@ void Player::SendLoot(uint64 guid, LootType loot_type) if (loot_type == LOOT_FISHING) go->getFishLoot(loot, this); + else if (loot_type == LOOT_FISHING_JUNK) + go->getFishLootJunk(loot, this); if (go->GetGOInfo()->type == GAMEOBJECT_TYPE_CHEST && go->GetGOInfo()->chest.groupLootRules) { @@ -9282,6 +9279,7 @@ void Player::SendLoot(uint64 guid, LootType loot_type) { case LOOT_INSIGNIA: loot_type = LOOT_SKINNING; break; case LOOT_FISHINGHOLE: loot_type = LOOT_FISHING; break; + case LOOT_FISHING_JUNK: loot_type = LOOT_FISHING; break; default: break; } @@ -17465,15 +17463,15 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder) { uint64 transGUID = MAKE_NEW_GUID(transLowGUID, 0, HIGHGUID_MO_TRANSPORT); + Transport* transport = NULL; if (GameObject* go = HashMapHolder<GameObject>::Find(transGUID)) - m_transport = go->ToTransport(); + transport = go->ToTransport(); - if (m_transport) + if (transport) { - m_movementInfo.transport.guid = transGUID; float x = fields[27].GetFloat(), y = fields[28].GetFloat(), z = fields[29].GetFloat(), o = fields[30].GetFloat(); m_movementInfo.transport.pos.Relocate(x, y, z, o); - m_transport->CalculatePassengerPosition(x, y, z, &o); + transport->CalculatePassengerPosition(x, y, z, &o); if (!Trinity::IsValidMapCoord(x, y, z, o) || // transport size limited @@ -17484,7 +17482,6 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder) TC_LOG_ERROR("entities.player", "Player (guidlow %d) have invalid transport coordinates (X: %f Y: %f Z: %f O: %f). Teleport to bind location.", guid, x, y, z, o); - m_transport = NULL; m_movementInfo.transport.Reset(); RelocateToHomebind(); @@ -17492,9 +17489,9 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder) else { Relocate(x, y, z, o); - mapId = m_transport->GetMapId(); + mapId = transport->GetMapId(); - m_transport->AddPassenger(this); + transport->AddPassenger(this); } } else @@ -20863,7 +20860,7 @@ void Player::TextEmote(const std::string& text) void Player::WhisperAddon(const std::string& text, const std::string& prefix, Player* receiver) { std::string _text(text); - sScriptMgr->OnPlayerChat(this, CHAT_MSG_WHISPER, LANG_ADDON, _text, receiver); + sScriptMgr->OnPlayerChat(this, CHAT_MSG_WHISPER, uint32(LANG_ADDON), _text, receiver); if (!receiver->GetSession()->IsAddonRegistered(prefix)) return; diff --git a/src/server/game/Entities/Transport/Transport.cpp b/src/server/game/Entities/Transport/Transport.cpp index 1e367149113..0c22caed882 100644 --- a/src/server/game/Entities/Transport/Transport.cpp +++ b/src/server/game/Entities/Transport/Transport.cpp @@ -35,7 +35,7 @@ Transport::Transport() : GameObject(), _transportInfo(NULL), _isMoving(true), _pendingStop(false), - _triggeredArrivalEvent(false), _triggeredDepartureEvent(false) + _triggeredArrivalEvent(false), _triggeredDepartureEvent(false), _passengerTeleportItr(_passengers.begin()) { m_updateFlag = UPDATEFLAG_TRANSPORT | UPDATEFLAG_LOWGUID | UPDATEFLAG_STATIONARY_POSITION | UPDATEFLAG_ROTATION; } @@ -107,8 +107,6 @@ void Transport::CleanupsBeforeDelete(bool finalCleanup /*= true*/) while (!_passengers.empty()) { WorldObject* obj = *_passengers.begin(); - obj->m_movementInfo.transport.Reset(); - obj->SetTransport(NULL); RemovePassenger(obj); } @@ -230,6 +228,8 @@ void Transport::AddPassenger(WorldObject* passenger) if (_passengers.insert(passenger).second) { + passenger->SetTransport(this); + passenger->m_movementInfo.transport.guid = GetGUID(); TC_LOG_DEBUG("entities.transport", "Object %s boarded transport %s.", passenger->GetName().c_str(), GetName().c_str()); if (Player* plr = passenger->ToPlayer()) @@ -239,8 +239,26 @@ void Transport::AddPassenger(WorldObject* passenger) void Transport::RemovePassenger(WorldObject* passenger) { - if (_passengers.erase(passenger) || _staticPassengers.erase(passenger)) // static passenger can remove itself in case of grid unload + bool erased = false; + if (_passengerTeleportItr != _passengers.end()) { + PassengerSet::iterator itr = _passengers.find(passenger); + if (itr != _passengers.end()) + { + if (itr == _passengerTeleportItr) + ++_passengerTeleportItr; + + _passengers.erase(itr); + erased = true; + } + } + else + erased = _passengers.erase(passenger) > 0; + + if (erased || _staticPassengers.erase(passenger)) // static passenger can remove itself in case of grid unload + { + passenger->SetTransport(NULL); + passenger->m_movementInfo.transport.Reset(); TC_LOG_DEBUG("entities.transport", "Object %s removed from transport %s.", passenger->GetName().c_str(), GetName().c_str()); if (Player* plr = passenger->ToPlayer()) @@ -581,9 +599,9 @@ bool Transport::TeleportTransport(uint32 newMapid, float x, float y, float z, fl GetMap()->RemoveFromMap<Transport>(this, false); SetMap(newMap); - for (std::set<WorldObject*>::iterator itr = _passengers.begin(); itr != _passengers.end();) + for (_passengerTeleportItr = _passengers.begin(); _passengerTeleportItr != _passengers.end();) { - WorldObject* obj = (*itr++); + WorldObject* obj = (*_passengerTeleportItr++); float destX, destY, destZ, destO; obj->m_movementInfo.transport.pos.GetPosition(destX, destY, destZ, destO); @@ -606,7 +624,7 @@ bool Transport::TeleportTransport(uint32 newMapid, float x, float y, float z, fl } case TYPEID_PLAYER: if (!obj->ToPlayer()->TeleportTo(newMapid, destX, destY, destZ, destO, TELE_TO_NOT_LEAVE_TRANSPORT)) - _passengers.erase(obj); + RemovePassenger(obj); break; case TYPEID_DYNAMICOBJECT: obj->AddObjectToRemoveList(); @@ -624,7 +642,7 @@ bool Transport::TeleportTransport(uint32 newMapid, float x, float y, float z, fl else { // Teleport players, they need to know it - for (std::set<WorldObject*>::iterator itr = _passengers.begin(); itr != _passengers.end(); ++itr) + for (PassengerSet::iterator itr = _passengers.begin(); itr != _passengers.end(); ++itr) { if ((*itr)->GetTypeId() == TYPEID_PLAYER) { @@ -641,9 +659,9 @@ bool Transport::TeleportTransport(uint32 newMapid, float x, float y, float z, fl } } -void Transport::UpdatePassengerPositions(std::set<WorldObject*>& passengers) +void Transport::UpdatePassengerPositions(PassengerSet& passengers) { - for (std::set<WorldObject*>::iterator itr = passengers.begin(); itr != passengers.end(); ++itr) + for (PassengerSet::iterator itr = passengers.begin(); itr != passengers.end(); ++itr) { WorldObject* passenger = *itr; // transport teleported but passenger not yet (can happen for players) diff --git a/src/server/game/Entities/Transport/Transport.h b/src/server/game/Entities/Transport/Transport.h index cfa8439f829..7da8c11861c 100644 --- a/src/server/game/Entities/Transport/Transport.h +++ b/src/server/game/Entities/Transport/Transport.h @@ -31,6 +31,8 @@ class Transport : public GameObject, public TransportBase Transport(); public: + typedef std::set<WorldObject*> PassengerSet; + ~Transport(); bool Create(uint32 guidlow, uint32 entry, uint32 mapid, float x, float y, float z, float ang, uint32 animprogress); @@ -42,7 +44,7 @@ class Transport : public GameObject, public TransportBase void AddPassenger(WorldObject* passenger); void RemovePassenger(WorldObject* passenger); - std::set<WorldObject*> const& GetPassengers() const { return _passengers; } + PassengerSet const& GetPassengers() const { return _passengers; } Creature* CreateNPCPassenger(uint32 guid, CreatureData const* data); GameObject* CreateGOPassenger(uint32 guid, GameObjectData const* data); @@ -99,7 +101,7 @@ class Transport : public GameObject, public TransportBase void MoveToNextWaypoint(); float CalculateSegmentPos(float perc); bool TeleportTransport(uint32 newMapid, float x, float y, float z, float o); - void UpdatePassengerPositions(std::set<WorldObject*>& passengers); + void UpdatePassengerPositions(PassengerSet& passengers); void DoEventIfAny(KeyFrame const& node, bool departure); //! Helpers to know if stop frame was reached @@ -118,8 +120,9 @@ class Transport : public GameObject, public TransportBase bool _triggeredArrivalEvent; bool _triggeredDepartureEvent; - std::set<WorldObject*> _passengers; - std::set<WorldObject*> _staticPassengers; + PassengerSet _passengers; + PassengerSet::iterator _passengerTeleportItr; + PassengerSet _staticPassengers; }; #endif diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 31425faf584..f2fd90bb964 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -3158,6 +3158,7 @@ void Unit::_ApplyAura(AuraApplication * aurApp, uint8 effMask) return; aura->HandleAuraSpecificMods(aurApp, caster, true, false); + aura->HandleAuraSpecificPeriodics(aurApp, caster); // apply effects of the aura for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) @@ -3275,6 +3276,19 @@ void Unit::_RemoveNoStackAurasDueToAura(Aura* aura) if (spellProto->IsPassiveStackableWithRanks()) return; + if (!IsHighestExclusiveAura(aura)) + { + if (!aura->GetSpellInfo()->IsAffectingArea()) + { + Unit* caster = aura->GetCaster(); + if (caster && caster->GetTypeId() == TYPEID_PLAYER) + Spell::SendCastResult(caster->ToPlayer(), aura->GetSpellInfo(), 1, SPELL_FAILED_AURA_BOUNCED); + } + + RemoveAura(aura); + return; + } + bool remove = false; for (AuraApplicationMap::iterator i = m_appliedAuras.begin(); i != m_appliedAuras.end(); ++i) { @@ -6922,23 +6936,14 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg if (GetTypeId() != TYPEID_PLAYER) return false; + float averageDmg = 0; // now compute approximate weapon damage by formula from wowwiki.com - Item* item = NULL; if (procFlags & PROC_FLAG_DONE_OFFHAND_ATTACK) - item = ToPlayer()->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND); + averageDmg = (GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE) + GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE)) / 2; else - item = ToPlayer()->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND); - - // dunno if it's really needed but will prevent any possible crashes - if (!item) - return false; - - ItemTemplate const* weapon = item->GetTemplate(); + averageDmg = (GetFloatValue(UNIT_FIELD_MINDAMAGE) + GetFloatValue(UNIT_FIELD_MAXDAMAGE)) / 2; - float weaponDPS = weapon->DPS; - float attackPower = GetTotalAttackPowerValue(BASE_ATTACK) / 14.0f; - float weaponSpeed = float(weapon->Delay) / 1000.0f; - basepoints0 = int32((weaponDPS + attackPower) * weaponSpeed); + basepoints0 = int32(averageDmg); break; } // Persistent Shield (Scarab Brooch trinket) @@ -7230,21 +7235,26 @@ void Unit::setPowerType(Powers new_powertype) } } + float powerMultiplier = 1.0f; + if (!IsPet()) + if (Creature* creature = ToCreature()) + powerMultiplier = creature->GetCreatureTemplate()->ModMana; + switch (new_powertype) { default: case POWER_MANA: break; case POWER_RAGE: - SetMaxPower(POWER_RAGE, GetCreatePowers(POWER_RAGE)); + SetMaxPower(POWER_RAGE, uint32(std::ceil(GetCreatePowers(POWER_RAGE) * powerMultiplier))); SetPower(POWER_RAGE, 0); break; case POWER_FOCUS: - SetMaxPower(POWER_FOCUS, GetCreatePowers(POWER_FOCUS)); - SetPower(POWER_FOCUS, GetCreatePowers(POWER_FOCUS)); + SetMaxPower(POWER_FOCUS, uint32(std::ceil(GetCreatePowers(POWER_FOCUS) * powerMultiplier))); + SetPower(POWER_FOCUS, uint32(std::ceil(GetCreatePowers(POWER_FOCUS) * powerMultiplier))); break; case POWER_ENERGY: - SetMaxPower(POWER_ENERGY, GetCreatePowers(POWER_ENERGY)); + SetMaxPower(POWER_ENERGY, uint32(std::ceil(GetCreatePowers(POWER_ENERGY) * powerMultiplier))); break; } } @@ -8420,39 +8430,162 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin if (Unit* owner = GetOwner()) return owner->SpellDamageBonusDone(victim, spellProto, pdamage, damagetype); - // Done total percent damage auras - float DoneTotalMod = 1.0f; float ApCoeffMod = 1.0f; int32 DoneTotal = 0; + // done scripted mod (take it from owner) + Unit const* owner = GetOwner() ? GetOwner() : this; + AuraEffectList const& mOverrideClassScript = owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); + for (AuraEffectList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i) + { + if (!(*i)->IsAffectingSpell(spellProto)) + continue; + + switch ((*i)->GetMiscValue()) + { + case 4418: // Increased Shock Damage + case 4554: // Increased Lightning Damage + case 4555: // Improved Moonfire + case 5142: // Increased Lightning Damage + case 5147: // Improved Consecration / Libram of Resurgence + case 5148: // Idol of the Shooting Star + case 6008: // Increased Lightning Damage + case 8627: // Totem of Hex + { + DoneTotal += (*i)->GetAmount(); + break; + } + } + } + + // Custom scripted damage + switch (spellProto->SpellFamilyName) + { + case SPELLFAMILY_DEATHKNIGHT: + // Impurity (dummy effect) + if (GetTypeId() == TYPEID_PLAYER) + { + PlayerSpellMap playerSpells = ToPlayer()->GetSpellMap(); + for (PlayerSpellMap::const_iterator itr = playerSpells.begin(); itr != playerSpells.end(); ++itr) + { + if (itr->second->state == PLAYERSPELL_REMOVED || itr->second->disabled) + continue; + switch (itr->first) + { + case 49220: + case 49633: + case 49635: + case 49636: + case 49638: + if (SpellInfo const* proto = sSpellMgr->GetSpellInfo(itr->first)) + AddPct(ApCoeffMod, proto->Effects[0].CalcValue()); + break; + } + } + } + break; + } + + // Done fixed damage bonus auras + int32 DoneAdvertisedBenefit = SpellBaseDamageBonusDone(spellProto->GetSchoolMask()); + // Pets just add their bonus damage to their spell damage + // note that their spell damage is just gain of their own auras + if (HasUnitTypeMask(UNIT_MASK_GUARDIAN)) + DoneAdvertisedBenefit += ((Guardian*)this)->GetBonusDamage(); + + // Check for table values + float coeff = 0; + SpellBonusEntry const* bonus = sSpellMgr->GetSpellBonusData(spellProto->Id); + if (bonus) + { + if (damagetype == DOT) + { + coeff = bonus->dot_damage; + if (bonus->ap_dot_bonus > 0) + { + WeaponAttackType attType = (spellProto->IsRangedWeaponSpell() && spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK; + float APbonus = float(victim->GetTotalAuraModifier(attType == BASE_ATTACK ? SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS : SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS)); + APbonus += GetTotalAttackPowerValue(attType); + DoneTotal += int32(bonus->ap_dot_bonus * stack * ApCoeffMod * APbonus); + } + } + else + { + coeff = bonus->direct_damage; + if (bonus->ap_bonus > 0) + { + WeaponAttackType attType = (spellProto->IsRangedWeaponSpell() && spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK; + float APbonus = float(victim->GetTotalAuraModifier(attType == BASE_ATTACK ? SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS : SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS)); + APbonus += GetTotalAttackPowerValue(attType); + DoneTotal += int32(bonus->ap_bonus * stack * ApCoeffMod * APbonus); + } + } + } + // Default calculation + if (DoneAdvertisedBenefit) + { + if (!bonus || coeff < 0) + coeff = CalculateDefaultCoefficient(spellProto, damagetype) * int32(stack); + + float factorMod = CalculateLevelPenalty(spellProto) * stack; + + if (Player* modOwner = GetSpellModOwner()) + { + coeff *= 100.0f; + modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_BONUS_MULTIPLIER, coeff); + coeff /= 100.0f; + } + DoneTotal += int32(DoneAdvertisedBenefit * coeff * factorMod); + } + + // Done Percentage for DOT is already calculated, no need to do it again. The percentage mod is applied in Aura::HandleAuraSpecificMods. + float tmpDamage = (int32(pdamage) + DoneTotal) * (damagetype == DOT ? 1.0f : SpellDamagePctDone(victim, spellProto, damagetype)); + // apply spellmod to Done damage (flat and pct) + if (Player* modOwner = GetSpellModOwner()) + modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, tmpDamage); + + return uint32(std::max(tmpDamage, 0.0f)); +} + +float Unit::SpellDamagePctDone(Unit* victim, SpellInfo const* spellProto, DamageEffectType damagetype) const +{ + if (!spellProto || !victim || damagetype == DIRECT_DAMAGE) + return 1.0f; + + // Some spells don't benefit from pct done mods + if (spellProto->AttributesEx6 & SPELL_ATTR6_NO_DONE_PCT_DAMAGE_MODS) + return 1.0f; + + // For totems pct done mods are calculated when its calculation is run on the player in SpellDamageBonusDone. + if (GetTypeId() == TYPEID_UNIT && ToCreature()->IsTotem()) + return 1.0f; + + // Done total percent damage auras + float DoneTotalMod = 1.0f; + // Pet damage? if (GetTypeId() == TYPEID_UNIT && !ToCreature()->IsPet()) DoneTotalMod *= ToCreature()->GetSpellDamageMod(ToCreature()->GetCreatureTemplate()->rank); - // Some spells don't benefit from pct done mods - if (!(spellProto->AttributesEx6 & SPELL_ATTR6_NO_DONE_PCT_DAMAGE_MODS)) + AuraEffectList const& mModDamagePercentDone = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); + for (AuraEffectList::const_iterator i = mModDamagePercentDone.begin(); i != mModDamagePercentDone.end(); ++i) { - AuraEffectList const& mModDamagePercentDone = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); - for (AuraEffectList::const_iterator i = mModDamagePercentDone.begin(); i != mModDamagePercentDone.end(); ++i) - { - if (spellProto->EquippedItemClass == -1 && (*i)->GetSpellInfo()->EquippedItemClass != -1) //prevent apply mods from weapon specific case to non weapon specific spells (Example: thunder clap and two-handed weapon specialization) - continue; + if (spellProto->EquippedItemClass == -1 && (*i)->GetSpellInfo()->EquippedItemClass != -1) //prevent apply mods from weapon specific case to non weapon specific spells (Example: thunder clap and two-handed weapon specialization) + continue; - if ((*i)->GetMiscValue() & spellProto->GetSchoolMask()) - { - if ((*i)->GetSpellInfo()->EquippedItemClass == -1) - AddPct(DoneTotalMod, (*i)->GetAmount()); - else if (!((*i)->GetSpellInfo()->AttributesEx5 & SPELL_ATTR5_SPECIAL_ITEM_CLASS_CHECK) && ((*i)->GetSpellInfo()->EquippedItemSubClassMask == 0)) - AddPct(DoneTotalMod, (*i)->GetAmount()); - else if (ToPlayer() && ToPlayer()->HasItemFitToSpellRequirements((*i)->GetSpellInfo())) - AddPct(DoneTotalMod, (*i)->GetAmount()); - } + if ((*i)->GetMiscValue() & spellProto->GetSchoolMask()) + { + if ((*i)->GetSpellInfo()->EquippedItemClass == -1) + AddPct(DoneTotalMod, (*i)->GetAmount()); + else if (!((*i)->GetSpellInfo()->AttributesEx5 & SPELL_ATTR5_SPECIAL_ITEM_CLASS_CHECK) && ((*i)->GetSpellInfo()->EquippedItemSubClassMask == 0)) + AddPct(DoneTotalMod, (*i)->GetAmount()); + else if (ToPlayer() && ToPlayer()->HasItemFitToSpellRequirements((*i)->GetSpellInfo())) + AddPct(DoneTotalMod, (*i)->GetAmount()); } } uint32 creatureTypeMask = victim->GetCreatureTypeMask(); - // Add flat bonus from spell damage versus - DoneTotal += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_FLAT_SPELL_DAMAGE_VERSUS, creatureTypeMask); + AuraEffectList const& mDamageDoneVersus = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS); for (AuraEffectList::const_iterator i = mDamageDoneVersus.begin(); i != mDamageDoneVersus.end(); ++i) if (creatureTypeMask & uint32((*i)->GetMiscValue())) @@ -8469,7 +8602,7 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin // done scripted mod (take it from owner) Unit const* owner = GetOwner() ? GetOwner() : this; - AuraEffectList const& mOverrideClassScript= owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); + AuraEffectList const& mOverrideClassScript = owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); for (AuraEffectList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i) { if (!(*i)->IsAffectingSpell(spellProto)) @@ -8531,18 +8664,6 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin AddPct(DoneTotalMod, (*i)->GetAmount()); break; } - case 4418: // Increased Shock Damage - case 4554: // Increased Lightning Damage - case 4555: // Improved Moonfire - case 5142: // Increased Lightning Damage - case 5147: // Improved Consecration / Libram of Resurgence - case 5148: // Idol of the Shooting Star - case 6008: // Increased Lightning Damage - case 8627: // Totem of Hex - { - DoneTotal += (*i)->GetAmount(); - break; - } } } @@ -8595,81 +8716,26 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin break; } } - // Drain Soul - increased damage for targets under 25 % HP - if (spellProto->SpellFamilyFlags[0] & 0x00004000) - if (HasAura(100001)) - DoneTotalMod *= 2; + // Shadow Bite (30% increase from each dot) if (spellProto->SpellFamilyFlags[1] & 0x00400000 && IsPet()) if (uint8 count = victim->GetDoTsByCaster(GetOwnerGUID())) AddPct(DoneTotalMod, 30 * count); + + // Drain Soul - increased damage for targets under 25 % HP + if (spellProto->SpellFamilyFlags[0] & 0x00004000) + if (HasAura(100001)) + DoneTotalMod *= 2; break; case SPELLFAMILY_DEATHKNIGHT: // Sigil of the Vengeful Heart if (spellProto->SpellFamilyFlags[0] & 0x2000) if (AuraEffect* aurEff = GetAuraEffect(64962, EFFECT_1)) - DoneTotal += aurEff->GetAmount(); + DoneTotalMod += aurEff->GetAmount(); break; } - // Done fixed damage bonus auras - int32 DoneAdvertisedBenefit = SpellBaseDamageBonusDone(spellProto->GetSchoolMask()); - // Pets just add their bonus damage to their spell damage - // note that their spell damage is just gain of their own auras - if (HasUnitTypeMask(UNIT_MASK_GUARDIAN)) - DoneAdvertisedBenefit += ((Guardian*)this)->GetBonusDamage(); - - // Check for table values - float coeff = 0; - SpellBonusEntry const* bonus = sSpellMgr->GetSpellBonusData(spellProto->Id); - if (bonus) - { - if (damagetype == DOT) - { - coeff = bonus->dot_damage; - if (bonus->ap_dot_bonus > 0) - { - WeaponAttackType attType = (spellProto->IsRangedWeaponSpell() && spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK; - float APbonus = float(victim->GetTotalAuraModifier(attType == BASE_ATTACK ? SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS : SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS)); - APbonus += GetTotalAttackPowerValue(attType); - DoneTotal += int32(bonus->ap_dot_bonus * stack * ApCoeffMod * APbonus); - } - } - else - { - coeff = bonus->direct_damage; - if (bonus->ap_bonus > 0) - { - WeaponAttackType attType = (spellProto->IsRangedWeaponSpell() && spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK; - float APbonus = float(victim->GetTotalAuraModifier(attType == BASE_ATTACK ? SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS : SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS)); - APbonus += GetTotalAttackPowerValue(attType); - DoneTotal += int32(bonus->ap_bonus * stack * ApCoeffMod * APbonus); - } - } - } - // Default calculation - if (DoneAdvertisedBenefit) - { - if (!bonus || coeff < 0) - coeff = CalculateDefaultCoefficient(spellProto, damagetype) * int32(stack); - - float factorMod = CalculateLevelPenalty(spellProto) * stack; - - if (Player* modOwner = GetSpellModOwner()) - { - coeff *= 100.0f; - modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_BONUS_MULTIPLIER, coeff); - coeff /= 100.0f; - } - DoneTotal += int32(DoneAdvertisedBenefit * coeff * factorMod); - } - - float tmpDamage = (int32(pdamage) + DoneTotal) * DoneTotalMod; - // apply spellmod to Done damage (flat and pct) - if (Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, tmpDamage); - - return uint32(std::max(tmpDamage, 0.0f)); + return DoneTotalMod; } uint32 Unit::SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype, uint32 stack) const @@ -8699,11 +8765,7 @@ uint32 Unit::SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, ui // Cheat Death case 2109: if ((*i)->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) - { - if (GetTypeId() != TYPEID_PLAYER) - continue; AddPct(TakenTotalMod, (*i)->GetAmount()); - } break; } } @@ -8825,16 +8887,21 @@ int32 Unit::SpellBaseDamageBonusTaken(SpellSchoolMask schoolMask) const return TakenAdvertisedBenefit; } -bool Unit::isSpellCrit(Unit* victim, SpellInfo const* spellProto, SpellSchoolMask schoolMask, WeaponAttackType attackType) const +bool Unit::IsSpellCrit(Unit* victim, SpellInfo const* spellProto, SpellSchoolMask schoolMask, WeaponAttackType attackType) const +{ + return roll_chance_f(GetUnitSpellCriticalChance(victim, spellProto, schoolMask, attackType)); +} + +float Unit::GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto, SpellSchoolMask schoolMask, WeaponAttackType attackType) const { //! Mobs can't crit with spells. Player Totems can //! Fire Elemental (from totem) can too - but this part is a hack and needs more research - if (IS_CREATURE_GUID(GetGUID()) && !(IsTotem() && IS_PLAYER_GUID(GetOwnerGUID())) && GetEntry() != 15438) - return false; + if (IS_CRE_OR_VEH_GUID(GetGUID()) && !(IsTotem() && IS_PLAYER_GUID(GetOwnerGUID())) && GetEntry() != 15438) + return 0.0f; // not critting spell if ((spellProto->AttributesEx2 & SPELL_ATTR2_CANT_CRIT)) - return false; + return 0.0f; float crit_chance = 0.0f; switch (spellProto->DmgClass) @@ -8850,7 +8917,7 @@ bool Unit::isSpellCrit(Unit* victim, SpellInfo const* spellProto, SpellSchoolMas case 71646: // Item - Bauble of True Blood 25m break; default: - return false; + return 0.0f; } // Do not add a break here, case fallthrough is intentional! Adding a break will make above spells unable to crit. case SPELL_DAMAGE_CLASS_MAGIC: @@ -8949,7 +9016,7 @@ bool Unit::isSpellCrit(Unit* victim, SpellInfo const* spellProto, SpellSchoolMas else if (spellProto->GetCategory() == 19) { if (victim->GetCreatureTypeMask() & CREATURE_TYPEMASK_DEMON_OR_UNDEAD) - return true; + return 100.0f; break; } break; @@ -8959,7 +9026,7 @@ bool Unit::isSpellCrit(Unit* victim, SpellInfo const* spellProto, SpellSchoolMas { if (victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_SHAMAN, 0x10000000, 0, 0, GetGUID())) if (victim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE) > -100) - return true; + return 100.0f; break; } break; @@ -8997,7 +9064,7 @@ bool Unit::isSpellCrit(Unit* victim, SpellInfo const* spellProto, SpellSchoolMas break; } default: - return false; + return 0.0f; } // percent done // only players use intelligence for critical chance computations @@ -9009,10 +9076,7 @@ bool Unit::isSpellCrit(Unit* victim, SpellInfo const* spellProto, SpellSchoolMas if ((*i)->GetCasterGUID() == GetGUID() && (*i)->IsAffectingSpell(spellProto)) crit_chance += (*i)->GetAmount(); - crit_chance = crit_chance > 0.0f ? crit_chance : 0.0f; - if (roll_chance_f(crit_chance)) - return true; - return false; + return crit_chance > 0.0f ? crit_chance : 0.0f; } uint32 Unit::SpellCriticalDamageBonus(SpellInfo const* spellProto, uint32 damage, Unit* /*victim*/) @@ -9075,14 +9139,8 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui if (spellProto->SpellFamilyName == SPELLFAMILY_POTION) return healamount; - float DoneTotalMod = 1.0f; int32 DoneTotal = 0; - // Healing done percent - AuraEffectList const& mHealingDonePct = GetAuraEffectsByType(SPELL_AURA_MOD_HEALING_DONE_PERCENT); - for (AuraEffectList::const_iterator i = mHealingDonePct.begin(); i != mHealingDonePct.end(); ++i) - AddPct(DoneTotalMod, (*i)->GetAmount()); - // done scripted mod (take it from owner) Unit const* owner = GetOwner() ? GetOwner() : this; AuraEffectList const& mOverrideClassScript= owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); @@ -9101,7 +9159,7 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui case 6935: case 6918: if (victim->HealthBelowPct(50)) - AddPct(DoneTotalMod, (*i)->GetAmount()); + AddPct(DoneTotal, (*i)->GetAmount()); break; case 8477: // Nourish Heal Boost { @@ -9119,7 +9177,7 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui continue; modPercent += stepPercent * aura->GetStackAmount(); } - AddPct(DoneTotalMod, modPercent); + AddPct(DoneTotal, modPercent); break; } default: @@ -9190,8 +9248,8 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui DoneTotal = 0; } - // use float as more appropriate for negative values and percent applying - float heal = float(int32(healamount) + DoneTotal) * DoneTotalMod; + // Done Percentage for DOT is already calculated, no need to do it again. The percentage mod is applied in Aura::HandleAuraSpecificMods. + float heal = float(int32(healamount) + DoneTotal) * (damagetype == DOT ? 1.0f : SpellHealingPctDone(victim, spellProto)); // apply spellmod to Done amount if (Player* modOwner = GetSpellModOwner()) modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, heal); @@ -9199,6 +9257,78 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui return uint32(std::max(heal, 0.0f)); } +float Unit::SpellHealingPctDone(Unit* victim, SpellInfo const* spellProto) const +{ + // For totems pct done mods are calculated when its calculation is run on the player in SpellHealingBonusDone. + if (GetTypeId() == TYPEID_UNIT && IsTotem()) + return 1.0f; + + // No bonus healing for potion spells + if (spellProto->SpellFamilyName == SPELLFAMILY_POTION) + return 1.0f; + + float DoneTotalMod = 1.0f; + + // Healing done percent + AuraEffectList const& mHealingDonePct = GetAuraEffectsByType(SPELL_AURA_MOD_HEALING_DONE_PERCENT); + for (AuraEffectList::const_iterator i = mHealingDonePct.begin(); i != mHealingDonePct.end(); ++i) + AddPct(DoneTotalMod, (*i)->GetAmount()); + + // done scripted mod (take it from owner) + Unit const* owner = GetOwner() ? GetOwner() : this; + AuraEffectList const& mOverrideClassScript= owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); + for (AuraEffectList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i) + { + if (!(*i)->IsAffectingSpell(spellProto)) + continue; + + switch ((*i)->GetMiscValue()) + { + case 21: // Test of Faith + case 6935: + case 6918: + if (victim->HealthBelowPct(50)) + AddPct(DoneTotalMod, (*i)->GetAmount()); + break; + case 7798: // Glyph of Regrowth + { + if (victim->GetAuraEffect(SPELL_AURA_PERIODIC_HEAL, SPELLFAMILY_DRUID, 0x40, 0, 0)) + AddPct(DoneTotalMod, (*i)->GetAmount()); + break; + } + case 8477: // Nourish Heal Boost + { + int32 stepPercent = (*i)->GetAmount(); + int32 modPercent = 0; + AuraApplicationMap const& victimAuras = victim->GetAppliedAuras(); + for (AuraApplicationMap::const_iterator itr = victimAuras.begin(); itr != victimAuras.end(); ++itr) + { + Aura const* aura = itr->second->GetBase(); + if (aura->GetCasterGUID() != GetGUID()) + continue; + SpellInfo const* m_spell = aura->GetSpellInfo(); + if (m_spell->SpellFamilyName != SPELLFAMILY_DRUID || + !(m_spell->SpellFamilyFlags[1] & 0x00000010 || m_spell->SpellFamilyFlags[0] & 0x50)) + continue; + modPercent += stepPercent * aura->GetStackAmount(); + } + AddPct(DoneTotalMod, modPercent); + break; + } + case 7871: // Glyph of Lesser Healing Wave + { + if (victim->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_SHAMAN, 0, 0x00000400, 0, GetGUID())) + AddPct(DoneTotalMod, (*i)->GetAmount()); + break; + } + default: + break; + } + } + + return DoneTotalMod; +} + uint32 Unit::SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, uint32 stack) const { float TakenTotalMod = 1.0f; @@ -9542,7 +9672,7 @@ uint32 Unit::MeleeDamageBonusDone(Unit* victim, uint32 pdamage, WeaponAttackType // Some spells don't benefit from pct done mods if (spellProto) - if (!(spellProto->AttributesEx6 & SPELL_ATTR6_NO_DONE_PCT_DAMAGE_MODS) && !spellProto->IsRankOf(sSpellMgr->GetSpellInfo(12162))) + if (!(spellProto->AttributesEx6 & SPELL_ATTR6_NO_DONE_PCT_DAMAGE_MODS)) { AuraEffectList const& mModDamagePercentDone = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); for (AuraEffectList::const_iterator i = mModDamagePercentDone.begin(); i != mModDamagePercentDone.end(); ++i) @@ -9658,10 +9788,11 @@ uint32 Unit::MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage, WeaponAttackT case 2109: if ((*i)->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) { - if (GetTypeId() != TYPEID_PLAYER) - continue; - float mod = ToPlayer()->GetRatingBonusValue(CR_RESILIENCE_PLAYER_DAMAGE_TAKEN) * (-8.0f); - AddPct(TakenTotalMod, std::max(mod, float((*i)->GetAmount()))); + if (Player* player = ToPlayer()) + { + float mod = player->GetRatingBonusValue(CR_RESILIENCE_PLAYER_DAMAGE_TAKEN) * (-8.0f); + AddPct(TakenTotalMod, std::max(mod, float((*i)->GetAmount()))); + } } break; } @@ -11101,19 +11232,24 @@ int32 Unit::ModSpellDuration(SpellInfo const* spellProto, Unit const* target, in return std::max(duration, 0); } -void Unit::ModSpellCastTime(SpellInfo const* spellProto, int32 & castTime, Spell* spell) +void Unit::ModSpellCastTime(SpellInfo const* spellInfo, int32 & castTime, Spell* spell) { - if (!spellProto || castTime < 0) + if (!spellInfo || castTime < 0) + return; + + if (spellInfo->IsChanneled() && !(spellInfo->AttributesEx5 & SPELL_ATTR5_HASTE_AFFECT_DURATION)) return; + // called from caster if (Player* modOwner = GetSpellModOwner()) - modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CASTING_TIME, castTime, spell); + modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CASTING_TIME, castTime, spell); - if (!(spellProto->Attributes & (SPELL_ATTR0_ABILITY|SPELL_ATTR0_TRADESPELL)) && ((GetTypeId() == TYPEID_PLAYER && spellProto->SpellFamilyName) || GetTypeId() == TYPEID_UNIT)) + if (!((spellInfo->Attributes & (SPELL_ATTR0_ABILITY | SPELL_ATTR0_TRADESPELL)) || (spellInfo->AttributesEx3 & SPELL_ATTR3_NO_DONE_BONUS)) && + ((GetTypeId() == TYPEID_PLAYER && spellInfo->SpellFamilyName) || GetTypeId() == TYPEID_UNIT)) castTime = int32(float(castTime) * GetFloatValue(UNIT_MOD_CAST_SPEED)); - else if (spellProto->Attributes & SPELL_ATTR0_REQ_AMMO && !(spellProto->AttributesEx2 & SPELL_ATTR2_AUTOREPEAT_FLAG)) + else if (spellInfo->Attributes & SPELL_ATTR0_REQ_AMMO && !(spellInfo->AttributesEx2 & SPELL_ATTR2_AUTOREPEAT_FLAG)) castTime = int32(float(castTime) * m_modAttackSpeedPct[RANGED_ATTACK]); - else if (spellProto->SpellVisual[0] == 3881 && HasAura(67556)) // cooking with Chef Hat. + else if (spellInfo->SpellVisual[0] == 3881 && HasAura(67556)) // cooking with Chef Hat. castTime = 500; } @@ -11815,12 +11951,7 @@ void Unit::CleanupsBeforeDelete(bool finalCleanup) { CleanupBeforeRemoveFromMap(finalCleanup); - if (GetTransport()) - { - GetTransport()->RemovePassenger(this); - SetTransport(NULL); - m_movementInfo.transport.Reset(); - } + WorldObject::CleanupsBeforeDelete(finalCleanup); } void Unit::UpdateCharmAI() @@ -15690,12 +15821,14 @@ bool Unit::UpdatePosition(float x, float y, float z, float orientation, bool tel bool turn = (GetOrientation() != orientation); bool relocated = (teleport || GetPositionX() != x || GetPositionY() != y || GetPositionZ() != z); + // TODO: Check if orientation transport offset changed instead of only global orientation if (turn) RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TURNING); if (relocated) { - RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MOVE); + if (!GetVehicle()) + RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MOVE); // move and update visible state if need if (GetTypeId() == TYPEID_PLAYER) @@ -16450,3 +16583,73 @@ void Unit::BuildCooldownPacket(WorldPacket& data, uint8 flags, PacketCooldowns c data << uint32(itr->second); } } + +int32 Unit::GetHighestExclusiveSameEffectSpellGroupValue(AuraEffect const* aurEff, AuraType auraType, bool checkMiscValue /*= false*/, int32 miscValue /*= 0*/) const +{ + int32 val = 0; + SpellSpellGroupMapBounds spellGroup = sSpellMgr->GetSpellSpellGroupMapBounds(aurEff->GetSpellInfo()->GetFirstRankSpell()->Id); + for (SpellSpellGroupMap::const_iterator itr = spellGroup.first; itr != spellGroup.second ; ++itr) + { + if (sSpellMgr->GetSpellGroupStackRule(itr->second) == SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT) + { + AuraEffectList const& auraEffList = GetAuraEffectsByType(auraType); + for (AuraEffectList::const_iterator auraItr = auraEffList.begin(); auraItr != auraEffList.end(); ++auraItr) + { + if (aurEff != (*auraItr) && (!checkMiscValue || (*auraItr)->GetMiscValue() == miscValue) && + sSpellMgr->IsSpellMemberOfSpellGroup((*auraItr)->GetSpellInfo()->Id, itr->second)) + { + // absolute value only + if (abs(val) < abs((*auraItr)->GetAmount())) + val = (*auraItr)->GetAmount(); + } + } + } + } + return val; +} + +bool Unit::IsHighestExclusiveAura(Aura const* aura, bool removeOtherAuraApplications /*= false*/) +{ + for (uint32 i = 0 ; i < MAX_SPELL_EFFECTS; ++i) + { + if (AuraEffect const* aurEff = aura->GetEffect(i)) + { + AuraType const auraType = AuraType(aura->GetSpellInfo()->Effects[i].ApplyAuraName); + AuraEffectList const& auras = GetAuraEffectsByType(auraType); + for (Unit::AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end();) + { + AuraEffect const* existingAurEff = (*itr); + ++itr; + + if (sSpellMgr->CheckSpellGroupStackRules(aura->GetSpellInfo(), existingAurEff->GetSpellInfo()) + == SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST) + { + int32 diff = abs(aurEff->GetAmount()) - abs(existingAurEff->GetAmount()); + if (!diff) + diff = int32(aura->GetEffectMask()) - int32(existingAurEff->GetBase()->GetEffectMask()); + + if (diff > 0) + { + Aura const* base = existingAurEff->GetBase(); + // no removing of area auras from the original owner, as that completely cancels them + if (removeOtherAuraApplications && (!base->IsArea() || base->GetOwner() != this)) + { + if (AuraApplication* aurApp = existingAurEff->GetBase()->GetApplicationOfTarget(GetGUID())) + { + bool hasMoreThanOneEffect = base->HasMoreThanOneEffectForType(auraType); + uint32 removedAuras = m_removedAurasCount; + RemoveAura(aurApp); + if (hasMoreThanOneEffect || m_removedAurasCount > removedAuras + 1) + itr = auras.begin(); + } + } + } + else if (diff < 0) + return false; + } + } + } + } + + return true; +} diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 970c5ee30fc..eb0882e3b64 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1306,7 +1306,7 @@ class Unit : public WorldObject void RemoveFromWorld(); void CleanupBeforeRemoveFromMap(bool finalCleanup); - void CleanupsBeforeDelete(bool finalCleanup = true); // used in ~Creature/~Player (or before mass creature delete to remove cross-references to already deleted units) + void CleanupsBeforeDelete(bool finalCleanup = true) override; // used in ~Creature/~Player (or before mass creature delete to remove cross-references to already deleted units) DiminishingLevels GetDiminishing(DiminishingGroup group); void IncrDiminishing(DiminishingGroup group); @@ -1983,13 +1983,15 @@ class Unit : public WorldObject Unit* GetMagicHitRedirectTarget(Unit* victim, SpellInfo const* spellInfo); Unit* GetMeleeHitRedirectTarget(Unit* victim, SpellInfo const* spellInfo = NULL); - int32 SpellBaseDamageBonusDone(SpellSchoolMask schoolMask) const; - int32 SpellBaseDamageBonusTaken(SpellSchoolMask schoolMask) const; + int32 SpellBaseDamageBonusDone(SpellSchoolMask schoolMask) const; + int32 SpellBaseDamageBonusTaken(SpellSchoolMask schoolMask) const; uint32 SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype, uint32 stack = 1) const; + float SpellDamagePctDone(Unit* victim, SpellInfo const* spellProto, DamageEffectType damagetype) const; uint32 SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype, uint32 stack = 1) const; - int32 SpellBaseHealingBonusDone(SpellSchoolMask schoolMask) const; - int32 SpellBaseHealingBonusTaken(SpellSchoolMask schoolMask) const; + int32 SpellBaseHealingBonusDone(SpellSchoolMask schoolMask) const; + int32 SpellBaseHealingBonusTaken(SpellSchoolMask schoolMask) const; uint32 SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, uint32 stack = 1) const; + float SpellHealingPctDone(Unit* victim, SpellInfo const* spellProto) const; uint32 SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, uint32 stack = 1) const; uint32 MeleeDamageBonusDone(Unit* pVictim, uint32 damage, WeaponAttackType attType, SpellInfo const* spellProto = NULL); @@ -1997,7 +1999,8 @@ class Unit : public WorldObject bool isSpellBlocked(Unit* victim, SpellInfo const* spellProto, WeaponAttackType attackType = BASE_ATTACK); bool isBlockCritical(); - bool isSpellCrit(Unit* victim, SpellInfo const* spellProto, SpellSchoolMask schoolMask, WeaponAttackType attackType = BASE_ATTACK) const; + bool IsSpellCrit(Unit* victim, SpellInfo const* spellProto, SpellSchoolMask schoolMask, WeaponAttackType attackType = BASE_ATTACK) const; + float GetUnitSpellCriticalChance(Unit* victim, SpellInfo const* spellProto, SpellSchoolMask schoolMask, WeaponAttackType attackType = BASE_ATTACK) const; uint32 SpellCriticalDamageBonus(SpellInfo const* spellProto, uint32 damage, Unit* victim); uint32 SpellCriticalHealingBonus(SpellInfo const* spellProto, uint32 damage, Unit* victim); @@ -2161,6 +2164,9 @@ class Unit : public WorldObject time_t GetLastDamagedTime() const { return _lastDamagedTime; } void SetLastDamagedTime(time_t val) { _lastDamagedTime = val; } + int32 GetHighestExclusiveSameEffectSpellGroupValue(AuraEffect const* aurEff, AuraType auraType, bool checkMiscValue = false, int32 miscValue = 0) const; + bool IsHighestExclusiveAura(Aura const* aura, bool removeOtherAuraApplications = false); + protected: explicit Unit (bool isWorldObject); diff --git a/src/server/game/Entities/Vehicle/Vehicle.cpp b/src/server/game/Entities/Vehicle/Vehicle.cpp index 930c4721f62..1e7779065d2 100644 --- a/src/server/game/Entities/Vehicle/Vehicle.cpp +++ b/src/server/game/Entities/Vehicle/Vehicle.cpp @@ -77,8 +77,12 @@ Vehicle::~Vehicle() void Vehicle::Install() { if (_me->GetTypeId() == TYPEID_UNIT) + { if (PowerDisplayEntry const* powerDisplay = sPowerDisplayStore.LookupEntry(_vehicleInfo->m_powerDisplayId)) _me->setPowerType(Powers(powerDisplay->PowerType)); + else if (_me->getClass() == CLASS_ROGUE) + _me->setPowerType(POWER_ENERGY); + } _status = STATUS_INSTALLED; if (GetBase()->GetTypeId() == TYPEID_UNIT) @@ -773,6 +777,8 @@ bool VehicleJoinEvent::Execute(uint64, uint32) Passenger->InterruptNonMeleeSpells(false); Passenger->RemoveAurasByType(SPELL_AURA_MOUNTED); + VehicleSeatEntry const* veSeat = Seat->second.SeatInfo; + Player* player = Passenger->ToPlayer(); if (player) { @@ -783,13 +789,13 @@ bool VehicleJoinEvent::Execute(uint64, uint32) player->StopCastingCharm(); player->StopCastingBindSight(); player->SendOnCancelExpectedVehicleRideAura(); - player->UnsummonPetTemporaryIfAny(); + if (!(veSeat->m_flagsB & VEHICLE_SEAT_FLAG_B_KEEP_PET)) + player->UnsummonPetTemporaryIfAny(); } if (Seat->second.SeatInfo->m_flags & VEHICLE_SEAT_FLAG_PASSENGER_NOT_SELECTABLE) Passenger->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - VehicleSeatEntry const* veSeat = Seat->second.SeatInfo; Passenger->m_movementInfo.transport.pos.Relocate(veSeat->m_attachmentOffsetX, veSeat->m_attachmentOffsetY, veSeat->m_attachmentOffsetZ); Passenger->m_movementInfo.transport.time = 0; Passenger->m_movementInfo.transport.seat = Seat->first; diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index c095403f261..fae3683a140 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -2868,32 +2868,32 @@ void ObjectMgr::LoadVehicleTemplateAccessories() { Field* fields = result->Fetch(); - uint32 uiEntry = fields[0].GetUInt32(); - uint32 uiAccessory = fields[1].GetUInt32(); - int8 uiSeat = int8(fields[2].GetInt8()); - bool bMinion = fields[3].GetBool(); - uint8 uiSummonType = fields[4].GetUInt8(); - uint32 uiSummonTimer= fields[5].GetUInt32(); + uint32 entry = fields[0].GetUInt32(); + uint32 accessory = fields[1].GetUInt32(); + int8 seatId = fields[2].GetInt8(); + bool isMinion = fields[3].GetBool(); + uint8 summonType = fields[4].GetUInt8(); + uint32 summonTimer = fields[5].GetUInt32(); - if (!sObjectMgr->GetCreatureTemplate(uiEntry)) + if (!sObjectMgr->GetCreatureTemplate(entry)) { - TC_LOG_ERROR("sql.sql", "Table `vehicle_template_accessory`: creature template entry %u does not exist.", uiEntry); + TC_LOG_ERROR("sql.sql", "Table `vehicle_template_accessory`: creature template entry %u does not exist.", entry); continue; } - if (!sObjectMgr->GetCreatureTemplate(uiAccessory)) + if (!sObjectMgr->GetCreatureTemplate(accessory)) { - TC_LOG_ERROR("sql.sql", "Table `vehicle_template_accessory`: Accessory %u does not exist.", uiAccessory); + TC_LOG_ERROR("sql.sql", "Table `vehicle_template_accessory`: Accessory %u does not exist.", accessory); continue; } - if (_spellClickInfoStore.find(uiEntry) == _spellClickInfoStore.end()) + if (_spellClickInfoStore.find(entry) == _spellClickInfoStore.end()) { - TC_LOG_ERROR("sql.sql", "Table `vehicle_template_accessory`: creature template entry %u has no data in npc_spellclick_spells", uiEntry); + TC_LOG_ERROR("sql.sql", "Table `vehicle_template_accessory`: creature template entry %u has no data in npc_spellclick_spells", entry); continue; } - _vehicleTemplateAccessoryStore[uiEntry].push_back(VehicleAccessory(uiAccessory, uiSeat, bMinion, uiSummonType, uiSummonTimer)); + _vehicleTemplateAccessoryStore[entry].push_back(VehicleAccessory(accessory, seatId, isMinion, summonType, summonTimer)); ++count; } diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index 9329f441156..62a770f06a8 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -1333,8 +1333,8 @@ class ObjectMgr time_t ret = 0; for (HotfixData::const_iterator itr = _hotfixData.begin(); itr != _hotfixData.end(); ++itr) if (itr->Entry == entry && itr->Type == type) - if (itr->Timestamp > ret) - ret = itr->Timestamp; + if (time_t(itr->Timestamp) > ret) + ret = time_t(itr->Timestamp); return ret ? ret : time(NULL); } diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.cpp b/src/server/game/Grids/Notifiers/GridNotifiers.cpp index 76f81a15e50..8040728133f 100644 --- a/src/server/game/Grids/Notifiers/GridNotifiers.cpp +++ b/src/server/game/Grids/Notifiers/GridNotifiers.cpp @@ -35,7 +35,8 @@ void VisibleNotifier::SendToSelf() // at this moment i_clientGUIDs have guids that not iterate at grid level checks // but exist one case when this possible and object not out of range: transports if (Transport* transport = i_player.GetTransport()) - for (std::set<WorldObject*>::const_iterator itr = transport->GetPassengers().begin(); itr != transport->GetPassengers().end();++itr) + { + for (Transport::PassengerSet::const_iterator itr = transport->GetPassengers().begin(); itr != transport->GetPassengers().end(); ++itr) { if (vis_guids.find((*itr)->GetGUID()) != vis_guids.end()) { @@ -54,11 +55,15 @@ void VisibleNotifier::SendToSelf() case TYPEID_UNIT: i_player.UpdateVisibilityOf((*itr)->ToCreature(), i_data, i_visibleNow); break; + case TYPEID_DYNAMICOBJECT: + i_player.UpdateVisibilityOf((*itr)->ToDynObject(), i_data, i_visibleNow); + break; default: break; } } } + } for (Player::ClientGUIDs::const_iterator it = vis_guids.begin();it != vis_guids.end(); ++it) { diff --git a/src/server/game/Handlers/CalendarHandler.cpp b/src/server/game/Handlers/CalendarHandler.cpp index 2f1a726f9cf..0461d7290d1 100644 --- a/src/server/game/Handlers/CalendarHandler.cpp +++ b/src/server/game/Handlers/CalendarHandler.cpp @@ -239,20 +239,28 @@ void WorldSession::HandleCalendarAddEvent(WorldPacket& recvData) recvData.ReadPackedTime(unkPackedTime); recvData >> flags; - CalendarEvent calendarEvent(sCalendarMgr->GetFreeEventId(), guid, 0, CalendarEventType(type), dungeonId, + // prevent events in the past + // To Do: properly handle timezones and remove the "- time_t(86400L)" hack + if (time_t(eventPackedTime) < (time(NULL) - time_t(86400L))) + { + recvData.rfinish(); + return; + } + + CalendarEvent* calendarEvent = new CalendarEvent(sCalendarMgr->GetFreeEventId(), guid, 0, CalendarEventType(type), dungeonId, time_t(eventPackedTime), flags, time_t(unkPackedTime), title, description); - if (calendarEvent.IsGuildEvent() || calendarEvent.IsGuildAnnouncement()) + if (calendarEvent->IsGuildEvent() || calendarEvent->IsGuildAnnouncement()) if (Player* creator = ObjectAccessor::FindPlayer(guid)) - calendarEvent.SetGuildId(creator->GetGuildId()); + calendarEvent->SetGuildId(creator->GetGuildId()); - if (calendarEvent.IsGuildAnnouncement()) + if (calendarEvent->IsGuildAnnouncement()) { // 946684800 is 01/01/2000 00:00:00 - default response time - CalendarInvite invite(0, calendarEvent.GetEventId(), 0, guid, 946684800, CALENDAR_STATUS_NOT_SIGNED_UP, CALENDAR_RANK_PLAYER, ""); + CalendarInvite invite(0, calendarEvent->GetEventId(), 0, guid, 946684800, CALENDAR_STATUS_NOT_SIGNED_UP, CALENDAR_RANK_PLAYER, ""); // WARNING: By passing pointer to a local variable, the underlying method(s) must NOT perform any kind // of storage of the pointer as it will lead to memory corruption - sCalendarMgr->AddInvite(&calendarEvent, &invite); + sCalendarMgr->AddInvite(calendarEvent, &invite); } else { @@ -275,15 +283,15 @@ void WorldSession::HandleCalendarAddEvent(WorldPacket& recvData) recvData >> status >> rank; // 946684800 is 01/01/2000 00:00:00 - default response time - CalendarInvite* invite = new CalendarInvite(sCalendarMgr->GetFreeInviteId(), calendarEvent.GetEventId(), invitee, guid, 946684800, CalendarInviteStatus(status), CalendarModerationRank(rank), ""); - sCalendarMgr->AddInvite(&calendarEvent, invite, trans); + CalendarInvite* invite = new CalendarInvite(sCalendarMgr->GetFreeInviteId(), calendarEvent->GetEventId(), invitee, guid, 946684800, CalendarInviteStatus(status), CalendarModerationRank(rank), ""); + sCalendarMgr->AddInvite(calendarEvent, invite, trans); } if (inviteCount > 1) CharacterDatabase.CommitTransaction(trans); } - sCalendarMgr->AddEvent(new CalendarEvent(calendarEvent, calendarEvent.GetEventId()), CALENDAR_SENDTYPE_ADD); + sCalendarMgr->AddEvent(calendarEvent, CALENDAR_SENDTYPE_ADD); } void WorldSession::HandleCalendarUpdateEvent(WorldPacket& recvData) @@ -308,6 +316,14 @@ void WorldSession::HandleCalendarUpdateEvent(WorldPacket& recvData) recvData.ReadPackedTime(timeZoneTime); recvData >> flags; + // prevent events in the past + // To Do: properly handle timezones and remove the "- time_t(86400L)" hack + if (time_t(eventPackedTime) < (time(NULL) - time_t(86400L))) + { + recvData.rfinish(); + return; + } + TC_LOG_DEBUG("network", "CMSG_CALENDAR_UPDATE_EVENT [" UI64FMTD "] EventId [" UI64FMTD "], InviteId [" UI64FMTD "] Title %s, Description %s, type %u " "Repeatable %u, MaxInvites %u, Dungeon ID %d, Time %u " @@ -350,17 +366,25 @@ void WorldSession::HandleCalendarCopyEvent(WorldPacket& recvData) uint64 guid = _player->GetGUID(); uint64 eventId; uint64 inviteId; - uint32 time; + uint32 eventTime; recvData >> eventId >> inviteId; - recvData.ReadPackedTime(time); + recvData.ReadPackedTime(eventTime); TC_LOG_DEBUG("network", "CMSG_CALENDAR_COPY_EVENT [" UI64FMTD "], EventId [" UI64FMTD - "] inviteId [" UI64FMTD "] Time: %u", guid, eventId, inviteId, time); + "] inviteId [" UI64FMTD "] Time: %u", guid, eventId, inviteId, eventTime); + + // prevent events in the past + // To Do: properly handle timezones and remove the "- time_t(86400L)" hack + if (time_t(eventTime) < (time(NULL) - time_t(86400L))) + { + recvData.rfinish(); + return; + } if (CalendarEvent* oldEvent = sCalendarMgr->GetEvent(eventId)) { CalendarEvent* newEvent = new CalendarEvent(*oldEvent, sCalendarMgr->GetFreeEventId()); - newEvent->SetEventTime(time_t(time)); + newEvent->SetEventTime(time_t(eventTime)); sCalendarMgr->AddEvent(newEvent, CALENDAR_SENDTYPE_COPY); CalendarInviteStore invites = sCalendarMgr->GetEventInvites(eventId); diff --git a/src/server/game/Handlers/GroupHandler.cpp b/src/server/game/Handlers/GroupHandler.cpp index 7ef56ff94b4..8565da90f40 100644 --- a/src/server/game/Handlers/GroupHandler.cpp +++ b/src/server/game/Handlers/GroupHandler.cpp @@ -855,8 +855,6 @@ void WorldSession::HandleGroupAssistantLeaderOpcode(WorldPacket& recvData) recvData >> apply; group->SetGroupMemberFlag(guid, apply, MEMBER_FLAG_ASSISTANT); - - group->SendUpdate(); } void WorldSession::HandlePartyAssignmentOpcode(WorldPacket& recvData) diff --git a/src/server/game/Handlers/GuildHandler.cpp b/src/server/game/Handlers/GuildHandler.cpp index 5821cba77d6..d40f2102c77 100644 --- a/src/server/game/Handlers/GuildHandler.cpp +++ b/src/server/game/Handlers/GuildHandler.cpp @@ -578,7 +578,7 @@ void WorldSession::HandleGuildBankLogQuery(WorldPacket& recvPacket) uint32 tabId; recvPacket >> tabId; - TC_LOG_DEBUG("guild", "MSG_GUILD_BANK_LOG_QUERY [%s]: TabId: %u", GetPlayerInfo().c_str(), tabId); + TC_LOG_DEBUG("guild", "CMSG_GUILD_BANK_LOG_QUERY [%s]: TabId: %u", GetPlayerInfo().c_str(), tabId); if (Guild* guild = GetPlayer()->GetGuild()) guild->SendBankLog(this, tabId); @@ -589,7 +589,7 @@ void WorldSession::HandleQueryGuildBankTabText(WorldPacket &recvPacket) uint8 tabId; recvPacket >> tabId; - TC_LOG_DEBUG("guild", "MSG_QUERY_GUILD_BANK_TEXT [%s]: TabId: %u", GetPlayerInfo().c_str(), tabId); + TC_LOG_DEBUG("guild", "CMSG_GUILD_BANK_QUERY_TEXT [%s]: TabId: %u", GetPlayerInfo().c_str(), tabId); if (Guild* guild = GetPlayer()->GetGuild()) guild->SendBankTabText(this, tabId); diff --git a/src/server/game/Handlers/MailHandler.cpp b/src/server/game/Handlers/MailHandler.cpp index e65643e7ffe..536d6a7dc95 100644 --- a/src/server/game/Handlers/MailHandler.cpp +++ b/src/server/game/Handlers/MailHandler.cpp @@ -28,6 +28,7 @@ #include "DBCStores.h" #include "Item.h" #include "AccountMgr.h" +#include "BattlenetAccountMgr.h" #include "GuildMgr.h" bool WorldSession::CanOpenMailBox(uint64 guid) @@ -192,6 +193,7 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) uint8 mailsCount = 0; //do not allow to send to one player more than 100 mails uint8 receiverLevel = 0; uint32 receiverAccountId = 0; + uint32 receiverBnetAccountId = 0; if (receiver) { @@ -199,6 +201,7 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) mailsCount = receiver->GetMailSize(); receiverLevel = receiver->getLevel(); receiverAccountId = receiver->GetSession()->GetAccountId(); + receiverBnetAccountId = receiver->GetSession()->GetBattlenetAccountId(); } else { @@ -225,6 +228,7 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) } receiverAccountId = sObjectMgr->GetPlayerAccountIdByGUID(receiverGuid); + receiverBnetAccountId = Battlenet::AccountMgr::GetIdByGameAccount(receiverAccountId); } // do not allow to have more than 100 mails in mailbox.. mails count is in opcode uint8!!! - so max can be 255.. @@ -288,8 +292,11 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) if (item->IsBoundAccountWide() && item->IsSoulBound() && player->GetSession()->GetAccountId() != receiverAccountId) { - player->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_NOT_SAME_ACCOUNT); - return; + if (!item->IsBattlenetAccountBound() || !player->GetSession()->GetBattlenetAccountId() || player->GetSession()->GetBattlenetAccountId() != receiverBnetAccountId) + { + player->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_NOT_SAME_ACCOUNT); + return; + } } if (item->GetTemplate()->Flags & ITEM_PROTO_FLAG_CONJURED || item->GetUInt32Value(ITEM_FIELD_DURATION)) diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index 3b5f9e16637..7a66d747342 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -1231,7 +1231,7 @@ void WorldSession::HandleInspectOpcode(WorldPacket& recvData) { data << uint64(guild->GetGUID()); data << uint32(guild->GetLevel()); - data << uint64(0/*guild->GetXP()*/); + data << uint64(guild->GetExperience()); data << uint32(guild->GetMembersCount()); } SendPacket(&data); diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp index fa137d98272..dabe40e427e 100644 --- a/src/server/game/Handlers/MovementHandler.cpp +++ b/src/server/game/Handlers/MovementHandler.cpp @@ -31,6 +31,7 @@ #include "InstanceSaveMgr.h" #include "ObjectMgr.h" #include "MovementStructures.h" +#include "Vehicle.h" #define MOVEMENT_PACKET_TIME_DELAY 0 @@ -320,27 +321,15 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvPacket) if (!plrMover->GetTransport()) { if (Transport* transport = plrMover->GetMap()->GetTransport(movementInfo.transport.guid)) - { - plrMover->m_transport = transport; transport->AddPassenger(plrMover); - } } else if (plrMover->GetTransport()->GetGUID() != movementInfo.transport.guid) { - bool foundNewTransport = false; - plrMover->m_transport->RemovePassenger(plrMover); + plrMover->GetTransport()->RemovePassenger(plrMover); if (Transport* transport = plrMover->GetMap()->GetTransport(movementInfo.transport.guid)) - { - foundNewTransport = true; - plrMover->m_transport = transport; transport->AddPassenger(plrMover); - } - - if (!foundNewTransport) - { - plrMover->m_transport = NULL; + else movementInfo.ResetTransport(); - } } } @@ -352,11 +341,7 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvPacket) } } else if (plrMover && plrMover->GetTransport()) // if we were on a transport, leave - { plrMover->m_transport->RemovePassenger(plrMover); - plrMover->m_transport = NULL; - movementInfo.ResetTransport(); - } // fall damage generation (ignore in flight case that can be triggered also at lags in moment teleportation to another map). if (opcode == MSG_MOVE_FALL_LAND && plrMover && !plrMover->IsInFlight()) @@ -379,12 +364,20 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvPacket) movementInfo.guid = mover->GetGUID(); mover->m_movementInfo = movementInfo; - /*----------------------*/ - /* process position-change */ - // this is almost never true (not sure why it is sometimes, but it is), normally use mover->IsVehicle() - if (mover->GetVehicle()) + // Some vehicles allow the passenger to turn by himself + if (Vehicle* vehicle = mover->GetVehicle()) { - mover->SetOrientation(movementInfo.pos.GetOrientation()); + if (VehicleSeatEntry const* seat = vehicle->GetSeatForPassenger(mover)) + { + if (seat->m_flags & VEHICLE_SEAT_FLAG_ALLOW_TURNING) + { + if (movementInfo.pos.GetOrientation() != mover->GetOrientation()) + { + mover->SetOrientation(movementInfo.pos.GetOrientation()); + mover->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TURNING); + } + } + } return; } @@ -530,7 +523,7 @@ void WorldSession::HandleSetActiveMoverOpcode(WorldPacket& recvPacket) if (GetPlayer()->IsInWorld()) { if (_player->m_mover->GetGUID() != guid) - TC_LOG_ERROR("network", "HandleSetActiveMoverOpcode: incorrect mover guid: mover is " UI64FMTD " (%s - Entry: %u) and should be " UI64FMTD, uint64(guid), GetLogNameForGuid(guid), GUID_ENPART(guid), _player->m_mover->GetGUID()); + TC_LOG_DEBUG("network", "HandleSetActiveMoverOpcode: incorrect mover guid: mover is " UI64FMTD " (%s - Entry: %u) and should be " UI64FMTD, uint64(guid), GetLogNameForGuid(guid), GUID_ENPART(guid), _player->m_mover->GetGUID()); } } diff --git a/src/server/game/Handlers/NPCHandler.cpp b/src/server/game/Handlers/NPCHandler.cpp index 0a77a941b5f..58f7951bb9d 100644 --- a/src/server/game/Handlers/NPCHandler.cpp +++ b/src/server/game/Handlers/NPCHandler.cpp @@ -552,7 +552,7 @@ void WorldSession::SendStablePetCallback(PreparedQueryResult result, uint64 guid // not let move dead pet in slot if (pet && pet->IsAlive() && pet->getPetType() == HUNTER_PET) { - data << uint32(0); // 4.x unknown, some kind of order? + data << uint32(num); // 4.x unknown, some kind of order? data << uint32(pet->GetCharmInfo()->GetPetNumber()); data << uint32(pet->GetEntry()); data << uint32(pet->getLevel()); @@ -567,6 +567,7 @@ void WorldSession::SendStablePetCallback(PreparedQueryResult result, uint64 guid { Field* fields = result->Fetch(); + data << uint32(num); data << uint32(fields[1].GetUInt32()); // petnumber data << uint32(fields[2].GetUInt32()); // creature entry data << uint32(fields[3].GetUInt16()); // level diff --git a/src/server/game/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp index 301e9a7d2c8..39d18178a01 100644 --- a/src/server/game/Handlers/PetHandler.cpp +++ b/src/server/game/Handlers/PetHandler.cpp @@ -79,13 +79,13 @@ void WorldSession::HandlePetAction(WorldPacket& recvData) if (!pet) { - TC_LOG_ERROR("network", "HandlePetAction: Pet (GUID: %u) doesn't exist for player %s (GUID: %u)", uint32(GUID_LOPART(guid1)), GetPlayer()->GetName().c_str(), GUID_LOPART(GetPlayer()->GetGUID())); + TC_LOG_DEBUG("network", "HandlePetAction: Pet (GUID: %u) doesn't exist for player %s (GUID: %u)", uint32(GUID_LOPART(guid1)), GetPlayer()->GetName().c_str(), GUID_LOPART(GetPlayer()->GetGUID())); return; } if (pet != GetPlayer()->GetFirstControlled()) { - TC_LOG_ERROR("network", "HandlePetAction: Pet (GUID: %u) does not belong to player %s (GUID: %u)", uint32(GUID_LOPART(guid1)), GetPlayer()->GetName().c_str(), GUID_LOPART(GetPlayer()->GetGUID())); + TC_LOG_DEBUG("network", "HandlePetAction: Pet (GUID: %u) does not belong to player %s (GUID: %u)", uint32(GUID_LOPART(guid1)), GetPlayer()->GetName().c_str(), GUID_LOPART(GetPlayer()->GetGUID())); return; } @@ -149,7 +149,7 @@ void WorldSession::HandlePetActionHelper(Unit* pet, uint64 guid1, uint32 spellid CharmInfo* charmInfo = pet->GetCharmInfo(); if (!charmInfo) { - TC_LOG_ERROR("network", "WorldSession::HandlePetAction(petGuid: " UI64FMTD ", tagGuid: " UI64FMTD ", spellId: %u, flag: %u): object (GUID: %u Entry: %u TypeId: %u) is considered pet-like but doesn't have a charminfo!", + TC_LOG_DEBUG("network", "WorldSession::HandlePetAction(petGuid: " UI64FMTD ", tagGuid: " UI64FMTD ", spellId: %u, flag: %u): object (GUID: %u Entry: %u TypeId: %u) is considered pet-like but doesn't have a charminfo!", guid1, guid2, spellid, flag, pet->GetGUIDLow(), pet->GetEntry(), pet->GetTypeId()); return; } diff --git a/src/server/game/Handlers/TradeHandler.cpp b/src/server/game/Handlers/TradeHandler.cpp index fc6062773a1..862c6a6204e 100644 --- a/src/server/game/Handlers/TradeHandler.cpp +++ b/src/server/game/Handlers/TradeHandler.cpp @@ -30,40 +30,45 @@ #include "Language.h" #include "AccountMgr.h" -void WorldSession::SendTradeStatus(TradeStatus status) +void WorldSession::SendTradeStatus(TradeStatus status, int8 clearSlot) { WorldPacket data; + Player* trader = GetPlayer()->GetTrader(); + data.Initialize(SMSG_TRADE_STATUS, 1+4+4); - data.WriteBit(0); // unk bit, usually 0 + data.WriteBit(trader ? (trader->GetSession()->GetBattlenetAccountId() == GetBattlenetAccountId()) : 0); // IsSameBnetAccount, used for trading heirlooms and other battle.net bound items with your other accounts data.WriteBits(status, 5); switch (status) { case TRADE_STATUS_BEGIN_TRADE: - data.WriteBits(0, 8); // zero guid + data.WriteBits(0, 8); // Trader Guid data.FlushBits(); break; case TRADE_STATUS_OPEN_WINDOW: data.FlushBits(); - data << uint32(0); // unk + data << uint32(0); // Trade Id break; case TRADE_STATUS_CLOSE_WINDOW: - data.WriteBit(0); // unk + data.WriteBit(0); // Error bool (0 = Target, 1 = Self) data.FlushBits(); - data << uint32(0); // unk - data << uint32(0); // unk + data << uint32(0); // Error Item (Relevant item to the error) + data << uint32(0); // InventoryResult break; - case TRADE_STATUS_ONLY_CONJURED: - case TRADE_STATUS_NOT_ELIGIBLE: + case TRADE_STATUS_ONLY_CONJURED: // Not Implemented + case TRADE_STATUS_NOT_ELIGIBLE: + // Used when trading loot soulbound items with people that are not eligible (TRADE_STATUS_NOT_ELIGIBLE), + // and when trying to trade items with players in other realms when in a cross realm BG, you can only trade conjured goods with them (TRADE_STATUS_ONLY_CONJURED) data.FlushBits(); - data << uint8(0); // unk + data << int8(clearSlot); // Trade slot to clear, -1 = Clear the money amount break; case TRADE_STATUS_CURRENCY: // Not implemented case TRADE_STATUS_CURRENCY_NOT_TRADABLE: // Not implemented + // Blizzard never implemented these, you can only trade currency with the field9 & 1 in CurrencyTypes.DBC, and only two test currencies have that flag data.FlushBits(); - data << uint32(0); // unk - data << uint32(0); // unk + data << uint32(0); // Trading Currency Id + data << uint32(0); // Trading Currency Amount default: data.FlushBits(); break; @@ -828,6 +833,13 @@ void WorldSession::HandleSetTradeItemOpcode(WorldPacket& recvPacket) return; } + if (item->IsBindedNotWith(GetPlayer()->GetTrader())) + { + // The item is BOP tradeable but the trader wasn't eligible to get it. + SendTradeStatus(TRADE_STATUS_NOT_ELIGIBLE, tradeSlot); + return; + } + my_trade->SetItem(TradeSlots(tradeSlot), item); } diff --git a/src/server/game/Loot/LootMgr.h b/src/server/game/Loot/LootMgr.h index ed0f3b9717b..9be745e622d 100644 --- a/src/server/game/Loot/LootMgr.h +++ b/src/server/game/Loot/LootMgr.h @@ -86,7 +86,8 @@ enum LootType LOOT_MILLING = 8, LOOT_FISHINGHOLE = 20, // unsupported by client, sending LOOT_FISHING instead - LOOT_INSIGNIA = 21 // unsupported by client, sending LOOT_CORPSE instead + LOOT_INSIGNIA = 21, // unsupported by client, sending LOOT_CORPSE instead + LOOT_FISHING_JUNK = 22 // unsupported by client, sending LOOT_FISHING instead }; // type of Loot Item in Loot View diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 92467487525..a1ee67fe6e4 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -2506,15 +2506,9 @@ void Map::SendInitSelf(Player* player) // build other passengers at transport also (they always visible and marked as visible and will not send at visibility update at add to map if (Transport* transport = player->GetTransport()) - { - for (std::set<WorldObject*>::const_iterator itr = transport->GetPassengers().begin(); itr != transport->GetPassengers().end(); ++itr) - { + for (Transport::PassengerSet::const_iterator itr = transport->GetPassengers().begin(); itr != transport->GetPassengers().end(); ++itr) if (player != (*itr) && player->HaveAtClient(*itr)) - { (*itr)->BuildCreateUpdateBlockForPlayer(&data, player); - } - } - } WorldPacket packet; data.BuildPacket(&packet); diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index 97834d3e444..68a0687dc24 100644 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -889,7 +889,8 @@ enum TrinityStrings LANG_CHARACTER_DELETED_LIST_LINE_CHAT = 1026, LANG_SQLDRIVER_QUERY_LOGGING_ENABLED = 1027, LANG_SQLDRIVER_QUERY_LOGGING_DISABLED = 1028, - // Room for more level 4 1029-1099 not used + LANG_ACCOUNT_INVALID_BNET_NAME = 1029, + // Room for more level 4 1030-1099 not used // Level 3 (continue) LANG_ACCOUNT_SETADDON = 1100, @@ -1232,7 +1233,8 @@ enum TrinityStrings LANG_BAN_ACCOUNT_YOUBANNEDMESSAGE_WORLD = 11006, LANG_BAN_ACCOUNT_YOUPERMBANNEDMESSAGE_WORLD = 11007, - LANG_NPCINFO_INHABIT_TYPE = 11008 + LANG_NPCINFO_INHABIT_TYPE = 11008, + LANG_NPCINFO_FLAGS_EXTRA = 11009 // NOT RESERVED IDS 12000-1999999999 // `db_script_string` table index 2000000000-2000009999 (MIN_DB_SCRIPT_STRING_ID-MAX_DB_SCRIPT_STRING_ID) diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index cbcf509747b..fc87bf2cdab 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -41,7 +41,8 @@ enum LootModes LOOT_MODE_HARD_MODE_1 = 0x2, LOOT_MODE_HARD_MODE_2 = 0x4, LOOT_MODE_HARD_MODE_3 = 0x8, - LOOT_MODE_HARD_MODE_4 = 0x10 + LOOT_MODE_HARD_MODE_4 = 0x10, + LOOT_MODE_JUNK_FISH = 0x8000 }; enum Expansions @@ -552,7 +553,7 @@ enum SpellAttr7 SPELL_ATTR7_UNK13 = 0x00002000, // 13 Not set in 3.2.2a. SPELL_ATTR7_UNK14 = 0x00004000, // 14 Only 52150 (Raise Dead - Pet) spell. SPELL_ATTR7_UNK15 = 0x00008000, // 15 Exorcism. Usable on players? 100% crit chance on undead and demons? - SPELL_ATTR7_UNK16 = 0x00010000, // 16 Druid spells (29166, 54833, 64372, 68285). + SPELL_ATTR7_CAN_RESTORE_SECONDARY_POWER = 0x00010000, // 16 These spells can replenish a powertype, which is not the current powertype. SPELL_ATTR7_UNK17 = 0x00020000, // 17 Only 27965 (Suicide) spell. SPELL_ATTR7_HAS_CHARGE_EFFECT = 0x00040000, // 18 Only spells that have Charge among effects. SPELL_ATTR7_ZONE_TELEPORT = 0x00080000, // 19 Teleports to specific zones. diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp index a744915a25a..d996a7b633e 100644 --- a/src/server/game/Scripting/ScriptLoader.cpp +++ b/src/server/game/Scripting/ScriptLoader.cpp @@ -48,6 +48,7 @@ void AddSC_account_commandscript(); void AddSC_achievement_commandscript(); void AddSC_arena_commandscript(); void AddSC_ban_commandscript(); +void AddSC_battlenet_account_commandscript(); void AddSC_bf_commandscript(); void AddSC_cast_commandscript(); void AddSC_character_commandscript(); @@ -472,7 +473,6 @@ void AddSC_boss_xt002(); void AddSC_boss_kologarn(); void AddSC_boss_assembly_of_iron(); void AddSC_boss_general_vezax(); -void AddSC_ulduar_teleporter(); void AddSC_boss_mimiron(); void AddSC_boss_hodir(); void AddSC_boss_freya(); @@ -759,6 +759,7 @@ void AddCommandScripts() AddSC_achievement_commandscript(); AddSC_arena_commandscript(); AddSC_ban_commandscript(); + AddSC_battlenet_account_commandscript(); AddSC_bf_commandscript(); AddSC_cast_commandscript(); AddSC_character_commandscript(); @@ -1321,7 +1322,6 @@ void AddNorthrendScripts() AddSC_boss_general_vezax(); AddSC_boss_assembly_of_iron(); AddSC_boss_kologarn(); - AddSC_ulduar_teleporter(); AddSC_boss_mimiron(); AddSC_boss_hodir(); AddSC_boss_freya(); diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 4f682f83ae4..5d12537b6e4 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -563,7 +563,7 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER(MSG_CHANNEL_UPDATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); DEFINE_OPCODE_HANDLER(MSG_CORPSE_QUERY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCorpseQueryOpcode ); DEFINE_OPCODE_HANDLER(MSG_INSPECT_ARENA_TEAMS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleInspectArenaTeamsOpcode ); - DEFINE_OPCODE_HANDLER(MSG_LIST_STABLED_PETS, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleListStabledPetsOpcode ); + DEFINE_OPCODE_HANDLER(MSG_LIST_STABLED_PETS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleListStabledPetsOpcode ); DEFINE_OPCODE_HANDLER(MSG_MINIMAP_PING, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleMinimapPingOpcode ); DEFINE_OPCODE_HANDLER(MSG_MOVE_CHARM_TELEPORT_CHEAT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER(MSG_MOVE_FALL_LAND, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes ); diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index 201235b4a40..2ece2942a56 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -99,7 +99,7 @@ bool WorldSessionFilter::Process(WorldPacket* packet) } /// WorldSession constructor -WorldSession::WorldSession(uint32 id, WorldSocket* sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale, uint32 recruiter, bool isARecruiter): +WorldSession::WorldSession(uint32 id, uint32 battlenetAccountId, WorldSocket* sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale, uint32 recruiter, bool isARecruiter): m_muteTime(mute_time), m_timeOutTime(0), AntiDOS(this), @@ -108,6 +108,7 @@ WorldSession::WorldSession(uint32 id, WorldSocket* sock, AccountTypes sec, uint8 m_Socket(sock), _security(sec), _accountId(id), + _battlenetAccountId(battlenetAccountId), m_expansion(expansion), _warden(NULL), _logoutTime(0), @@ -1186,6 +1187,12 @@ void WorldSession::InvalidateRBACData() bool WorldSession::DosProtection::EvaluateOpcode(WorldPacket& p, time_t time) const { + uint32 maxPacketCounterAllowed = GetMaxPacketCounterAllowed(p.GetOpcode()); + + // Return true if there no limit for the opcode + if (!maxPacketCounterAllowed) + return true; + PacketCounter& packetCounter = _PacketThrottlingMap[p.GetOpcode()]; if (packetCounter.lastReceiveTime != time) { @@ -1193,31 +1200,14 @@ bool WorldSession::DosProtection::EvaluateOpcode(WorldPacket& p, time_t time) co packetCounter.amountCounter = 0; } - uint32 maxPacketCounterAllowed = GetMaxPacketCounterAllowed(p.GetOpcode()); - - bool dosTriggered = false; // Check if player is flooding some packets - if (++packetCounter.amountCounter > maxPacketCounterAllowed) - { - dosTriggered = true; - TC_LOG_WARN("network", "AntiDOS: Account %u, IP: %s, Ping: %u, Character: %s, flooding packet (opc: %s (0x%X), count: %u)", - Session->GetAccountId(), Session->GetRemoteAddress().c_str(), Session->GetLatency(), Session->GetPlayerName().c_str(), - opcodeTable[p.GetOpcode()]->Name, p.GetOpcode(), packetCounter.amountCounter); - } - - // Then check if player is sending packets not allowed - if (!IsOpcodeAllowed(p.GetOpcode())) - { - dosTriggered = true; - // Opcode not allowed, let the punishment begin - TC_LOG_WARN("network", "AntiDOS: Account %u, IP: %s, sent unacceptable packet (opc: %u, size: %u)", - Session->GetAccountId(), Session->GetRemoteAddress().c_str(), p.GetOpcode(), (uint32)p.size()); - } - - // Return true if everything is fine, otherwise apply the configured policy - if (!dosTriggered) + if (++packetCounter.amountCounter <= maxPacketCounterAllowed) return true; + TC_LOG_WARN("network", "AntiDOS: Account %u, IP: %s, Ping: %u, Character: %s, flooding packet (opc: %s (0x%X), count: %u)", + Session->GetAccountId(), Session->GetRemoteAddress().c_str(), Session->GetLatency(), Session->GetPlayerName().c_str(), + opcodeTable[p.GetOpcode()]->Name, p.GetOpcode(), packetCounter.amountCounter); + switch (_policy) { case POLICY_LOG: @@ -1252,220 +1242,231 @@ uint32 WorldSession::DosProtection::GetMaxPacketCounterAllowed(uint16 opcode) co uint32 maxPacketCounterAllowed; switch (opcode) { - case CMSG_MESSAGECHAT_ADDON_BATTLEGROUND: - case CMSG_MESSAGECHAT_ADDON_GUILD: - case CMSG_MESSAGECHAT_ADDON_OFFICER: - case CMSG_MESSAGECHAT_ADDON_PARTY: - case CMSG_MESSAGECHAT_ADDON_RAID: - case CMSG_MESSAGECHAT_ADDON_WHISPER: - case CMSG_MESSAGECHAT_AFK: - case CMSG_MESSAGECHAT_BATTLEGROUND: - case CMSG_MESSAGECHAT_CHANNEL: - case CMSG_MESSAGECHAT_DND: - case CMSG_MESSAGECHAT_EMOTE: - case CMSG_MESSAGECHAT_GUILD: - case CMSG_MESSAGECHAT_OFFICER: - case CMSG_MESSAGECHAT_PARTY: - case CMSG_MESSAGECHAT_RAID: - case CMSG_MESSAGECHAT_RAID_WARNING: - case CMSG_MESSAGECHAT_SAY: - case CMSG_MESSAGECHAT_WHISPER: - case CMSG_MESSAGECHAT_YELL: + // CPU usage sending 2000 packets/second on a 3.70 GHz 4 cores on Win x64 + // [% CPU mysqld] [%CPU worldserver RelWithDebInfo] + case CMSG_PLAYER_LOGIN: // 0 0.5 + case CMSG_NAME_QUERY: // 0 1 + case CMSG_PET_NAME_QUERY: // 0 1 + case CMSG_NPC_TEXT_QUERY: // 0 1 + case CMSG_ATTACKSTOP: // 0 1 + case CMSG_QUERY_QUESTS_COMPLETED: // 0 1 + case CMSG_QUERY_TIME: // 0 1 + case CMSG_CORPSE_MAP_POSITION_QUERY: // 0 1 + case CMSG_MOVE_TIME_SKIPPED: // 0 1 + case MSG_QUERY_NEXT_MAIL_TIME: // 0 1 + case CMSG_SETSHEATHED: // 0 1 + case MSG_RAID_TARGET_UPDATE: // 0 1 + case CMSG_PLAYER_LOGOUT: // 0 1 + case CMSG_LOGOUT_REQUEST: // 0 1 + case CMSG_PET_RENAME: // 0 1 + case CMSG_QUESTGIVER_REQUEST_REWARD: // 0 1 + case CMSG_COMPLETE_CINEMATIC: // 0 1 + case CMSG_BANKER_ACTIVATE: // 0 1 + case CMSG_BUY_BANK_SLOT: // 0 1 + case CMSG_OPT_OUT_OF_LOOT: // 0 1 + case CMSG_DUEL_ACCEPTED: // 0 1 + case CMSG_DUEL_CANCELLED: // 0 1 + case CMSG_CALENDAR_COMPLAIN: // 0 1 + case CMSG_QUEST_QUERY: // 0 1.5 + case CMSG_GAMEOBJECT_QUERY: // 0 1.5 + case CMSG_CREATURE_QUERY: // 0 1.5 + case CMSG_QUESTGIVER_STATUS_QUERY: // 0 1.5 + case CMSG_GUILD_QUERY: // 0 1.5 + case CMSG_ARENA_TEAM_QUERY: // 0 1.5 + case CMSG_TAXINODE_STATUS_QUERY: // 0 1.5 + case CMSG_TAXIQUERYAVAILABLENODES: // 0 1.5 + case CMSG_QUESTGIVER_QUERY_QUEST: // 0 1.5 + case CMSG_PAGE_TEXT_QUERY: // 0 1.5 + case CMSG_GUILD_BANK_QUERY_TEXT: // 0 1.5 + case MSG_CORPSE_QUERY: // 0 1.5 + case MSG_MOVE_SET_FACING: // 0 1.5 + case CMSG_REQUEST_PARTY_MEMBER_STATS: // 0 1.5 + case CMSG_QUESTGIVER_COMPLETE_QUEST: // 0 1.5 + case CMSG_SET_ACTION_BUTTON: // 0 1.5 + case CMSG_RESET_INSTANCES: // 0 1.5 + case CMSG_HEARTH_AND_RESURRECT: // 0 1.5 + case CMSG_TOGGLE_PVP: // 0 1.5 + case CMSG_PET_ABANDON: // 0 1.5 + case CMSG_ACTIVATETAXIEXPRESS: // 0 1.5 + case CMSG_ACTIVATETAXI: // 0 1.5 + case CMSG_SELF_RES: // 0 1.5 + case CMSG_UNLEARN_SKILL: // 0 1.5 + case CMSG_EQUIPMENT_SET_SAVE: // 0 1.5 + case CMSG_EQUIPMENT_SET_DELETE: // 0 1.5 + case CMSG_DISMISS_CRITTER: // 0 1.5 + case CMSG_REPOP_REQUEST: // 0 1.5 + case CMSG_GROUP_INVITE: // 0 1.5 + case CMSG_GROUP_INVITE_RESPONSE: // 0 1.5 + case CMSG_GROUP_UNINVITE_GUID: // 0 1.5 + case CMSG_GROUP_DISBAND: // 0 1.5 + case CMSG_BATTLEMASTER_JOIN_ARENA: // 0 1.5 + case CMSG_BATTLEFIELD_LEAVE: // 0 1.5 + case CMSG_GUILD_BANK_LOG_QUERY: // 0 2 + case CMSG_LOGOUT_CANCEL: // 0 2 + case CMSG_REALM_SPLIT: // 0 2 + case CMSG_ALTER_APPEARANCE: // 0 2 + case CMSG_QUEST_CONFIRM_ACCEPT: // 0 2 + case CMSG_GUILD_EVENT_LOG_QUERY: // 0 2.5 + case CMSG_READY_FOR_ACCOUNT_DATA_TIMES: // 0 2.5 + case CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY: // 0 2.5 + case CMSG_BEGIN_TRADE: // 0 2.5 + case CMSG_INITIATE_TRADE: // 0 3 + case CMSG_MESSAGECHAT_ADDON_BATTLEGROUND: // 0 3.5 + case CMSG_MESSAGECHAT_ADDON_GUILD: // 0 3.5 + case CMSG_MESSAGECHAT_ADDON_OFFICER: // 0 3.5 + case CMSG_MESSAGECHAT_ADDON_PARTY: // 0 3.5 + case CMSG_MESSAGECHAT_ADDON_RAID: // 0 3.5 + case CMSG_MESSAGECHAT_ADDON_WHISPER: // 0 3.5 + case CMSG_MESSAGECHAT_AFK: // 0 3.5 + case CMSG_MESSAGECHAT_BATTLEGROUND: // 0 3.5 + case CMSG_MESSAGECHAT_CHANNEL: // 0 3.5 + case CMSG_MESSAGECHAT_DND: // 0 3.5 + case CMSG_MESSAGECHAT_EMOTE: // 0 3.5 + case CMSG_MESSAGECHAT_GUILD: // 0 3.5 + case CMSG_MESSAGECHAT_OFFICER: // 0 3.5 + case CMSG_MESSAGECHAT_PARTY: // 0 3.5 + case CMSG_MESSAGECHAT_RAID: // 0 3.5 + case CMSG_MESSAGECHAT_RAID_WARNING: // 0 3.5 + case CMSG_MESSAGECHAT_SAY: // 0 3.5 + case CMSG_MESSAGECHAT_WHISPER: // 0 3.5 + case CMSG_MESSAGECHAT_YELL: // 0 3.5 + case CMSG_INSPECT: // 0 3.5 + case CMSG_AREA_SPIRIT_HEALER_QUERY: // not profiled { - maxPacketCounterAllowed = 500; + // "0" is a magic number meaning there's no limit for the opcode. + // All the opcodes above must cause little CPU usage and no sync/async database queries at all + maxPacketCounterAllowed = 0; break; } - case CMSG_ATTACKSTOP: - case CMSG_GUILD_QUERY: - case CMSG_NAME_QUERY: - case CMSG_PET_NAME_QUERY: - case CMSG_CREATURE_QUERY: - case CMSG_NPC_TEXT_QUERY: - case CMSG_QUESTGIVER_STATUS_QUERY: + case CMSG_QUESTGIVER_ACCEPT_QUEST: // 0 4 + case CMSG_QUESTLOG_REMOVE_QUEST: // 0 4 + case CMSG_QUESTGIVER_CHOOSE_REWARD: // 0 4 + case CMSG_CONTACT_LIST: // 0 5 + case CMSG_LEARN_PREVIEW_TALENTS: // 0 6 + case CMSG_AUTOBANK_ITEM: // 0 6 + case CMSG_AUTOSTORE_BANK_ITEM: // 0 6 + case CMSG_WHO: // 0 7 + case CMSG_PLAYER_VEHICLE_ENTER: // 0 8 + case CMSG_LEARN_PREVIEW_TALENTS_PET: // not profiled + case MSG_MOVE_HEARTBEAT: { - maxPacketCounterAllowed = 5000; + maxPacketCounterAllowed = 200; break; } - case CMSG_ARENA_TEAM_QUERY: - case CMSG_TAXINODE_STATUS_QUERY: - case CMSG_TAXIQUERYAVAILABLENODES: - case CMSG_QUESTGIVER_QUERY_QUEST: - case CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY: - case CMSG_QUERY_QUESTS_COMPLETED: - case CMSG_QUEST_POI_QUERY: - case CMSG_QUERY_TIME: - case CMSG_PAGE_TEXT_QUERY: - case CMSG_PETITION_QUERY: - case CMSG_QUERY_INSPECT_ACHIEVEMENTS: - case CMSG_AREA_SPIRIT_HEALER_QUERY: - case CMSG_CORPSE_MAP_POSITION_QUERY: - case CMSG_MOVE_TIME_SKIPPED: - case CMSG_GUILD_BANK_QUERY_TAB: - case CMSG_GUILD_BANK_LOG_QUERY: - case CMSG_GUILD_EVENT_LOG_QUERY: - case MSG_CORPSE_QUERY: - case MSG_QUERY_NEXT_MAIL_TIME: - case MSG_MOVE_SET_FACING: - case CMSG_INSPECT: + case CMSG_GUILD_SET_NOTE: // 1 2 1 async db query + case CMSG_SET_CONTACT_NOTES: // 1 2.5 1 async db query + case CMSG_CALENDAR_GET_CALENDAR: // 0 1.5 medium upload bandwidth usage + case CMSG_GUILD_BANK_QUERY_TAB: // 0 3.5 medium upload bandwidth usage + case CMSG_QUERY_INSPECT_ACHIEVEMENTS: // 0 13 high upload bandwidth usage { - maxPacketCounterAllowed = 500; + maxPacketCounterAllowed = 50; break; } - case CMSG_REQUEST_PARTY_MEMBER_STATS: - case CMSG_WHO: - case CMSG_SETSHEATHED: - case CMSG_CONTACT_LIST: - case CMSG_GUILD_MOTD: + case CMSG_QUEST_POI_QUERY: // 0 25 very high upload bandwidth usage { - maxPacketCounterAllowed = 50; + maxPacketCounterAllowed = MAX_QUEST_LOG_SIZE; break; } - case CMSG_SPELLCLICK: - case CMSG_GAMEOBJ_USE: - case CMSG_GAMEOBJ_REPORT_USE: - case MSG_RAID_TARGET_UPDATE: - case CMSG_QUESTGIVER_COMPLETE_QUEST: - case CMSG_PLAYER_VEHICLE_ENTER: - case CMSG_PETITION_SIGN: + case CMSG_GM_REPORT_LAG: // 1 3 1 async db query + case CMSG_SPELLCLICK: // not profiled + case CMSG_GAMEOBJ_USE: // not profiled + case CMSG_GAMEOBJ_REPORT_USE: // not profiled { maxPacketCounterAllowed = 20; break; } - case CMSG_PLAYER_LOGOUT: - case CMSG_LOGOUT_REQUEST: - case CMSG_LOGOUT_CANCEL: - case CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE: - case CMSG_REQUEST_VEHICLE_PREV_SEAT: - case CMSG_REQUEST_VEHICLE_NEXT_SEAT: - case CMSG_REQUEST_VEHICLE_SWITCH_SEAT: - case CMSG_TOGGLE_PVP: - case CMSG_ADD_FRIEND: - case CMSG_DEL_FRIEND: - case CMSG_SET_CONTACT_NOTES: - case CMSG_RESET_INSTANCES: - case CMSG_HEARTH_AND_RESURRECT: - case CMSG_CHAR_CREATE: - case CMSG_READY_FOR_ACCOUNT_DATA_TIMES: - case CMSG_CHAR_ENUM: - case CMSG_REALM_SPLIT: - case CMSG_CHAR_DELETE: - case CMSG_PLAYER_LOGIN: - case CMSG_PET_ABANDON: - case CMSG_PET_RENAME: - case CMSG_CHAR_RENAME: - case CMSG_CHAR_CUSTOMIZE: - case CMSG_CHAR_RACE_CHANGE: - case CMSG_CHAR_FACTION_CHANGE: - case CMSG_GMTICKET_CREATE: - case CMSG_GMTICKET_UPDATETEXT: - case CMSG_GMTICKET_DELETETICKET: - case CMSG_GMSURVEY_SUBMIT: - case CMSG_GM_REPORT_LAG: - case CMSG_BUG: - case CMSG_GMRESPONSE_RESOLVE: - case CMSG_ACTIVATETAXIEXPRESS: - case CMSG_ACTIVATETAXI: - case CMSG_SELF_RES: - case CMSG_INITIATE_TRADE: - case CMSG_BEGIN_TRADE: - case CMSG_UNLEARN_SKILL: - case CMSG_DISMISS_CONTROLLED_VEHICLE: - case CMSG_REQUEST_VEHICLE_EXIT: - case CMSG_LEARN_PREVIEW_TALENTS: - case CMSG_LEARN_PREVIEW_TALENTS_PET: - case CMSG_EJECT_PASSENGER: - case CMSG_EQUIPMENT_SET_SAVE: - case CMSG_EQUIPMENT_SET_DELETE: - case CMSG_ALTER_APPEARANCE: - case CMSG_QUESTGIVER_ACCEPT_QUEST: - case CMSG_QUESTGIVER_CHOOSE_REWARD: - case CMSG_QUESTGIVER_REQUEST_REWARD: - //case CMSG_QUESTGIVER_CANCEL: - case CMSG_QUESTLOG_REMOVE_QUEST: - case CMSG_QUEST_CONFIRM_ACCEPT: - case CMSG_DISMISS_CRITTER: - case CMSG_REPOP_REQUEST: - case CMSG_PETITION_BUY: - case CMSG_TURN_IN_PETITION: - case CMSG_COMPLETE_CINEMATIC: - case CMSG_ITEM_REFUND: - case CMSG_SOCKET_GEMS: - case CMSG_WRAP_ITEM: - case CMSG_BUY_BANK_SLOT: - case CMSG_GROUP_INVITE_RESPONSE: - //case CMSG_GROUP_UNINVITE: - case CMSG_GROUP_UNINVITE_GUID: - case CMSG_GROUP_SET_LEADER: - case CMSG_GROUP_DISBAND: - case CMSG_GROUP_RAID_CONVERT: - case CMSG_GROUP_CHANGE_SUB_GROUP: - case CMSG_GROUP_ASSISTANT_LEADER: - case CMSG_OPT_OUT_OF_LOOT: - case CMSG_BATTLEMASTER_JOIN_ARENA: - case CMSG_BATTLEFIELD_LEAVE: - case CMSG_REPORT_PVP_AFK: - case CMSG_DUEL_ACCEPTED: - case CMSG_DUEL_CANCELLED: - case CMSG_CALENDAR_GET_CALENDAR: - case CMSG_CALENDAR_ADD_EVENT: - case CMSG_CALENDAR_UPDATE_EVENT: - case CMSG_CALENDAR_REMOVE_EVENT: - case CMSG_CALENDAR_COPY_EVENT: - case CMSG_CALENDAR_EVENT_INVITE: - case CMSG_CALENDAR_EVENT_SIGNUP: - case CMSG_CALENDAR_EVENT_RSVP: - case CMSG_CALENDAR_EVENT_REMOVE_INVITE: - case CMSG_CALENDAR_EVENT_MODERATOR_STATUS: - case CMSG_CALENDAR_COMPLAIN: - case CMSG_ARENA_TEAM_INVITE: - case CMSG_ARENA_TEAM_ACCEPT: - case CMSG_ARENA_TEAM_DECLINE: - case CMSG_ARENA_TEAM_LEAVE: - case CMSG_ARENA_TEAM_DISBAND: - case CMSG_ARENA_TEAM_REMOVE: - case CMSG_ARENA_TEAM_LEADER: - case CMSG_LOOT_METHOD: - case CMSG_GUILD_INVITE: - case CMSG_GUILD_ACCEPT: - case CMSG_GUILD_DECLINE: - case CMSG_GUILD_LEAVE: - case CMSG_GUILD_DISBAND: - case CMSG_GUILD_SET_GUILD_MASTER: - case CMSG_GUILD_QUERY_RANKS: - case CMSG_GUILD_ADD_RANK: - case CMSG_GUILD_DEL_RANK: - case CMSG_GUILD_INFO_TEXT: - case CMSG_GUILD_BANK_DEPOSIT_MONEY: - case CMSG_GUILD_BANK_WITHDRAW_MONEY: - case CMSG_GUILD_BANK_BUY_TAB: - case CMSG_GUILD_BANK_UPDATE_TAB: - case CMSG_SET_GUILD_BANK_TEXT: - case MSG_SAVE_GUILD_EMBLEM: - case MSG_PETITION_RENAME: - case MSG_PETITION_DECLINE: - case MSG_TALENT_WIPE_CONFIRM: - case MSG_SET_DUNGEON_DIFFICULTY: - case MSG_SET_RAID_DIFFICULTY: - case MSG_RANDOM_ROLL: - case MSG_PARTY_ASSIGNMENT: - case MSG_RAID_READY_CHECK: + case CMSG_PETITION_SIGN: // 9 4 2 sync 1 async db queries + case CMSG_TURN_IN_PETITION: // 8 5.5 2 sync db query + case CMSG_GROUP_CHANGE_SUB_GROUP: // 6 5 1 sync 1 async db queries + case CMSG_PETITION_QUERY: // 4 3.5 1 sync db query + case CMSG_CHAR_RACE_CHANGE: // 5 4 1 sync db query + case CMSG_CHAR_CUSTOMIZE: // 5 5 1 sync db query + case CMSG_CHAR_FACTION_CHANGE: // 5 5 1 sync db query + case CMSG_CHAR_DELETE: // 4 4 1 sync db query + case CMSG_DEL_FRIEND: // 7 5 1 async db query + case CMSG_ADD_FRIEND: // 6 4 1 async db query + case CMSG_CHAR_RENAME: // 5 3 1 async db query + case CMSG_GMSURVEY_SUBMIT: // 2 3 1 async db query + case CMSG_BUG: // 1 1 1 async db query + case CMSG_GROUP_SET_LEADER: // 1 2 1 async db query + case CMSG_GROUP_RAID_CONVERT: // 1 5 1 async db query + case CMSG_GROUP_ASSISTANT_LEADER: // 1 2 1 async db query + case CMSG_CALENDAR_ADD_EVENT: // 21 10 2 async db query + case CMSG_PETITION_BUY: // not profiled 1 sync 1 async db queries + case CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE: // not profiled + case CMSG_REQUEST_VEHICLE_PREV_SEAT: // not profiled + case CMSG_REQUEST_VEHICLE_NEXT_SEAT: // not profiled + case CMSG_REQUEST_VEHICLE_SWITCH_SEAT: // not profiled + case CMSG_DISMISS_CONTROLLED_VEHICLE: // not profiled + case CMSG_REQUEST_VEHICLE_EXIT: // not profiled + case CMSG_EJECT_PASSENGER: // not profiled + case CMSG_ITEM_REFUND: // not profiled + case CMSG_SOCKET_GEMS: // not profiled + case CMSG_WRAP_ITEM: // not profiled + case CMSG_REPORT_PVP_AFK: // not profiled { - maxPacketCounterAllowed = 3; + maxPacketCounterAllowed = 10; break; } - case CMSG_SET_ACTION_BUTTON: + case CMSG_CHAR_CREATE: // 7 5 3 async db queries + case CMSG_CHAR_ENUM: // 22 3 2 async db queries + case CMSG_GMTICKET_CREATE: // 1 25 1 async db query + case CMSG_GMTICKET_UPDATETEXT: // 0 15 1 async db query + case CMSG_GMTICKET_DELETETICKET: // 1 25 1 async db query + case CMSG_GMRESPONSE_RESOLVE: // 1 25 1 async db query + case CMSG_CALENDAR_UPDATE_EVENT: // not profiled + case CMSG_CALENDAR_REMOVE_EVENT: // not profiled + case CMSG_CALENDAR_COPY_EVENT: // not profiled + case CMSG_CALENDAR_EVENT_INVITE: // not profiled + case CMSG_CALENDAR_EVENT_SIGNUP: // not profiled + case CMSG_CALENDAR_EVENT_RSVP: // not profiled + case CMSG_CALENDAR_EVENT_REMOVE_INVITE: // not profiled + case CMSG_CALENDAR_EVENT_MODERATOR_STATUS: // not profiled + case CMSG_ARENA_TEAM_INVITE: // not profiled + case CMSG_ARENA_TEAM_ACCEPT: // not profiled + case CMSG_ARENA_TEAM_DECLINE: // not profiled + case CMSG_ARENA_TEAM_LEAVE: // not profiled + case CMSG_ARENA_TEAM_DISBAND: // not profiled + case CMSG_ARENA_TEAM_REMOVE: // not profiled + case CMSG_ARENA_TEAM_LEADER: // not profiled + case CMSG_LOOT_METHOD: // not profiled + case CMSG_GUILD_INVITE: // not profiled + case CMSG_GUILD_ACCEPT: // not profiled + case CMSG_GUILD_DECLINE: // not profiled + case CMSG_GUILD_LEAVE: // not profiled + case CMSG_GUILD_DISBAND: // not profiled + case CMSG_GUILD_SET_GUILD_MASTER: // not profiled + case CMSG_GUILD_MOTD: // not profiled + case CMSG_GUILD_SET_RANK_PERMISSIONS: // not profiled + case CMSG_GUILD_ADD_RANK: // not profiled + case CMSG_GUILD_DEL_RANK: // not profiled + case CMSG_GUILD_INFO_TEXT: // not profiled + case CMSG_GUILD_BANK_DEPOSIT_MONEY: // not profiled + case CMSG_GUILD_BANK_WITHDRAW_MONEY: // not profiled + case CMSG_GUILD_BANK_BUY_TAB: // not profiled + case CMSG_GUILD_BANK_UPDATE_TAB: // not profiled + case CMSG_SET_GUILD_BANK_TEXT: // not profiled + case MSG_SAVE_GUILD_EMBLEM: // not profiled + case MSG_PETITION_RENAME: // not profiled + case MSG_PETITION_DECLINE: // not profiled + case MSG_TALENT_WIPE_CONFIRM: // not profiled + case MSG_SET_DUNGEON_DIFFICULTY: // not profiled + case MSG_SET_RAID_DIFFICULTY: // not profiled + case MSG_RANDOM_ROLL: // not profiled + case MSG_PARTY_ASSIGNMENT: // not profiled + case MSG_RAID_READY_CHECK: // not profiled { - maxPacketCounterAllowed = MAX_ACTION_BUTTONS; + maxPacketCounterAllowed = 3; break; } - case CMSG_ITEM_REFUND_INFO: + case CMSG_ITEM_REFUND_INFO: // not profiled { maxPacketCounterAllowed = PLAYER_SLOTS_COUNT; break; diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 3eb9f5cb3c5..9c44fa8fad3 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -215,7 +215,7 @@ struct PacketCounter class WorldSession { public: - WorldSession(uint32 id, WorldSocket* sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale, uint32 recruiter, bool isARecruiter); + WorldSession(uint32 id, uint32 battlenetAccountId, WorldSocket* sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale, uint32 recruiter, bool isARecruiter); ~WorldSession(); bool PlayerLoading() const { return m_playerLoading; } @@ -246,6 +246,7 @@ class WorldSession AccountTypes GetSecurity() const { return _security; } uint32 GetAccountId() const { return _accountId; } + uint32 GetBattlenetAccountId() const { return _battlenetAccountId; } Player* GetPlayer() const { return _player; } std::string const& GetPlayerName() const; std::string GetPlayerInfo() const; @@ -302,7 +303,7 @@ class WorldSession void SendBattleGroundList(uint64 guid, BattlegroundTypeId bgTypeId = BATTLEGROUND_RB); - void SendTradeStatus(TradeStatus status); + void SendTradeStatus(TradeStatus status, int8 clearSlot = 0); void SendUpdateTrade(bool trader_data = true); void SendCancelTrade(); @@ -994,7 +995,6 @@ class WorldSession public: DosProtection(WorldSession* s) : Session(s), _policy((Policy)sWorld->getIntConfig(CONFIG_PACKET_SPOOF_POLICY)) { } bool EvaluateOpcode(WorldPacket& p, time_t time) const; - void AllowOpcode(uint16 opcode, bool allow) { _isOpcodeAllowed[opcode] = allow; } protected: enum Policy { @@ -1003,22 +1003,11 @@ class WorldSession POLICY_BAN, }; - bool IsOpcodeAllowed(uint16 opcode) const - { - OpcodeStatusMap::const_iterator itr = _isOpcodeAllowed.find(opcode); - if (itr == _isOpcodeAllowed.end()) - return true; // No presence in the map indicates this is the first time the opcode was sent this session, so allow - - return itr->second; - } - uint32 GetMaxPacketCounterAllowed(uint16 opcode) const; WorldSession* Session; private: - typedef std::unordered_map<uint16, bool> OpcodeStatusMap; - OpcodeStatusMap _isOpcodeAllowed; // could be bool array, but wouldn't be practical for game versions with non-linear opcodes Policy _policy; typedef std::unordered_map<uint16, PacketCounter> PacketThrottlingMap; // mark this member as "mutable" so it can be modified even in const functions @@ -1055,6 +1044,7 @@ class WorldSession AccountTypes _security; uint32 _accountId; + uint32 _battlenetAccountId; uint8 m_expansion; typedef std::list<AddonInfo> AddonsList; diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index 737a2f8cbf1..58299a7194c 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -45,6 +45,7 @@ #include "PacketLog.h" #include "ScriptMgr.h" #include "AccountMgr.h" +#include "BattlenetAccountMgr.h" #if defined(__GNUC__) #pragma pack(1) @@ -856,9 +857,20 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) // Get the account information from the realmd database // 0 1 2 3 4 5 6 7 8 // SELECT id, sessionkey, last_ip, locked, expansion, mutetime, locale, recruiter, os FROM account WHERE username = ? - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME); - - stmt->setString(0, account); + PreparedStatement* stmt; + uint32 battlenetAccountId = 0; + uint8 battlenetAccountIndex = 0; + if (Battlenet::AccountMgr::GetAccountIdAndIndex(account, &battlenetAccountId, &battlenetAccountIndex)) + { + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_INFO_BY_BNET); + stmt->setUInt32(0, battlenetAccountId); + stmt->setUInt8(1, battlenetAccountIndex); + } + else + { + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME); + stmt->setString(0, account); + } PreparedQueryResult result = LoginDatabase.Query(stmt); @@ -1007,7 +1019,7 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) LoginDatabase.Execute(stmt); // NOTE ATM the socket is single-threaded, have this in mind ... - ACE_NEW_RETURN(m_Session, WorldSession(id, this, AccountTypes(security), expansion, mutetime, locale, recruiter, isRecruiter), -1); + ACE_NEW_RETURN(m_Session, WorldSession(id, battlenetAccountId, this, AccountTypes(security), expansion, mutetime, locale, recruiter, isRecruiter), -1); m_Crypt.Init(&k); diff --git a/src/server/game/Server/WorldSocket.h b/src/server/game/Server/WorldSocket.h index 4ccacd05c7e..306a50c083a 100644 --- a/src/server/game/Server/WorldSocket.h +++ b/src/server/game/Server/WorldSocket.h @@ -39,7 +39,7 @@ #endif /* ACE_LACKS_PRAGMA_ONCE */ #include "Common.h" -#include "AuthCrypt.h" +#include "WorldPacketCrypt.h" class ACE_Message_Block; class WorldPacket; @@ -176,7 +176,7 @@ class WorldSocket : public WorldHandler std::string m_Address; /// Class used for managing encryption of the headers - AuthCrypt m_Crypt; + WorldPacketCrypt m_Crypt; /// Mutex lock to protect m_Session LockType m_SessionLock; diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index c767d4da9ed..03512b85460 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -434,6 +434,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= AuraEffect::AuraEffect(Aura* base, uint8 effIndex, int32 *baseAmount, Unit* caster): m_base(base), m_spellInfo(base->GetSpellInfo()), m_baseAmount(baseAmount ? *baseAmount : m_spellInfo->Effects[effIndex].BasePoints), +m_damage(0), m_critChance(0.0f), m_donePct(1.0f), m_spellmod(NULL), m_periodicTimer(0), m_tickNumber(0), m_effIndex(effIndex), m_canBeRecalculated(true), m_isPeriodic(false) { @@ -995,10 +996,11 @@ void AuraEffect::UpdatePeriodic(Unit* caster) GetBase()->CallScriptEffectUpdatePeriodicHandlers(this); } -bool AuraEffect::IsPeriodicTickCrit(Unit* target, Unit const* caster) const +bool AuraEffect::CanPeriodicTickCrit(Unit const* caster) const { ASSERT(caster); - return caster->isSpellCrit(target, m_spellInfo, m_spellInfo->GetSchoolMask()); + + return caster->HasAuraTypeWithAffectMask(SPELL_AURA_ABILITY_PERIODIC_CRIT, m_spellInfo); } bool AuraEffect::IsAffectingSpell(SpellInfo const* spell) const @@ -3565,11 +3567,23 @@ void AuraEffect::HandleModResistancePercent(AuraApplication const* aurApp, uint8 return; Unit* target = aurApp->GetTarget(); + int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_RESISTANCE_PCT); + if (abs(spellGroupVal) >= abs(GetAmount())) + return; for (int8 i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++) { if (GetMiscValue() & int32(1<<i)) { + if (spellGroupVal) + { + target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_PCT, (float)spellGroupVal, !apply); + if (target->GetTypeId() == TYPEID_PLAYER || target->IsPet()) + { + target->ApplyResistanceBuffModsPercentMod(SpellSchools(i), true, (float)spellGroupVal, !apply); + target->ApplyResistanceBuffModsPercentMod(SpellSchools(i), false, (float)spellGroupVal, !apply); + } + } target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_PCT, float(GetAmount()), apply); if (target->GetTypeId() == TYPEID_PLAYER || target->ToCreature()->IsPet()) { @@ -3629,19 +3643,29 @@ void AuraEffect::HandleAuraModStat(AuraApplication const* aurApp, uint8 mode, bo if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; - Unit* target = aurApp->GetTarget(); - if (GetMiscValue() < -2 || GetMiscValue() > 4) { TC_LOG_ERROR("spells", "WARNING: Spell %u effect %u has an unsupported misc value (%i) for SPELL_AURA_MOD_STAT ", GetId(), GetEffIndex(), GetMiscValue()); return; } + Unit* target = aurApp->GetTarget(); + int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_STAT, true, GetMiscValue()); + if (abs(spellGroupVal) >= abs(GetAmount())) + return; + for (int32 i = STAT_STRENGTH; i < MAX_STATS; i++) { // -1 or -2 is all stats (misc < -2 checked in function beginning) if (GetMiscValue() < 0 || GetMiscValue() == i) { + if (spellGroupVal) + { + target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_VALUE, float(spellGroupVal), !apply); + if (target->GetTypeId() == TYPEID_PLAYER || target->ToCreature()->IsPet()) + target->ApplyStatBuffMod(Stats(i), float(spellGroupVal), !apply); + } + //target->ApplyStatMod(Stats(i), m_amount, apply); target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_VALUE, float(GetAmount()), apply); if (target->GetTypeId() == TYPEID_PLAYER || target->ToCreature()->IsPet()) @@ -3754,6 +3778,22 @@ void AuraEffect::HandleModTotalPercentStat(AuraApplication const* aurApp, uint8 return; Unit* target = aurApp->GetTarget(); + int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, true, -1); + if (abs(spellGroupVal) >= abs(GetAmount())) + return; + + if (spellGroupVal) + { + for (int32 i = STAT_STRENGTH; i < MAX_STATS; i++) + { + if (GetMiscValue() == i || GetMiscValue() == -1) // affect the same stats + { + target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT, float(spellGroupVal), !apply); + if (target->GetTypeId() == TYPEID_PLAYER || target->ToCreature()->IsPet()) + target->ApplyStatPercentBuffMod(Stats(i), float(spellGroupVal), !apply); + } + } + } // save current health state float healthPct = target->GetHealthPct(); @@ -3763,6 +3803,17 @@ void AuraEffect::HandleModTotalPercentStat(AuraApplication const* aurApp, uint8 { if (GetMiscValueB() & 1 << i || !GetMiscValueB()) // 0 is also used for all stats { + int32 spellGroupVal2 = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, true, i); + if (abs(spellGroupVal2) >= abs(GetAmount())) + continue; + + if (spellGroupVal2) + { + target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT, float(spellGroupVal2), !apply); + if (target->GetTypeId() == TYPEID_PLAYER || target->ToCreature()->IsPet()) + target->ApplyStatPercentBuffMod(Stats(i), float(spellGroupVal2), !apply); + } + target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT, float(GetAmount()), apply); if (target->GetTypeId() == TYPEID_PLAYER || target->ToCreature()->IsPet()) target->ApplyStatPercentBuffMod(Stats(i), float(GetAmount()), apply); @@ -4162,7 +4213,17 @@ void AuraEffect::HandleModCombatSpeedPct(AuraApplication const* aurApp, uint8 mo return; Unit* target = aurApp->GetTarget(); + int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MELEE_SLOW); + if (abs(spellGroupVal) >= abs(GetAmount())) + return; + if (spellGroupVal) + { + target->ApplyCastTimePercentMod(float(spellGroupVal), !apply); + target->ApplyAttackTimePercentMod(BASE_ATTACK, float(spellGroupVal), !apply); + target->ApplyAttackTimePercentMod(OFF_ATTACK, float(spellGroupVal), !apply); + target->ApplyAttackTimePercentMod(RANGED_ATTACK, float(spellGroupVal), !apply); + } target->ApplyCastTimePercentMod(float(m_amount), apply); target->ApplyAttackTimePercentMod(BASE_ATTACK, float(GetAmount()), apply); target->ApplyAttackTimePercentMod(OFF_ATTACK, float(GetAmount()), apply); @@ -4187,7 +4248,15 @@ void AuraEffect::HandleModMeleeSpeedPct(AuraApplication const* aurApp, uint8 mod //! ToDo: Haste auras with the same handler _CAN'T_ stack together Unit* target = aurApp->GetTarget(); + int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_MELEE_HASTE); + if (abs(spellGroupVal) >= abs(GetAmount())) + return; + if (spellGroupVal) + { + target->ApplyAttackTimePercentMod(BASE_ATTACK, float(spellGroupVal), !apply); + target->ApplyAttackTimePercentMod(OFF_ATTACK, float(spellGroupVal), !apply); + } target->ApplyAttackTimePercentMod(BASE_ATTACK, float(GetAmount()), apply); target->ApplyAttackTimePercentMod(OFF_ATTACK, float(GetAmount()), apply); } @@ -4395,7 +4464,8 @@ void AuraEffect::HandleModDamagePercentDone(AuraApplication const* aurApp, uint8 return; Unit* target = aurApp->GetTarget(); - if (!target) + int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); + if (abs(spellGroupVal) >= abs(GetAmount())) return; if (target->GetTypeId() == TYPEID_PLAYER) @@ -4407,12 +4477,23 @@ void AuraEffect::HandleModDamagePercentDone(AuraApplication const* aurApp, uint8 if ((GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) && (GetSpellInfo()->EquippedItemClass == -1 || target->GetTypeId() != TYPEID_PLAYER)) { + if (spellGroupVal) + { + target->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, float(spellGroupVal), !apply); + target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, float(spellGroupVal), !apply); + target->HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_PCT, float(spellGroupVal), !apply); + } target->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, float(GetAmount()), apply); target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, float(GetAmount()), apply); target->HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_PCT, float(GetAmount()), apply); - if (target->GetTypeId() == TYPEID_PLAYER) - target->ToPlayer()->ApplyPercentModFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT, float (GetAmount()), apply); + if (Player* player = target->ToPlayer()) + { + if (spellGroupVal) + player->ApplyPercentModFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT, float(spellGroupVal), !apply); + + player->ApplyPercentModFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT, float(GetAmount()), apply); + } } else { @@ -5754,15 +5835,19 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const uint32 resist = 0; CleanDamage cleanDamage = CleanDamage(0, 0, BASE_ATTACK, MELEE_HIT_NORMAL); - // ignore non positive values (can be result apply spellmods to aura damage - uint32 damage = std::max(GetAmount(), 0); + // AOE spells are not affected by the new periodic system. + bool isAreaAura = m_spellInfo->Effects[m_effIndex].IsAreaAuraEffect() || m_spellInfo->Effects[m_effIndex].IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA); + // ignore negative values (can be result apply spellmods to aura damage + uint32 damage = isAreaAura ? std::max(GetAmount(), 0) : m_damage; // Script Hook For HandlePeriodicDamageAurasTick -- Allow scripts to change the Damage pre class mitigation calculations - sScriptMgr->ModifyPeriodicDamageAurasTick(target, caster, damage); + if (isAreaAura) + sScriptMgr->ModifyPeriodicDamageAurasTick(target, caster, damage); if (GetAuraType() == SPELL_AURA_PERIODIC_DAMAGE) { - damage = caster->SpellDamageBonusDone(target, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount()); + if (isAreaAura) + damage = caster->SpellDamageBonusDone(target, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount()) * caster->SpellDamagePctDone(target, m_spellInfo, DOT); damage = target->SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount()); // Calculate armor mitigation @@ -5809,19 +5894,24 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const else damage = uint32(target->CountPctFromMaxHealth(damage)); - if (m_spellInfo->Effects[m_effIndex].IsTargetingArea() || m_spellInfo->Effects[m_effIndex].IsAreaAuraEffect() || m_spellInfo->Effects[m_effIndex].IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA)) - { - damage = int32(float(damage) * target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask)); - if (caster->GetTypeId() != TYPEID_PLAYER) - damage = int32(float(damage) * target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CREATURE_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask)); - } + if (!(m_spellInfo->AttributesEx4 & SPELL_ATTR4_FIXED_DAMAGE)) + if (m_spellInfo->Effects[m_effIndex].IsTargetingArea() || isAreaAura) + { + damage = int32(float(damage) * target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask)); + if (caster->GetTypeId() != TYPEID_PLAYER) + damage = int32(float(damage) * target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CREATURE_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask)); + } + + bool crit = false; + + if (CanPeriodicTickCrit(caster)) + crit = roll_chance_f(isAreaAura ? caster->GetUnitSpellCriticalChance(target, m_spellInfo, m_spellInfo->GetSchoolMask()) : m_critChance); - bool crit = IsPeriodicTickCrit(target, caster); if (crit) damage = caster->SpellCriticalDamageBonus(m_spellInfo, damage, target); int32 dmg = damage; - + if (!(GetSpellInfo()->AttributesEx4 & SPELL_ATTR4_FIXED_DAMAGE)) caster->ApplyResilience(target, &dmg); damage = dmg; @@ -5872,23 +5962,42 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c uint32 resist = 0; CleanDamage cleanDamage = CleanDamage(0, 0, BASE_ATTACK, MELEE_HIT_NORMAL); - uint32 damage = std::max(GetAmount(), 0); + bool isAreaAura = m_spellInfo->Effects[m_effIndex].IsAreaAuraEffect() || m_spellInfo->Effects[m_effIndex].IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA); + // ignore negative values (can be result apply spellmods to aura damage + uint32 damage = isAreaAura ? std::max(GetAmount(), 0) : m_damage; - damage = caster->SpellDamageBonusDone(target, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount()); + if (isAreaAura) + { + // Script Hook For HandlePeriodicDamageAurasTick -- Allow scripts to change the Damage pre class mitigation calculations + sScriptMgr->ModifyPeriodicDamageAurasTick(target, caster, damage); + damage = caster->SpellDamageBonusDone(target, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount()) * caster->SpellDamagePctDone(target, m_spellInfo, DOT); + } damage = target->SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount()); - bool crit = IsPeriodicTickCrit(target, caster); - if (crit) - damage = caster->SpellCriticalDamageBonus(m_spellInfo, damage, target); - // Calculate armor mitigation - if (Unit::IsDamageReducedByArmor(GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), m_effIndex)) + if (Unit::IsDamageReducedByArmor(GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), GetEffIndex())) { uint32 damageReductedArmor = caster->CalcArmorReducedDamage(target, damage, GetSpellInfo()); cleanDamage.mitigated_damage += damage - damageReductedArmor; damage = damageReductedArmor; } + if (!(m_spellInfo->AttributesEx4 & SPELL_ATTR4_FIXED_DAMAGE)) + if (m_spellInfo->Effects[m_effIndex].IsTargetingArea() || isAreaAura) + { + damage = int32(float(damage) * target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask)); + if (caster->GetTypeId() != TYPEID_PLAYER) + damage = int32(float(damage) * target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CREATURE_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask)); + } + + bool crit = false; + + if (CanPeriodicTickCrit(caster)) + crit = roll_chance_f(isAreaAura ? caster->GetUnitSpellCriticalChance(target, m_spellInfo, m_spellInfo->GetSchoolMask()) : m_critChance); + + if (crit) + damage = caster->SpellCriticalDamageBonus(m_spellInfo, damage, target); + int32 dmg = damage; if (!(GetSpellInfo()->AttributesEx4 & SPELL_ATTR4_FIXED_DAMAGE)) caster->ApplyResilience(target, &dmg); @@ -5973,8 +6082,9 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const if (GetBase()->IsPermanent() && target->IsFullHealth()) return; + bool isAreaAura = m_spellInfo->Effects[m_effIndex].IsAreaAuraEffect() || m_spellInfo->Effects[m_effIndex].IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA); // ignore negative values (can be result apply spellmods to aura damage - int32 damage = std::max(m_amount, 0); + int32 damage = isAreaAura ? std::max(GetAmount(), 0) : m_damage; if (GetAuraType() == SPELL_AURA_OBS_MOD_HEALTH) { @@ -6013,12 +6123,16 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const damage += addition; } - - damage = caster->SpellHealingBonusDone(target, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount()); + if (isAreaAura) + damage = caster->SpellHealingBonusDone(target, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount()) * caster->SpellHealingPctDone(target, m_spellInfo); damage = target->SpellHealingBonusTaken(caster, GetSpellInfo(), damage, DOT, GetBase()->GetStackAmount()); } - bool crit = IsPeriodicTickCrit(target, caster); + bool crit = false; + + if (CanPeriodicTickCrit(caster)) + crit = roll_chance_f(isAreaAura ? caster->GetUnitSpellCriticalChance(target, m_spellInfo, m_spellInfo->GetSchoolMask()) : m_critChance); + if (crit) damage = caster->SpellCriticalHealingBonus(m_spellInfo, damage, target); @@ -6166,6 +6280,9 @@ void AuraEffect::HandlePeriodicEnergizeAuraTick(Unit* target, Unit* caster) cons { Powers powerType = Powers(GetMiscValue()); + if (target->GetTypeId() == TYPEID_PLAYER && target->getPowerType() != powerType && !(m_spellInfo->AttributesEx7 & SPELL_ATTR7_CAN_RESTORE_SECONDARY_POWER)) + return; + if (!target->IsAlive() || !target->GetMaxPower(powerType)) return; diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h index 2415b89c9a8..700bbb10417 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.h +++ b/src/server/game/Spells/Auras/SpellAuraEffects.h @@ -70,6 +70,13 @@ class AuraEffect void HandleEffect(Unit* target, uint8 mode, bool apply); void ApplySpellMod(Unit* target, bool apply); + void SetDamage(int32 val) { m_damage = val; } + int32 GetDamage() const { return m_damage; } + void SetCritChance(float val) { m_critChance = val; } + float GetCritChance() const { return m_critChance; } + void SetDonePct(float val) { m_donePct = val; } + float GetDonePct() const { return m_donePct; } + void Update(uint32 diff, Unit* caster); void UpdatePeriodic(Unit* caster); @@ -98,6 +105,9 @@ class AuraEffect int32 const m_baseAmount; int32 m_amount; + int32 m_damage; + float m_critChance; + float m_donePct; SpellModifier* m_spellmod; @@ -109,7 +119,7 @@ class AuraEffect bool m_canBeRecalculated; bool m_isPeriodic; private: - bool IsPeriodicTickCrit(Unit* target, Unit const* caster) const; + bool CanPeriodicTickCrit(Unit const* caster) const; public: // aura effect apply/remove handlers diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index 05b4ebfc258..472af90c9ed 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -548,6 +548,9 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply) || !CanBeAppliedOn(itr->first)) addUnit = false; + if (addUnit && !itr->first->IsHighestExclusiveAura(this, true)) + addUnit = false; + if (addUnit) { // persistent area aura does not hit flying targets @@ -755,9 +758,20 @@ void Aura::SetDuration(int32 duration, bool withMods) SetNeedClientUpdateForTargets(); } -void Aura::RefreshDuration() +void Aura::RefreshDuration(bool withMods) { - SetDuration(GetMaxDuration()); + if (withMods) + { + int32 duration = m_spellInfo->GetMaxDuration(); + // Calculate duration of periodics affected by haste. + if (GetCaster()->HasAuraTypeWithAffectMask(SPELL_AURA_PERIODIC_HASTE, m_spellInfo) || m_spellInfo->AttributesEx5 & SPELL_ATTR5_HASTE_AFFECT_DURATION) + duration = int32(duration * GetCaster()->GetFloatValue(UNIT_MOD_CAST_SPEED)); + + SetMaxDuration(duration); + SetDuration(duration); + } + else + SetDuration(GetMaxDuration()); if (m_spellInfo->ManaPerSecond) m_timeCla = 1 * IN_MILLISECONDS; @@ -851,7 +865,10 @@ void Aura::SetStackAmount(uint8 stackAmount) for (std::list<AuraApplication*>::const_iterator apptItr = applications.begin(); apptItr != applications.end(); ++apptItr) if (!(*apptItr)->GetRemoveMode()) + { HandleAuraSpecificMods(*apptItr, caster, true, true); + HandleAuraSpecificPeriodics(*apptItr, caster); + } SetNeedClientUpdateForTargets(); } @@ -906,6 +923,18 @@ void Aura::RefreshSpellMods() player->RestoreAllSpellMods(0, this); } +bool Aura::HasMoreThanOneEffectForType(AuraType auraType) const +{ + uint32 count = 0; + for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) + { + if (HasEffect(i) && GetSpellInfo()->Effects[i].ApplyAuraName == auraType) + ++count; + } + + return count > 1; +} + bool Aura::IsArea() const { for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) @@ -1459,26 +1488,62 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b break; } break; - case SPELLFAMILY_WARLOCK: - // Drain Soul - If the target is at or below 25% health, Drain Soul causes four times the normal damage - if (GetSpellInfo()->SpellFamilyFlags[0] & 0x00004000) + } +} + +void Aura::HandleAuraSpecificPeriodics(AuraApplication const* aurApp, Unit* caster) +{ + Unit* target = aurApp->GetTarget(); + + if (!caster || aurApp->GetRemoveMode()) + return; + + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + { + if (!HasEffect(i)) + continue; + + if (m_spellInfo->Effects[i].IsAreaAuraEffect() || m_spellInfo->Effects[i].IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA)) + continue; + + switch (m_spellInfo->Effects[i].ApplyAuraName) + { + case SPELL_AURA_PERIODIC_DAMAGE: + case SPELL_AURA_PERIODIC_DAMAGE_PERCENT: + case SPELL_AURA_PERIODIC_LEECH: { - if (!caster) - break; - if (apply) - { - if (target != caster && !target->HealthAbovePct(25)) - caster->CastSpell(caster, 100001, true); - } - else - { - if (target != caster) - caster->RemoveAurasDueToSpell(GetId()); - else - caster->RemoveAurasDueToSpell(100001); - } + AuraEffect* aurEff = GetEffect(i); + + // ignore non positive values (can be result apply spellmods to aura damage + uint32 damage = std::max(aurEff->GetAmount(), 0); + + // Script Hook For HandlePeriodicDamageAurasTick -- Allow scripts to change the Damage pre class mitigation calculations + sScriptMgr->ModifyPeriodicDamageAurasTick(target, caster, damage); + + aurEff->SetDonePct(caster->SpellDamagePctDone(target, m_spellInfo, DOT)); // Calculate done percentage first! + aurEff->SetDamage(caster->SpellDamageBonusDone(target, m_spellInfo, damage, DOT, GetStackAmount()) * aurEff->GetDonePct()); + aurEff->SetCritChance(caster->GetUnitSpellCriticalChance(target, m_spellInfo, m_spellInfo->GetSchoolMask())); + break; } - break; + case SPELL_AURA_PERIODIC_HEAL: + case SPELL_AURA_OBS_MOD_HEALTH: + { + AuraEffect* aurEff = GetEffect(i); + + // ignore non positive values (can be result apply spellmods to aura damage + uint32 damage = std::max(aurEff->GetAmount(), 0); + + // Script Hook For HandlePeriodicDamageAurasTick -- Allow scripts to change the Damage pre class mitigation calculations + sScriptMgr->ModifyPeriodicDamageAurasTick(target, caster, damage); + + aurEff->SetDonePct(caster->SpellHealingPctDone(target, m_spellInfo)); // Calculate done percentage first! + aurEff->SetDamage(caster->SpellHealingBonusDone(target, m_spellInfo, damage, DOT, GetStackAmount()) * aurEff->GetDonePct()); + aurEff->SetCritChance(caster->GetUnitSpellCriticalChance(target, m_spellInfo, m_spellInfo->GetSchoolMask())); + break; + } + default: + break; + } } } @@ -1536,13 +1601,19 @@ bool Aura::CanStackWith(Aura const* existingAura) const return false; // check spell group stack rules - SpellGroupStackRule stackRule = sSpellMgr->CheckSpellGroupStackRules(m_spellInfo, existingSpellInfo); - if (stackRule) + switch (sSpellMgr->CheckSpellGroupStackRules(m_spellInfo, existingSpellInfo)) { - if (stackRule == SPELL_GROUP_STACK_RULE_EXCLUSIVE) - return false; - if (sameCaster && stackRule == SPELL_GROUP_STACK_RULE_EXCLUSIVE_FROM_SAME_CASTER) + case SPELL_GROUP_STACK_RULE_EXCLUSIVE: + case SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST: // if it reaches this point, existing aura is lower/equal return false; + case SPELL_GROUP_STACK_RULE_EXCLUSIVE_FROM_SAME_CASTER: + if (sameCaster) + return false; + break; + case SPELL_GROUP_STACK_RULE_DEFAULT: + case SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT: + default: + break; } if (m_spellInfo->SpellFamilyName != existingSpellInfo->SpellFamilyName) diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h index f62b1ff47b4..8c426ea2175 100644 --- a/src/server/game/Spells/Auras/SpellAuras.h +++ b/src/server/game/Spells/Auras/SpellAuras.h @@ -129,7 +129,7 @@ class Aura int32 CalcMaxDuration(Unit* caster) const; int32 GetDuration() const { return m_duration; } void SetDuration(int32 duration, bool withMods = false); - void RefreshDuration(); + void RefreshDuration(bool withMods = false); void RefreshTimers(); bool IsExpired() const { return !GetDuration();} bool IsPermanent() const { return GetMaxDuration() == -1; } @@ -149,6 +149,7 @@ class Aura uint8 GetCasterLevel() const { return m_casterLevel; } + bool HasMoreThanOneEffectForType(AuraType auraType) const; bool IsArea() const; bool IsPassive() const; bool IsDeathPersistent() const; @@ -190,6 +191,7 @@ class Aura void SetNeedClientUpdateForTargets() const; void HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, bool apply, bool onReapply); + void HandleAuraSpecificPeriodics(AuraApplication const* aurApp, Unit* caster); bool CanBeAppliedOn(Unit* target); bool CheckAreaTarget(Unit* target); bool CanStackWith(Aura const* existingAura) const; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index b64ee454e2e..b884dc0a02a 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -2346,7 +2346,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) // Do healing and triggers if (m_healing > 0) { - bool crit = caster->isSpellCrit(unitTarget, m_spellInfo, m_spellSchoolMask); + bool crit = caster->IsSpellCrit(unitTarget, m_spellInfo, m_spellSchoolMask); uint32 addhealth = m_healing; if (crit) { @@ -2598,10 +2598,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA { // Haste modifies duration of channeled spells if (m_spellInfo->IsChanneled()) - { - if (m_spellInfo->AttributesEx5 & SPELL_ATTR5_HASTE_AFFECT_DURATION) - m_originalCaster->ModSpellCastTime(aurSpellInfo, duration, this); - } + m_originalCaster->ModSpellCastTime(aurSpellInfo, duration, this); else if (m_spellInfo->AttributesEx5 & SPELL_ATTR5_HASTE_AFFECT_DURATION) { int32 origDuration = duration; @@ -3242,9 +3239,9 @@ void Spell::handle_immediate() // Apply duration mod if (Player* modOwner = m_caster->GetSpellModOwner()) modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration); + // Apply haste mods - if (m_spellInfo->AttributesEx5 & SPELL_ATTR5_HASTE_AFFECT_DURATION) - m_caster->ModSpellCastTime(m_spellInfo, duration, this); + m_caster->ModSpellCastTime(m_spellInfo, duration, this); m_spellState = SPELL_STATE_CASTING; m_caster->AddInterruptMask(m_spellInfo->ChannelInterruptFlags); @@ -3770,7 +3767,7 @@ void Spell::SendSpellStart() castFlags |= CAST_FLAG_POWER_LEFT_SELF; if (m_spellInfo->RuneCostID && m_spellInfo->PowerType == POWER_RUNES) - castFlags |= CAST_FLAG_UNKNOWN_19; + castFlags |= CAST_FLAG_NO_GCD; // not needed, but Blizzard sends it WorldPacket data(SMSG_SPELL_START, (8+8+4+4+2)); if (m_CastItem) @@ -3859,21 +3856,22 @@ void Spell::SendSpellGo() if ((m_caster->GetTypeId() == TYPEID_PLAYER) && (m_caster->getClass() == CLASS_DEATH_KNIGHT) && m_spellInfo->RuneCostID - && m_spellInfo->PowerType == POWER_RUNES) + && m_spellInfo->PowerType == POWER_RUNES + && !(_triggeredCastFlags & TRIGGERED_IGNORE_POWER_AND_REAGENT_COST)) { - castFlags |= CAST_FLAG_UNKNOWN_19; // same as in SMSG_SPELL_START + castFlags |= CAST_FLAG_NO_GCD; // not needed, but Blizzard sends it castFlags |= CAST_FLAG_RUNE_LIST; // rune cooldowns list } if (m_spellInfo->HasEffect(SPELL_EFFECT_ACTIVATE_RUNE)) - { castFlags |= CAST_FLAG_RUNE_LIST; // rune cooldowns list - castFlags |= CAST_FLAG_UNKNOWN_19; // same as in SMSG_SPELL_START - } if (m_targets.HasTraj()) castFlags |= CAST_FLAG_ADJUST_MISSILE; + if (!m_spellInfo->StartRecoveryTime) + castFlags |= CAST_FLAG_NO_GCD; + WorldPacket data(SMSG_SPELL_GO, 50); // guess size if (m_CastItem) @@ -6758,7 +6756,7 @@ void Spell::DoAllEffectOnLaunchTarget(TargetInfo& targetInfo, float* multiplier) } } - targetInfo.crit = m_caster->isSpellCrit(unit, m_spellInfo, m_spellSchoolMask, m_attackType); + targetInfo.crit = m_caster->IsSpellCrit(unit, m_spellInfo, m_spellSchoolMask, m_attackType); } SpellCastResult Spell::CanOpenLock(uint32 effIndex, uint32 lockId, SkillType& skillId, int32& reqSkillValue, int32& skillValue) diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index 2b026b77160..ae5bba9ed1a 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -57,7 +57,7 @@ enum SpellCastFlags CAST_FLAG_UNKNOWN_16 = 0x00008000, CAST_FLAG_UNKNOWN_17 = 0x00010000, CAST_FLAG_ADJUST_MISSILE = 0x00020000, - CAST_FLAG_UNKNOWN_19 = 0x00040000, + CAST_FLAG_NO_GCD = 0x00040000, // no GCD for spell casts from charm/summon (vehicle spells is an example) CAST_FLAG_VISUAL_CHAIN = 0x00080000, CAST_FLAG_UNKNOWN_21 = 0x00100000, CAST_FLAG_RUNE_LIST = 0x00200000, diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index d3257f29906..bdfe78d941a 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -960,7 +960,7 @@ void Spell::EffectTeleportUnits(SpellEffIndex /*effIndex*/) TC_LOG_DEBUG("spells", "Spell::EffectTeleportUnits - teleport unit to %u %f %f %f %f\n", mapid, x, y, z, orientation); if (unitTarget->GetTypeId() == TYPEID_PLAYER) - unitTarget->ToPlayer()->TeleportTo(mapid, x, y, z, orientation, unitTarget == m_caster ? TELE_TO_SPELL : 0); + unitTarget->ToPlayer()->TeleportTo(mapid, x, y, z, orientation, unitTarget == m_caster ? TELE_TO_SPELL | TELE_TO_NOT_LEAVE_COMBAT : 0); else if (mapid == unitTarget->GetMapId()) unitTarget->NearTeleportTo(x, y, z, orientation, unitTarget == m_caster); else @@ -1594,6 +1594,12 @@ void Spell::EffectEnergize(SpellEffIndex effIndex) Powers power = Powers(m_spellInfo->Effects[effIndex].MiscValue); + if (unitTarget->GetTypeId() == TYPEID_PLAYER && unitTarget->getPowerType() != power && !(m_spellInfo->AttributesEx7 & SPELL_ATTR7_CAN_RESTORE_SECONDARY_POWER)) + return; + + if (unitTarget->GetMaxPower(power) == 0) + return; + // Some level depends spells int level_multiplier = 0; int level_diff = 0; @@ -1633,9 +1639,6 @@ void Spell::EffectEnergize(SpellEffIndex effIndex) if (damage < 0 && power != POWER_ECLIPSE) return; - if (unitTarget->GetMaxPower(power) == 0) - return; - m_caster->EnergizeBySpell(unitTarget, m_spellInfo->Id, damage, power); // Mad Alchemist's Potion @@ -1700,6 +1703,9 @@ void Spell::EffectEnergizePct(SpellEffIndex effIndex) Powers power = Powers(m_spellInfo->Effects[effIndex].MiscValue); + if (unitTarget->GetTypeId() == TYPEID_PLAYER && unitTarget->getPowerType() != power && !(m_spellInfo->AttributesEx7 & SPELL_ATTR7_CAN_RESTORE_SECONDARY_POWER)) + return; + uint32 maxPower = unitTarget->GetMaxPower(power); if (maxPower == 0) return; @@ -3754,26 +3760,6 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex) } break; } - case SPELLFAMILY_DEATHKNIGHT: - { - // Pestilence - if (m_spellInfo->SpellFamilyFlags[1]&0x10000) - { - // Get diseases on target of spell - if (m_targets.GetUnitTarget() && // Glyph of Disease - cast on unit target too to refresh aura - (m_targets.GetUnitTarget() != unitTarget || m_caster->GetAura(63334))) - { - // And spread them on target - // Blood Plague - if (m_targets.GetUnitTarget()->GetAura(55078)) - m_caster->CastSpell(unitTarget, 55078, true); - // Frost Fever - if (m_targets.GetUnitTarget()->GetAura(55095)) - m_caster->CastSpell(unitTarget, 55095, true); - } - } - break; - } } // normal DB scripted effect diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 277d2b701c4..09bb154106b 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -768,6 +768,15 @@ SpellGroupStackRule SpellMgr::CheckSpellGroupStackRules(SpellInfo const* spellIn return rule; } +SpellGroupStackRule SpellMgr::GetSpellGroupStackRule(SpellGroup group) const +{ + SpellGroupStackMap::const_iterator itr = mSpellGroupStack.find(group); + if (itr != mSpellGroupStack.end()) + return itr->second; + + return SPELL_GROUP_STACK_RULE_DEFAULT; +} + SpellProcEventEntry const* SpellMgr::GetSpellProcEvent(uint32 spellId) const { SpellProcEventMap::const_iterator itr = mSpellProcEventMap.find(spellId); diff --git a/src/server/game/Spells/SpellMgr.h b/src/server/game/Spells/SpellMgr.h index 29bfd33f704..4f6364cf036 100644 --- a/src/server/game/Spells/SpellMgr.h +++ b/src/server/game/Spells/SpellMgr.h @@ -347,14 +347,14 @@ typedef std::pair<SpellGroupSpellMap::const_iterator, SpellGroupSpellMap::const_ enum SpellGroupStackRule { - SPELL_GROUP_STACK_RULE_DEFAULT = 0, - SPELL_GROUP_STACK_RULE_EXCLUSIVE = 1, - SPELL_GROUP_STACK_RULE_EXCLUSIVE_FROM_SAME_CASTER = 2, - SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT = 3 + SPELL_GROUP_STACK_RULE_DEFAULT, + SPELL_GROUP_STACK_RULE_EXCLUSIVE, + SPELL_GROUP_STACK_RULE_EXCLUSIVE_FROM_SAME_CASTER, + SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT, + SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST, + SPELL_GROUP_STACK_RULE_MAX }; -#define SPELL_GROUP_STACK_RULE_MAX 4 - typedef std::map<SpellGroup, SpellGroupStackRule> SpellGroupStackMap; struct SpellThreatEntry @@ -655,6 +655,7 @@ class SpellMgr // Spell Group Stack Rules table bool AddSameEffectStackRuleSpellGroups(SpellInfo const* spellInfo, int32 amount, std::map<SpellGroup, int32>& groups) const; SpellGroupStackRule CheckSpellGroupStackRules(SpellInfo const* spellInfo1, SpellInfo const* spellInfo2) const; + SpellGroupStackRule GetSpellGroupStackRule(SpellGroup groupid) const; // Spell proc event table SpellProcEventEntry const* GetSpellProcEvent(uint32 spellId) const; diff --git a/src/server/game/Warden/WardenWin.cpp b/src/server/game/Warden/WardenWin.cpp index 18bf2897358..3428708ed69 100644 --- a/src/server/game/Warden/WardenWin.cpp +++ b/src/server/game/Warden/WardenWin.cpp @@ -16,7 +16,7 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "Cryptography/HMACSHA1.h" +#include "Cryptography/HmacHash.h" #include "Cryptography/WardenKeyGeneration.h" #include "Common.h" #include "WorldPacket.h" @@ -283,7 +283,7 @@ void WardenWin::RequestData() { uint32 seed = static_cast<uint32>(rand32()); buff << uint32(seed); - HmacHash hmac(4, (uint8*)&seed); + HmacSha1 hmac(4, (uint8*)&seed); hmac.UpdateData(wd->Str); hmac.Finalize(); buff.append(hmac.GetDigest(), hmac.GetLength()); diff --git a/src/server/scripts/Commands/cs_account.cpp b/src/server/scripts/Commands/cs_account.cpp index 3c9714ca55a..3406c25eb16 100644 --- a/src/server/scripts/Commands/cs_account.cpp +++ b/src/server/scripts/Commands/cs_account.cpp @@ -126,10 +126,9 @@ public: if (!accountName || !password) return false; - AccountOpResult result = sAccountMgr->CreateAccount(std::string(accountName), std::string(password), email); - switch (result) + switch (sAccountMgr->CreateAccount(std::string(accountName), std::string(password), email)) { - case AOR_OK: + case AccountOpResult::AOR_OK: handler->PSendSysMessage(LANG_ACCOUNT_CREATED, accountName); if (handler->GetSession()) { @@ -139,15 +138,15 @@ public: accountName, email.c_str()); } break; - case AOR_NAME_TOO_LONG: + case AccountOpResult::AOR_NAME_TOO_LONG: handler->SendSysMessage(LANG_ACCOUNT_TOO_LONG); handler->SetSentErrorMessage(true); return false; - case AOR_NAME_ALREADY_EXIST: + case AccountOpResult::AOR_NAME_ALREADY_EXIST: handler->SendSysMessage(LANG_ACCOUNT_ALREADY_EXIST); handler->SetSentErrorMessage(true); return false; - case AOR_DB_INTERNAL_ERROR: + case AccountOpResult::AOR_DB_INTERNAL_ERROR: handler->PSendSysMessage(LANG_ACCOUNT_NOT_CREATED_SQL_ERROR, accountName); handler->SetSentErrorMessage(true); return false; @@ -173,7 +172,7 @@ public: return false; std::string accountName = account; - if (!AccountMgr::normalizeString(accountName)) + if (!Utf8ToUpperOnlyLatin(accountName)) { handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); handler->SetSentErrorMessage(true); @@ -197,14 +196,14 @@ public: AccountOpResult result = AccountMgr::DeleteAccount(accountId); switch (result) { - case AOR_OK: + case AccountOpResult::AOR_OK: handler->PSendSysMessage(LANG_ACCOUNT_DELETED, accountName.c_str()); break; - case AOR_NAME_NOT_EXIST: + case AccountOpResult::AOR_NAME_NOT_EXIST: handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); handler->SetSentErrorMessage(true); return false; - case AOR_DB_INTERNAL_ERROR: + case AccountOpResult::AOR_DB_INTERNAL_ERROR: handler->PSendSysMessage(LANG_ACCOUNT_NOT_DELETED_SQL_ERROR, accountName.c_str()); handler->SetSentErrorMessage(true); return false; @@ -416,14 +415,14 @@ public: AccountOpResult result = AccountMgr::ChangeEmail(handler->GetSession()->GetAccountId(), std::string(email)); switch (result) { - case AOR_OK: + case AccountOpResult::AOR_OK: handler->SendSysMessage(LANG_COMMAND_EMAIL); TC_LOG_INFO("entities.player.character", "Account: %u (IP: %s) Character:[%s] (GUID: %u) Changed Email from [%s] to [%s].", handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress().c_str(), handler->GetSession()->GetPlayer()->GetName().c_str(), handler->GetSession()->GetPlayer()->GetGUIDLow(), oldEmail, email); break; - case AOR_EMAIL_TOO_LONG: + case AccountOpResult::AOR_EMAIL_TOO_LONG: handler->SendSysMessage(LANG_EMAIL_TOO_LONG); handler->SetSentErrorMessage(true); return false; @@ -501,13 +500,13 @@ public: AccountOpResult result = AccountMgr::ChangePassword(handler->GetSession()->GetAccountId(), std::string(newPassword)); switch (result) { - case AOR_OK: + case AccountOpResult::AOR_OK: handler->SendSysMessage(LANG_COMMAND_PASSWORD); TC_LOG_INFO("entities.player.character", "Account: %u (IP: %s) Character:[%s] (GUID: %u) Changed Password.", handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress().c_str(), handler->GetSession()->GetPlayer()->GetName().c_str(), handler->GetSession()->GetPlayer()->GetGUIDLow()); break; - case AOR_PASS_TOO_LONG: + case AccountOpResult::AOR_PASS_TOO_LONG: handler->SendSysMessage(LANG_PASSWORD_TOO_LONG); handler->SetSentErrorMessage(true); return false; @@ -586,7 +585,7 @@ public: { ///- Convert Account name to Upper Format accountName = account; - if (!AccountMgr::normalizeString(accountName)) + if (!Utf8ToUpperOnlyLatin(accountName)) { handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); handler->SetSentErrorMessage(true); @@ -656,7 +655,7 @@ public: if (isAccountNameGiven) { targetAccountName = arg1; - if (!AccountMgr::normalizeString(targetAccountName)) + if (!Utf8ToUpperOnlyLatin(targetAccountName)) { handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, targetAccountName.c_str()); handler->SetSentErrorMessage(true); @@ -744,7 +743,7 @@ public: return false; std::string accountName = account; - if (!AccountMgr::normalizeString(accountName)) + if (!Utf8ToUpperOnlyLatin(accountName)) { handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); handler->SetSentErrorMessage(true); @@ -775,14 +774,14 @@ public: switch (result) { - case AOR_OK: + case AccountOpResult::AOR_OK: handler->SendSysMessage(LANG_COMMAND_PASSWORD); break; - case AOR_NAME_NOT_EXIST: + case AccountOpResult::AOR_NAME_NOT_EXIST: handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); handler->SetSentErrorMessage(true); return false; - case AOR_PASS_TOO_LONG: + case AccountOpResult::AOR_PASS_TOO_LONG: handler->SendSysMessage(LANG_PASSWORD_TOO_LONG); handler->SetSentErrorMessage(true); return false; @@ -813,7 +812,7 @@ public: } std::string accountName = account; - if (!AccountMgr::normalizeString(accountName)) + if (!Utf8ToUpperOnlyLatin(accountName)) { handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); handler->SetSentErrorMessage(true); @@ -843,16 +842,16 @@ public: AccountOpResult result = AccountMgr::ChangeEmail(targetAccountId, email); switch (result) { - case AOR_OK: + case AccountOpResult::AOR_OK: handler->SendSysMessage(LANG_COMMAND_EMAIL); TC_LOG_INFO("entities.player.character", "ChangeEmail: Account %s [Id: %u] had it's email changed to %s.", accountName.c_str(), targetAccountId, email); break; - case AOR_NAME_NOT_EXIST: + case AccountOpResult::AOR_NAME_NOT_EXIST: handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); handler->SetSentErrorMessage(true); return false; - case AOR_EMAIL_TOO_LONG: + case AccountOpResult::AOR_EMAIL_TOO_LONG: handler->SendSysMessage(LANG_EMAIL_TOO_LONG); handler->SetSentErrorMessage(true); return false; @@ -889,7 +888,7 @@ public: } std::string accountName = account; - if (!AccountMgr::normalizeString(accountName)) + if (!Utf8ToUpperOnlyLatin(accountName)) { handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); handler->SetSentErrorMessage(true); @@ -919,16 +918,16 @@ public: AccountOpResult result = AccountMgr::ChangeRegEmail(targetAccountId, email); switch (result) { - case AOR_OK: + case AccountOpResult::AOR_OK: handler->SendSysMessage(LANG_COMMAND_EMAIL); TC_LOG_INFO("entities.player.character", "ChangeRegEmail: Account %s [Id: %u] had it's Registration Email changed to %s.", accountName.c_str(), targetAccountId, email); break; - case AOR_NAME_NOT_EXIST: + case AccountOpResult::AOR_NAME_NOT_EXIST: handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); handler->SetSentErrorMessage(true); return false; - case AOR_EMAIL_TOO_LONG: + case AccountOpResult::AOR_EMAIL_TOO_LONG: handler->SendSysMessage(LANG_EMAIL_TOO_LONG); handler->SetSentErrorMessage(true); return false; diff --git a/src/server/scripts/Commands/cs_ban.cpp b/src/server/scripts/Commands/cs_ban.cpp index afaf5f651bc..ab962b69869 100644 --- a/src/server/scripts/Commands/cs_ban.cpp +++ b/src/server/scripts/Commands/cs_ban.cpp @@ -174,7 +174,7 @@ public: switch (mode) { case BAN_ACCOUNT: - if (!AccountMgr::normalizeString(nameOrIP)) + if (!Utf8ToUpperOnlyLatin(nameOrIP)) { handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, nameOrIP.c_str()); handler->SetSentErrorMessage(true); @@ -245,7 +245,7 @@ public: return false; std::string accountName = nameStr; - if (!AccountMgr::normalizeString(accountName)) + if (!Utf8ToUpperOnlyLatin(accountName)) { handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); handler->SetSentErrorMessage(true); @@ -710,7 +710,7 @@ public: switch (mode) { case BAN_ACCOUNT: - if (!AccountMgr::normalizeString(nameOrIP)) + if (!Utf8ToUpperOnlyLatin(nameOrIP)) { handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, nameOrIP.c_str()); handler->SetSentErrorMessage(true); diff --git a/src/server/scripts/Commands/cs_battlenet_account.cpp b/src/server/scripts/Commands/cs_battlenet_account.cpp new file mode 100644 index 00000000000..dfbff501144 --- /dev/null +++ b/src/server/scripts/Commands/cs_battlenet_account.cpp @@ -0,0 +1,336 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "BattlenetAccountMgr.h" +#include "AccountMgr.h" +#include "Chat.h" +#include "Language.h" +#include "Player.h" +#include "ScriptMgr.h" + +class battlenet_account_commandscript : public CommandScript +{ +public: + battlenet_account_commandscript() : CommandScript("battlenet_account_commandscript") { } + + ChatCommand* GetCommands() const override + { + static ChatCommand accountSetCommandTable[] = + { + { "password", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT_SET_PASSWORD, true, &HandleAccountSetPasswordCommand, "", NULL }, + { NULL, 0, false, NULL, "", NULL } + }; + + static ChatCommand accountLockCommandTable[] = + { + { "country", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT_LOCK_COUNTRY, true, &HandleAccountLockCountryCommand, "", NULL }, + { "ip", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT_LOCK_IP, true, &HandleAccountLockIpCommand, "", NULL }, + { NULL, 0, false, NULL, "", NULL } + }; + + static ChatCommand accountCommandTable[] = + { + { "create", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT_CREATE, true, &HandleAccountCreateCommand, "", NULL }, + { "lock", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT, false, NULL, "", accountLockCommandTable }, + { "set", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT_SET, true, NULL, "", accountSetCommandTable }, + { "password", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT_PASSWORD, false, &HandleAccountPasswordCommand, "", NULL }, + { NULL, 0, false, NULL, "", NULL } + }; + + static ChatCommand commandTable[] = + { + { "battlenetaccount", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT, true, NULL, "", accountCommandTable }, + { NULL, 0, false, NULL, "", NULL } + }; + + return commandTable; + } + + /// Create an account + static bool HandleAccountCreateCommand(ChatHandler* handler, char const* args) + { + if (!*args) + return false; + + std::string email; + + ///- %Parse the command line arguments + char* accountName = strtok((char*)args, " "); + char* password = strtok(NULL, " "); + if (!accountName || !password) + return false; + + if (!strchr(accountName, '@')) + { + handler->SendSysMessage(LANG_ACCOUNT_INVALID_BNET_NAME); + handler->SetSentErrorMessage(true); + return false; + } + + switch (Battlenet::AccountMgr::CreateBattlenetAccount(std::string(accountName), std::string(password))) + { + case AccountOpResult::AOR_OK: + handler->PSendSysMessage(LANG_ACCOUNT_CREATED, accountName); + if (handler->GetSession()) + { + TC_LOG_INFO("entities.player.character", "Battle.net account: %d (IP: %s) Character:[%s] (GUID: %u) created Account %s", + handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress().c_str(), + handler->GetSession()->GetPlayer()->GetName().c_str(), handler->GetSession()->GetPlayer()->GetGUIDLow(), + accountName); + } + break; + case AccountOpResult::AOR_NAME_TOO_LONG: + handler->SendSysMessage(LANG_ACCOUNT_TOO_LONG); + handler->SetSentErrorMessage(true); + return false; + case AccountOpResult::AOR_NAME_ALREADY_EXIST: + handler->SendSysMessage(LANG_ACCOUNT_ALREADY_EXIST); + handler->SetSentErrorMessage(true); + return false; + case AccountOpResult::AOR_PASS_TOO_LONG: + handler->SendSysMessage(LANG_PASSWORD_TOO_LONG); + handler->SetSentErrorMessage(true); + return false; + default: + break; + } + + return true; + } + + // Sets country lock on own account + static bool HandleAccountLockCountryCommand(ChatHandler* handler, char const* args) + { + if (!*args) + { + handler->SendSysMessage(LANG_USE_BOL); + handler->SetSentErrorMessage(true); + return false; + } + + std::string param = (char*)args; + if (!param.empty()) + { + if (param == "on") + { + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LOGON_COUNTRY); + uint32 ip = inet_addr(handler->GetSession()->GetRemoteAddress().c_str()); + EndianConvertReverse(ip); + stmt->setUInt32(0, ip); + PreparedQueryResult result = LoginDatabase.Query(stmt); + if (result) + { + Field* fields = result->Fetch(); + std::string country = fields[0].GetString(); + stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_ACCOUNT_LOCK_CONTRY); + stmt->setString(0, country); + stmt->setUInt32(1, handler->GetSession()->GetBattlenetAccountId()); + LoginDatabase.Execute(stmt); + handler->PSendSysMessage(LANG_COMMAND_ACCLOCKLOCKED); + } + else + { + handler->PSendSysMessage("[IP2NATION] Table empty"); + TC_LOG_DEBUG("server.authserver", "[IP2NATION] Table empty"); + } + } + else if (param == "off") + { + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_ACCOUNT_LOCK_CONTRY); + stmt->setString(0, "00"); + stmt->setUInt32(1, handler->GetSession()->GetBattlenetAccountId()); + LoginDatabase.Execute(stmt); + handler->PSendSysMessage(LANG_COMMAND_ACCLOCKUNLOCKED); + } + return true; + } + + handler->SendSysMessage(LANG_USE_BOL); + handler->SetSentErrorMessage(true); + return false; + } + + // Sets ip lock on own account + static bool HandleAccountLockIpCommand(ChatHandler* handler, char const* args) + { + if (!*args) + { + handler->SendSysMessage(LANG_USE_BOL); + handler->SetSentErrorMessage(true); + return false; + } + + std::string param = (char*)args; + + if (!param.empty()) + { + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_ACCOUNT_LOCK); + + if (param == "on") + { + stmt->setBool(0, true); // locked + handler->PSendSysMessage(LANG_COMMAND_ACCLOCKLOCKED); + } + else if (param == "off") + { + stmt->setBool(0, false); // unlocked + handler->PSendSysMessage(LANG_COMMAND_ACCLOCKUNLOCKED); + } + + stmt->setUInt32(1, handler->GetSession()->GetBattlenetAccountId()); + + LoginDatabase.Execute(stmt); + return true; + } + + handler->SendSysMessage(LANG_USE_BOL); + handler->SetSentErrorMessage(true); + return false; + } + + static bool HandleAccountPasswordCommand(ChatHandler* handler, char const* args) + { + // If no args are given at all, we can return false right away. + if (!*args) + { + handler->SendSysMessage(LANG_CMD_SYNTAX); + handler->SetSentErrorMessage(true); + return false; + } + + // Command is supposed to be: .account password [$oldpassword] [$newpassword] [$newpasswordconfirmation] [$emailconfirmation] + char* oldPassword = strtok((char*)args, " "); // This extracts [$oldpassword] + char* newPassword = strtok(NULL, " "); // This extracts [$newpassword] + char* passwordConfirmation = strtok(NULL, " "); // This extracts [$newpasswordconfirmation] + + //Is any of those variables missing for any reason ? We return false. + if (!oldPassword || !newPassword || !passwordConfirmation) + { + handler->SendSysMessage(LANG_CMD_SYNTAX); + handler->SetSentErrorMessage(true); + return false; + } + + // We compare the old, saved password to the entered old password - no chance for the unauthorized. + if (!Battlenet::AccountMgr::CheckPassword(handler->GetSession()->GetAccountId(), std::string(oldPassword))) + { + handler->SendSysMessage(LANG_COMMAND_WRONGOLDPASSWORD); + handler->SetSentErrorMessage(true); + TC_LOG_INFO("entities.player.character", "Battle.net account: %u (IP: %s) Character:[%s] (GUID: %u) Tried to change password, but the provided old password is wrong.", + handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress().c_str(), + handler->GetSession()->GetPlayer()->GetName().c_str(), handler->GetSession()->GetPlayer()->GetGUIDLow()); + return false; + } + + // Making sure that newly entered password is correctly entered. + if (strcmp(newPassword, passwordConfirmation) != 0) + { + handler->SendSysMessage(LANG_NEW_PASSWORDS_NOT_MATCH); + handler->SetSentErrorMessage(true); + return false; + } + + // Changes password and prints result. + AccountOpResult result = Battlenet::AccountMgr::ChangePassword(handler->GetSession()->GetBattlenetAccountId(), std::string(newPassword)); + switch (result) + { + case AccountOpResult::AOR_OK: + handler->SendSysMessage(LANG_COMMAND_PASSWORD); + TC_LOG_INFO("entities.player.character", "Battle.net account: %u (IP: %s) Character:[%s] (GUID: %u) Changed Password.", + handler->GetSession()->GetBattlenetAccountId(), handler->GetSession()->GetRemoteAddress().c_str(), + handler->GetSession()->GetPlayer()->GetName().c_str(), handler->GetSession()->GetPlayer()->GetGUIDLow()); + break; + case AccountOpResult::AOR_PASS_TOO_LONG: + handler->SendSysMessage(LANG_PASSWORD_TOO_LONG); + handler->SetSentErrorMessage(true); + return false; + default: + handler->SendSysMessage(LANG_COMMAND_NOTCHANGEPASSWORD); + handler->SetSentErrorMessage(true); + return false; + } + + return true; + } + + /// Set password for account + static bool HandleAccountSetPasswordCommand(ChatHandler* handler, char const* args) + { + if (!*args) + { + handler->SendSysMessage(LANG_CMD_SYNTAX); + handler->SetSentErrorMessage(true); + return false; + } + + ///- Get the command line arguments + char* account = strtok((char*)args, " "); + char* password = strtok(NULL, " "); + char* passwordConfirmation = strtok(NULL, " "); + + if (!account || !password || !passwordConfirmation) + return false; + + std::string accountName = account; + if (!Utf8ToUpperOnlyLatin(accountName)) + { + handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); + handler->SetSentErrorMessage(true); + return false; + } + + uint32 targetAccountId = Battlenet::AccountMgr::GetId(accountName); + if (!targetAccountId) + { + handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); + handler->SetSentErrorMessage(true); + return false; + } + + if (strcmp(password, passwordConfirmation)) + { + handler->SendSysMessage(LANG_NEW_PASSWORDS_NOT_MATCH); + handler->SetSentErrorMessage(true); + return false; + } + + AccountOpResult result = Battlenet::AccountMgr::ChangePassword(targetAccountId, password); + + switch (result) + { + case AccountOpResult::AOR_OK: + handler->SendSysMessage(LANG_COMMAND_PASSWORD); + break; + case AccountOpResult::AOR_NAME_NOT_EXIST: + handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); + handler->SetSentErrorMessage(true); + return false; + case AccountOpResult::AOR_PASS_TOO_LONG: + handler->SendSysMessage(LANG_PASSWORD_TOO_LONG); + handler->SetSentErrorMessage(true); + return false; + default: + break; + } + return true; + } +}; + +void AddSC_battlenet_account_commandscript() +{ + new battlenet_account_commandscript(); +} diff --git a/src/server/scripts/Commands/cs_character.cpp b/src/server/scripts/Commands/cs_character.cpp index ffdc9deeae3..0c6d495a360 100644 --- a/src/server/scripts/Commands/cs_character.cpp +++ b/src/server/scripts/Commands/cs_character.cpp @@ -858,7 +858,7 @@ public: return false; std::string accountName = accountStr; - if (!AccountMgr::normalizeString(accountName)) + if (!Utf8ToUpperOnlyLatin(accountName)) { handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); handler->SetSentErrorMessage(true); diff --git a/src/server/scripts/Commands/cs_lookup.cpp b/src/server/scripts/Commands/cs_lookup.cpp index 15d065f127e..64829a46a05 100644 --- a/src/server/scripts/Commands/cs_lookup.cpp +++ b/src/server/scripts/Commands/cs_lookup.cpp @@ -1218,8 +1218,7 @@ public: char* limitStr = strtok(NULL, " "); int32 limit = limitStr ? atoi(limitStr) : -1; - if (!AccountMgr::normalizeString - (account)) + if (!Utf8ToUpperOnlyLatin(account)) return false; PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_LIST_BY_NAME); diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp index 7833b3b5e5d..84716ad9590 100644 --- a/src/server/scripts/Commands/cs_npc.cpp +++ b/src/server/scripts/Commands/cs_npc.cpp @@ -43,6 +43,7 @@ struct EnumName #define CREATE_NAMED_ENUM(VALUE) { VALUE, STRINGIZE(VALUE) } #define NPCFLAG_COUNT 24 +#define FLAGS_EXTRA_COUNT 16 EnumName<NPCFlags, int32> const npcFlagTexts[NPCFLAG_COUNT] = { @@ -145,6 +146,26 @@ EnumName<UnitFlags> const unitFlags[MAX_UNIT_FLAGS] = CREATE_NAMED_ENUM(UNIT_FLAG_UNK_31) }; +EnumName<CreatureFlagsExtra> const flagsExtra[FLAGS_EXTRA_COUNT] = +{ + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_INSTANCE_BIND), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_CIVILIAN), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_PARRY), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_BLOCK), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_CRUSH), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_XP_AT_KILL), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_TRIGGER), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_TAUNT), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_WORLDEVENT), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_GUARD), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_CRIT), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_SKILLGAIN), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_TAUNT_DIMINISH), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_ALL_DIMINISH), + CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_DUNGEON_BOSS) +}; + class npc_commandscript : public CommandScript { public: @@ -738,6 +759,10 @@ public: handler->PSendSysMessage(LANG_NPCINFO_ARMOR, target->GetArmor()); handler->PSendSysMessage(LANG_NPCINFO_POSITION, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ()); handler->PSendSysMessage(LANG_NPCINFO_AIINFO, target->GetAIName().c_str(), target->GetScriptName().c_str()); + handler->PSendSysMessage(LANG_NPCINFO_FLAGS_EXTRA, cInfo->flags_extra); + for (uint8 i = 0; i < FLAGS_EXTRA_COUNT; ++i) + if (cInfo->flags_extra & flagsExtra[i].Value) + handler->PSendSysMessage("%s (0x%X)", flagsExtra[i].Name, flagsExtra[i].Value); for (uint8 i = 0; i < NPCFLAG_COUNT; i++) if (npcflags & npcFlagTexts[i].Value) diff --git a/src/server/scripts/Commands/cs_rbac.cpp b/src/server/scripts/Commands/cs_rbac.cpp index 47fa01837f6..080e868a924 100644 --- a/src/server/scripts/Commands/cs_rbac.cpp +++ b/src/server/scripts/Commands/cs_rbac.cpp @@ -142,7 +142,7 @@ public: {
accountName = param1;
- if (AccountMgr::normalizeString(accountName))
+ if (Utf8ToUpperOnlyLatin(accountName))
accountId = AccountMgr::GetId(accountName);
if (!accountId)
diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_golemagg.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_golemagg.cpp index 2a473754ce6..f9757997731 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_golemagg.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_golemagg.cpp @@ -144,7 +144,7 @@ class npc_core_rager : public CreatureScript if (HealthAbovePct(50) || !instance) return; - if (Creature* pGolemagg = instance->instance->GetCreature(instance->GetData64(BOSS_GOLEMAGG_THE_INCINERATOR))) + if (Creature* pGolemagg = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_GOLEMAGG_THE_INCINERATOR))) { if (pGolemagg->IsAlive()) { diff --git a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/instance_ahnkahet.cpp b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/instance_ahnkahet.cpp index 4aa59e72556..bf7b4355ea6 100644 --- a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/instance_ahnkahet.cpp +++ b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/instance_ahnkahet.cpp @@ -141,9 +141,9 @@ class instance_ahnkahet : public InstanceMapScript SwitchTrigger = data; break; case DATA_JEDOGA_RESET_INITIANDS: - for (std::set<uint64>::const_iterator itr = InitiandGUIDs.begin(); itr != InitiandGUIDs.end(); ++itr) + for (uint64 guid : InitiandGUIDs) { - if (Creature* creature = instance->GetCreature(*itr)) + if (Creature* creature = instance->GetCreature(guid)) { creature->Respawn(); if (!creature->IsInEvadeMode()) @@ -164,9 +164,9 @@ class instance_ahnkahet : public InstanceMapScript case DATA_SPHERE_2: return SpheresState[type - DATA_SPHERE_1]; case DATA_ALL_INITIAND_DEAD: - for (std::set<uint64>::const_iterator itr = InitiandGUIDs.begin(); itr != InitiandGUIDs.end(); ++itr) + for (uint64 guid : InitiandGUIDs) { - Creature* cr = instance->GetCreature(*itr); + Creature* cr = instance->GetCreature(guid); if (!cr || cr->IsAlive()) return 0; } @@ -214,11 +214,11 @@ class instance_ahnkahet : public InstanceMapScript { std::vector<uint64> vInitiands; vInitiands.clear(); - for (std::set<uint64>::const_iterator itr = InitiandGUIDs.begin(); itr != InitiandGUIDs.end(); ++itr) + for (uint64 guid : InitiandGUIDs) { - Creature* cr = instance->GetCreature(*itr); + Creature* cr = instance->GetCreature(guid); if (cr && cr->IsAlive()) - vInitiands.push_back(*itr); + vInitiands.push_back(guid); } if (vInitiands.empty()) return 0; @@ -245,9 +245,9 @@ class instance_ahnkahet : public InstanceMapScript case DATA_JEDOGA_SHADOWSEEKER: if (state == DONE) { - for (std::set<uint64>::const_iterator itr = InitiandGUIDs.begin(); itr != InitiandGUIDs.end(); ++itr) + for (uint64 guid : InitiandGUIDs) { - if (Creature* cr = instance->GetCreature(*itr)) + if (Creature* cr = instance->GetCreature(guid)) cr->DespawnOrUnsummon(); } } diff --git a/src/server/scripts/Northrend/CMakeLists.txt b/src/server/scripts/Northrend/CMakeLists.txt index aff3c0a9528..8401ea4b9a5 100644 --- a/src/server/scripts/Northrend/CMakeLists.txt +++ b/src/server/scripts/Northrend/CMakeLists.txt @@ -20,7 +20,6 @@ set(scripts_STAT_SRCS Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp Northrend/Ulduar/HallsOfLightning/boss_loken.cpp Northrend/Ulduar/Ulduar/boss_general_vezax.cpp - Northrend/Ulduar/Ulduar/ulduar_teleporter.cpp Northrend/Ulduar/Ulduar/boss_thorim.cpp Northrend/Ulduar/Ulduar/boss_ignis.cpp Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp index 006ef461cab..78e8f2d248e 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp @@ -854,7 +854,6 @@ class npc_halion_controller : public CreatureScript { if (Creature* halion = ObjectAccessor::GetCreature(*me, _instance->GetData64(itr))) { - RemoveCorporeality(halion, itr == DATA_TWILIGHT_HALION); halion->CastSpell(halion, GetSpell(_materialCorporealityValue, itr == DATA_TWILIGHT_HALION), true); if (itr == DATA_TWILIGHT_HALION) @@ -865,19 +864,6 @@ class npc_halion_controller : public CreatureScript } } - void RemoveCorporeality(Creature* who, bool isTwilight = false) - { - for (uint8 i = 0; i < MAX_CORPOREALITY_STATE; i++) - { - uint32 spellID = (isTwilight ? _corporealityReference[i].twilightRealmSpell : _corporealityReference[i].materialRealmSpell); - if (who->HasAura(spellID)) - { - who->RemoveAurasDueToSpell(spellID); - break; - } - } - } - uint32 GetSpell(uint8 pctValue, bool isTwilight = false) const { CorporealityEntry entry = _corporealityReference[pctValue]; diff --git a/src/server/scripts/Northrend/DraktharonKeep/boss_novos.cpp b/src/server/scripts/Northrend/DraktharonKeep/boss_novos.cpp index 63b1359a406..4e9462a447f 100644 --- a/src/server/scripts/Northrend/DraktharonKeep/boss_novos.cpp +++ b/src/server/scripts/Northrend/DraktharonKeep/boss_novos.cpp @@ -208,7 +208,7 @@ public: { for (uint8 i = 0; i < 4; i++) if (uint64 guid = instance->GetData64(summoners[i].data)) - if (Creature* crystalChannelTarget = instance->instance->GetCreature(guid)) + if (Creature* crystalChannelTarget = ObjectAccessor::GetCreature(*me, guid)) { if (active) crystalChannelTarget->AI()->SetData(summoners[i].spell, summoners[i].timer); @@ -221,7 +221,7 @@ public: { for (uint8 i = 0; i < 4; i++) if (uint64 guid = instance->GetData64(DATA_NOVOS_CRYSTAL_1 + i)) - if (GameObject* crystal = instance->instance->GetGameObject(guid)) + if (GameObject* crystal = ObjectAccessor::GetGameObject(*me, guid)) SetCrystalStatus(crystal, active); } @@ -241,7 +241,7 @@ public: { for (uint8 i = 0; i < 4; i++) if (uint64 guid = instance->GetData64(DATA_NOVOS_CRYSTAL_1 + i)) - if (GameObject* crystal = instance->instance->GetGameObject(guid)) + if (GameObject* crystal = ObjectAccessor::GetGameObject(*me, guid)) if (crystal->GetGoState() == GO_STATE_ACTIVE) { SetCrystalStatus(crystal, false); @@ -258,7 +258,7 @@ public: events.ScheduleEvent(EVENT_SUMMON_MINIONS, 15000); } else if (uint64 guid = instance->GetData64(DATA_NOVOS_SUMMONER_4)) - if (Creature* crystalChannelTarget = instance->instance->GetCreature(guid)) + if (Creature* crystalChannelTarget = ObjectAccessor::GetCreature(*me, guid)) crystalChannelTarget->AI()->SetData(SPELL_SUMMON_CRYSTAL_HANDLER, 15000); } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp index 16d1531e890..e1658e564ec 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp @@ -1227,9 +1227,9 @@ class spell_deathbringer_blood_nova_targeting : public SpellScriptLoader if (targets.empty()) return; - // select one random target, with preference of ranged targets + // select one random target, preferring ranged targets uint32 targetsAtRange = 0; - uint32 const minTargets = uint32(GetCaster()->GetMap()->GetSpawnMode() & 1 ? 10 : 4); + uint32 const minTargets = uint32(GetCaster()->GetMap()->Is25ManRaid() ? 10 : 4); targets.sort(Trinity::ObjectDistanceOrderPred(GetCaster(), false)); // get target count at range @@ -1237,18 +1237,12 @@ class spell_deathbringer_blood_nova_targeting : public SpellScriptLoader if ((*itr)->GetDistance(GetCaster()) < 12.0f) break; - // set the upper cap + // If not enough ranged targets are present just select anyone if (targetsAtRange < minTargets) - targetsAtRange = std::min<uint32>(targets.size() - 1, minTargets); - - if (!targetsAtRange) - { - targets.clear(); - return; - } + targetsAtRange = uint32(targets.size()); std::list<WorldObject*>::const_iterator itr = targets.begin(); - std::advance(itr, urand(0, targetsAtRange)); + std::advance(itr, urand(0, targetsAtRange - 1)); target = *itr; targets.clear(); targets.push_back(target); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp index 569a81ee9cc..55c1003ff0c 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp @@ -538,6 +538,11 @@ class boss_the_lich_king : public CreatureScript Trinity::GameObjectWorker<FrozenThroneResetWorker> worker(me, reset); me->VisitNearbyGridObject(333.0f, worker); + // Restore Tirion's gossip only after The Lich King fully resets to prevent + // restarting the encounter while LK still runs back to spawn point + if (Creature* tirion = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HIGHLORD_TIRION_FORDRING))) + tirion->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + // Reset any light override me->GetMap()->SetZoneOverrideLight(AREA_THE_FROZEN_THRONE, 0, 5000); } @@ -1180,11 +1185,6 @@ class npc_tirion_fordring_tft : public CreatureScript void JustReachedHome() override { me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); - - if (_instance->GetBossState(DATA_THE_LICH_KING) == DONE) - return; - - me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); } void UpdateAI(uint32 diff) override diff --git a/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp b/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp index d3b4a285af6..d4f00414b7d 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp @@ -120,7 +120,6 @@ public: } void MoveInLineOfSight(Unit* who) override - { if (!hasTaunted && me->IsWithinDistInMap(who, 60.0f) && who->GetTypeId() == TYPEID_PLAYER) { diff --git a/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp b/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp index 02bafa8d10d..3d42827c0a8 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp @@ -84,7 +84,6 @@ class boss_faerlina : public CreatureScript } void MoveInLineOfSight(Unit* who) override - { if (!_introDone && who->GetTypeId() == TYPEID_PLAYER) { diff --git a/src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp b/src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp index 3a0e3ce7c73..381be8d5cd1 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp @@ -70,7 +70,6 @@ public: } void MoveInLineOfSight(Unit* who) override - { if (who->GetEntry() == NPC_ZOMBIE && me->IsWithinDistInMap(who, 7)) { diff --git a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp index 1331c25de17..e8ed181da5a 100644 --- a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp +++ b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp @@ -368,9 +368,9 @@ class instance_naxxramas : public InstanceMapScript if (i == section) continue; - for (std::set<uint64>::const_iterator itr = HeiganEruptionGUID[i].begin(); itr != HeiganEruptionGUID[i].end(); ++itr) + for (uint64 guid : HeiganEruptionGUID[i]) { - if (GameObject* heiganEruption = instance->GetGameObject(*itr)) + if (GameObject* heiganEruption = instance->GetGameObject(guid)) { heiganEruption->SendCustomAnim(heiganEruption->GetGoAnimProgress()); heiganEruption->CastSpell(NULL, SPELL_ERUPTION); diff --git a/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp b/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp index 80c71771c96..d78a07f5c2b 100644 --- a/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp +++ b/src/server/scripts/Northrend/Nexus/Oculus/instance_oculus.cpp @@ -281,8 +281,8 @@ class instance_oculus : public InstanceMapScript void GreaterWhelps() { - for (std::list<uint64>::const_iterator itr = GreaterWhelpList.begin(); itr != GreaterWhelpList.end(); ++itr) - if (Creature* gwhelp = instance->GetCreature(*itr)) + for (uint64 guid : GreaterWhelpList) + if (Creature* gwhelp = instance->GetCreature(guid)) gwhelp->SetPhaseMask(1, true); } diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_bjarngrim.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_bjarngrim.cpp index 24d145f097f..13ea815febc 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_bjarngrim.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_bjarngrim.cpp @@ -164,11 +164,9 @@ public: for (uint8 i = 0; i < 2; ++i) { - if (Creature* pStormforgedLieutenant = (ObjectAccessor::GetCreature((*me), m_auiStormforgedLieutenantGUID[i]))) - { + if (Creature* pStormforgedLieutenant = ObjectAccessor::GetCreature(*me, m_auiStormforgedLieutenantGUID[i])) if (!pStormforgedLieutenant->IsAlive()) pStormforgedLieutenant->Respawn(); - } } if (m_uiStance != STANCE_DEFENSIVE) @@ -411,7 +409,7 @@ public: void EnterCombat(Unit* who) override { - if (Creature* pBjarngrim = instance->instance->GetCreature(instance->GetData64(DATA_BJARNGRIM))) + if (Creature* pBjarngrim = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_BJARNGRIM))) { if (pBjarngrim->IsAlive() && !pBjarngrim->GetVictim()) pBjarngrim->AI()->AttackStart(who); @@ -434,7 +432,7 @@ public: if (m_uiRenewSteel_Timer <= uiDiff) { - if (Creature* pBjarngrim = instance->instance->GetCreature(instance->GetData64(DATA_BJARNGRIM))) + if (Creature* pBjarngrim = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_BJARNGRIM))) { if (pBjarngrim->IsAlive()) DoCast(pBjarngrim, SPELL_RENEW_STEEL_N); diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp index aac315cda0d..83082b18d73 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp @@ -165,9 +165,9 @@ public: Position pos = me->GetPosition(); - for (std::list<uint64>::const_iterator itr = lSparkList.begin(); itr != lSparkList.end(); ++itr) + for (uint64 guid : lSparkList) { - if (Creature* pSpark = ObjectAccessor::GetCreature(*me, *itr)) + if (Creature* pSpark = ObjectAccessor::GetCreature(*me, guid)) { if (pSpark->IsAlive()) { diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp index d0b8f75e711..b424ce01b06 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp @@ -162,13 +162,11 @@ public: if (m_lGolemGUIDList.empty()) return; - for (std::list<uint64>::const_iterator itr = m_lGolemGUIDList.begin(); itr != m_lGolemGUIDList.end(); ++itr) + for (uint64 guid : m_lGolemGUIDList) { - if (Creature* temp = ObjectAccessor::GetCreature(*me, *itr)) - { + if (Creature* temp = ObjectAccessor::GetCreature(*me, guid)) if (temp->IsAlive()) temp->DespawnOrUnsummon(); - } } m_lGolemGUIDList.clear(); @@ -179,9 +177,9 @@ public: if (m_lGolemGUIDList.empty()) return; - for (std::list<uint64>::const_iterator itr = m_lGolemGUIDList.begin(); itr != m_lGolemGUIDList.end(); ++itr) + for (uint64 guid : m_lGolemGUIDList) { - if (Creature* temp = ObjectAccessor::GetCreature(*me, *itr)) + if (Creature* temp = ObjectAccessor::GetCreature(*me, guid)) { // Only shatter brittle golems if (temp->IsAlive() && temp->GetEntry() == NPC_BRITTLE_GOLEM) diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_maiden_of_grief.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_maiden_of_grief.cpp index eec08c3c429..796299cc952 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_maiden_of_grief.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_maiden_of_grief.cpp @@ -37,7 +37,7 @@ enum Spells enum Events { - EVENT_PARTING_SORROW = 1, + EVENT_PARTING_SORROW = 1, EVENT_STORM_OF_GRIEF, EVENT_SHOCK_OF_SORROW, EVENT_PILLAR_OF_WOE diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp index 67500382758..595dcecd554 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp @@ -334,7 +334,7 @@ class boss_algalon_the_observer : public CreatureScript { case ACTION_START_INTRO: { - me->SetFlag(UNIT_FIELD_FLAGS_2, 0x20); + me->SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_INSTANTLY_APPEAR_MODEL); me->SetDisableGravity(true); DoCast(me, SPELL_ARRIVAL, true); DoCast(me, SPELL_RIDE_THE_LIGHTNING, true); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp index d728bc2a898..6437a76ee95 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp @@ -18,9 +18,10 @@ #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "InstanceScript.h" -#include "ulduar.h" #include "Player.h" #include "WorldPacket.h" +#include "SpellScript.h" +#include "ulduar.h" static DoorData const doorData[] = { @@ -1094,7 +1095,43 @@ class instance_ulduar : public InstanceMapScript } }; +class spell_ulduar_teleporter : public SpellScriptLoader +{ + public: + spell_ulduar_teleporter() : SpellScriptLoader("spell_ulduar_teleporter") { } + + class spell_ulduar_teleporter_SpellScript : public SpellScript + { + PrepareSpellScript(spell_ulduar_teleporter_SpellScript); + + SpellCastResult CheckRequirement() + { + if (GetExplTargetUnit()->GetTypeId() != TYPEID_PLAYER) + return SPELL_FAILED_DONT_REPORT; + + if (GetExplTargetUnit()->IsInCombat()) + { + Spell::SendCastResult(GetExplTargetUnit()->ToPlayer(), GetSpellInfo(), 0, SPELL_FAILED_AFFECTING_COMBAT); + return SPELL_FAILED_AFFECTING_COMBAT; + } + + return SPELL_CAST_OK; + } + + void Register() override + { + OnCheckCast += SpellCheckCastFn(spell_ulduar_teleporter_SpellScript::CheckRequirement); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_ulduar_teleporter_SpellScript(); + } +}; + void AddSC_instance_ulduar() { new instance_ulduar(); + new spell_ulduar_teleporter(); } diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar_teleporter.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar_teleporter.cpp deleted file mode 100644 index 9fc0e4056fa..00000000000 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar_teleporter.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include "ScriptMgr.h" -#include "ScriptedGossip.h" -#include "InstanceScript.h" -#include "Player.h" -#include "ulduar.h" - -/* -The teleporter appears to be active and stable. - -- Expedition Base Camp -- Formation Grounds -- Colossal Forge -- Scrapyard -- Antechamber of Ulduar -- Shattered Walkway -- Conservatory of Life -*/ - -enum UlduarTeleporter -{ - BASE_CAMP = 200, - GROUNDS = 201, - FORGE = 202, - SCRAPYARD = 203, - ANTECHAMBER = 204, - WALKWAY = 205, - CONSERVATORY = 206, -}; - -class ulduar_teleporter : public GameObjectScript -{ - public: - ulduar_teleporter() : GameObjectScript("ulduar_teleporter") { } - - bool OnGossipSelect(Player* player, GameObject* /*gameObject*/, uint32 sender, uint32 action) override - { - player->PlayerTalkClass->ClearMenus(); - if (sender != GOSSIP_SENDER_MAIN) - return false; - if (!player->getAttackers().empty()) - return false; - - switch (action) - { - case BASE_CAMP: - player->TeleportTo(603, -706.122f, -92.6024f, 429.876f, 0.0f); - player->CLOSE_GOSSIP_MENU(); - break; - case GROUNDS: - player->TeleportTo(603, 131.248f, -35.3802f, 409.804f, 0.0f); - player->CLOSE_GOSSIP_MENU(); - break; - case FORGE: - player->TeleportTo(603, 553.233f, -12.3247f, 409.679f, 0.0f); - player->CLOSE_GOSSIP_MENU(); - break; - case SCRAPYARD: - player->TeleportTo(603, 926.292f, -11.4635f, 418.595f, 0.0f); - player->CLOSE_GOSSIP_MENU(); - break; - case ANTECHAMBER: - player->TeleportTo(603, 1498.09f, -24.246f, 420.967f, 0.0f); - player->CLOSE_GOSSIP_MENU(); - break; - case WALKWAY: - player->TeleportTo(603, 1859.45f, -24.1f, 448.9f, 0.0f); - player->CLOSE_GOSSIP_MENU(); - break; - case CONSERVATORY: - player->TeleportTo(603, 2086.27f, -24.3134f, 421.239f, 0.0f); - player->CLOSE_GOSSIP_MENU(); - break; - } - - return true; - } - - bool OnGossipHello(Player* player, GameObject* gameObject) override - { - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Expedition Base Camp", GOSSIP_SENDER_MAIN, BASE_CAMP); - if (InstanceScript* instance = gameObject->GetInstanceScript()) - { - if (instance->GetData(DATA_COLOSSUS) == 2) //count of 2 collossus death - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Formation Grounds", GOSSIP_SENDER_MAIN, GROUNDS); - if (instance->GetBossState(BOSS_LEVIATHAN) == DONE) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Colossal Forge", GOSSIP_SENDER_MAIN, FORGE); - if (instance->GetBossState(BOSS_XT002) == DONE) - { - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Scrapyard", GOSSIP_SENDER_MAIN, SCRAPYARD); - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Antechamber of Ulduar", GOSSIP_SENDER_MAIN, ANTECHAMBER); - } - if (instance->GetBossState(BOSS_KOLOGARN) == DONE) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Shattered Walkway", GOSSIP_SENDER_MAIN, WALKWAY); - if (instance->GetBossState(BOSS_AURIAYA) == DONE) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Conservatory of Life", GOSSIP_SENDER_MAIN, CONSERVATORY); - } - - player->SEND_GOSSIP_MENU(gameObject->GetGOInfo()->GetGossipMenuId(), gameObject->GetGUID()); - return true; - } -}; - -void AddSC_ulduar_teleporter() -{ - new ulduar_teleporter(); -} diff --git a/src/server/scripts/Northrend/zone_crystalsong_forest.cpp b/src/server/scripts/Northrend/zone_crystalsong_forest.cpp index e4bd9c469fb..7d680ecd071 100644 --- a/src/server/scripts/Northrend/zone_crystalsong_forest.cpp +++ b/src/server/scripts/Northrend/zone_crystalsong_forest.cpp @@ -76,20 +76,18 @@ public: GetCreatureListWithEntryInGrid(orbList, me, NPC_TRANSITUS_SHIELD_DUMMY, 32.0f); if (!orbList.empty()) { - for (std::list<Creature*>::const_iterator itr = orbList.begin(); itr != orbList.end(); ++itr) + for (Creature* orb : orbList) { - if (Creature* pOrb = *itr) + if (orb->GetPositionY() < 1000) { - if (pOrb->GetPositionY() < 1000) - { - targetGUID = pOrb->GetGUID(); - break; - } + targetGUID = orb->GetGUID(); + break; } } } } - }else + } + else { if (!targetGUID) if (Creature* pOrb = GetClosestCreatureWithEntry(me, NPC_TRANSITUS_SHIELD_DUMMY, 32.0f)) diff --git a/src/server/scripts/Northrend/zone_dalaran.cpp b/src/server/scripts/Northrend/zone_dalaran.cpp index 30e86fc3b63..2d5028bac05 100644 --- a/src/server/scripts/Northrend/zone_dalaran.cpp +++ b/src/server/scripts/Northrend/zone_dalaran.cpp @@ -73,7 +73,6 @@ public: void AttackStart(Unit* /*who*/) override { } void MoveInLineOfSight(Unit* who) override - { if (!who || !who->IsInWorld() || who->GetZoneId() != 4395) return; diff --git a/src/server/scripts/Northrend/zone_dragonblight.cpp b/src/server/scripts/Northrend/zone_dragonblight.cpp index bda6d953d9f..59c9b21a220 100644 --- a/src/server/scripts/Northrend/zone_dragonblight.cpp +++ b/src/server/scripts/Northrend/zone_dragonblight.cpp @@ -246,13 +246,10 @@ class npc_commander_eligor_dawnbringer : public CreatureScript { std::list<Creature*> creatureList; GetCreatureListWithEntryInGrid(creatureList, me, AudienceMobs[ii], 15.0f); - for (std::list<Creature*>::iterator itr = creatureList.begin(); itr != creatureList.end(); ++itr) + for (Creature* creature : creatureList) { - if (Creature* creatureList = *itr) - { - audienceList[creaturecount] = creatureList->GetGUID(); - ++creaturecount; - } + audienceList[creaturecount] = creature->GetGUID(); + ++creaturecount; } } diff --git a/src/server/scripts/Outland/BlackTemple/boss_bloodboil.cpp b/src/server/scripts/Outland/BlackTemple/boss_gurtogg_bloodboil.cpp index 0004df68016..f03caa37cb2 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_bloodboil.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_gurtogg_bloodboil.cpp @@ -17,14 +17,14 @@ */ /* ScriptData -SDName: Boss_Bloodboil -SD%Complete: 80 -SDComment: Bloodboil not working correctly, missing enrage -SDCategory: Black Temple +Name: Boss_Bloodboil +Complete: 80 +Category: Black Temple EndScriptData */ #include "ScriptMgr.h" #include "ScriptedCreature.h" +#include "SpellScript.h" #include "black_temple.h" enum Bloodboil @@ -54,9 +54,6 @@ enum Bloodboil SPELL_BERSERK = 45078 }; - -//This is used to sort the players by distance in preparation for the Bloodboil cast. - class boss_gurtogg_bloodboil : public CreatureScript { public: @@ -137,51 +134,6 @@ public: Talk(SAY_DEATH); } - // Note: This seems like a very complicated fix. The fix needs to be handled by the core, as implementation of limited-target AoE spells are still not limited. - void CastBloodboil() - { - // Get the Threat List - std::list<HostileReference*> m_threatlist = me->getThreatManager().getThreatList(); - - if (m_threatlist.empty()) // He doesn't have anyone in his threatlist, useless to continue - return; - - std::list<Unit*> targets; - std::list<HostileReference*>::const_iterator itr = m_threatlist.begin(); - for (; itr!= m_threatlist.end(); ++itr) //store the threat list in a different container - { - Unit* target = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid()); - //only on alive players - if (target && target->IsAlive() && target->GetTypeId() == TYPEID_PLAYER) - targets.push_back(target); - } - - //Sort the list of players - targets.sort(Trinity::ObjectDistanceOrderPred(me, false)); - //Resize so we only get top 5 - targets.resize(5); - - //Aura each player in the targets list with Bloodboil. Aura code copied+pasted from Aura command in Level3.cpp - /*SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(SPELL_BLOODBOIL); - if (spellInfo) - { - for (std::list<Unit*>::const_iterator itr = targets.begin(); itr != targets.end(); ++itr) - { - Unit* target = *itr; - if (!target) return; - for (uint32 i = 0; i<3; ++i) - { - uint8 eff = spellInfo->Effect[i]; - if (eff >= TOTAL_SPELL_EFFECTS) - continue; - - Aura* Aur = new Aura(spellInfo, i, target, target, target); - target->AddAura(Aur); - } - } - }*/ - } - void RevertThreatOnTarget(uint64 guid) { if (Unit* unit = ObjectAccessor::GetUnit(*me, guid)) @@ -247,8 +199,7 @@ public: { if (BloodboilCount < 5) // Only cast it five times. { - //CastBloodboil(); // Causes issues on windows, so is commented out. - DoCastVictim(SPELL_BLOODBOIL); + DoCastAOE(SPELL_BLOODBOIL); ++BloodboilCount; BloodboilTimer = 10000*BloodboilCount; } @@ -274,7 +225,7 @@ public: { if (Phase1) { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) { Phase1 = false; @@ -327,7 +278,41 @@ public: }; +// 42005 - Bloodboil +class spell_gurtogg_bloodboil_bloodboil : public SpellScriptLoader +{ + public: + spell_gurtogg_bloodboil_bloodboil() : SpellScriptLoader("spell_gurtogg_bloodboil_bloodboil") { } + + class spell_gurtogg_bloodboil_bloodboil_SpellScript : public SpellScript + { + PrepareSpellScript(spell_gurtogg_bloodboil_bloodboil_SpellScript); + + void FilterTargets(std::list<WorldObject*>& targets) + { + if (targets.size() <= 5) + return; + + // Sort the list of players + targets.sort(Trinity::ObjectDistanceOrderPred(GetCaster(), false)); + // Resize so we only get top 5 + targets.resize(5); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_gurtogg_bloodboil_bloodboil_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_gurtogg_bloodboil_bloodboil_SpellScript(); + } +}; + void AddSC_boss_gurtogg_bloodboil() { new boss_gurtogg_bloodboil(); + new spell_gurtogg_bloodboil_bloodboil(); } diff --git a/src/server/scripts/Outland/CMakeLists.txt b/src/server/scripts/Outland/CMakeLists.txt index 414a3bce14a..0c69a236ef8 100644 --- a/src/server/scripts/Outland/CMakeLists.txt +++ b/src/server/scripts/Outland/CMakeLists.txt @@ -112,7 +112,7 @@ set(scripts_STAT_SRCS Outland/BlackTemple/instance_black_temple.cpp Outland/BlackTemple/boss_reliquary_of_souls.cpp Outland/BlackTemple/boss_warlord_najentus.cpp - Outland/BlackTemple/boss_bloodboil.cpp + Outland/BlackTemple/boss_gurtogg_bloodboil.cpp Outland/BlackTemple/boss_illidan.cpp Outland/zone_shadowmoon_valley.cpp Outland/zone_blades_edge_mountains.cpp diff --git a/src/server/scripts/Outland/zone_shadowmoon_valley.cpp b/src/server/scripts/Outland/zone_shadowmoon_valley.cpp index 116beb3d081..cfcc05a625c 100644 --- a/src/server/scripts/Outland/zone_shadowmoon_valley.cpp +++ b/src/server/scripts/Outland/zone_shadowmoon_valley.cpp @@ -1813,7 +1813,6 @@ public: enum ZuluhedChains { - QUEST_ZULUHED = 10866, NPC_KARYNAKU = 22112, }; @@ -1828,9 +1827,9 @@ class spell_unlocking_zuluheds_chains : public SpellScriptLoader void HandleAfterHit() { - if (GetCaster()->GetTypeId() == TYPEID_PLAYER) - if (Creature* karynaku = GetCaster()->FindNearestCreature(NPC_KARYNAKU, 15.0f)) - GetCaster()->ToPlayer()->KilledMonsterCredit(NPC_KARYNAKU, karynaku->GetGUID()); + if (Player* caster = GetCaster()->ToPlayer()) + if (Creature* karynaku = caster->FindNearestCreature(NPC_KARYNAKU, 15.0f)) + caster->KilledMonsterCredit(NPC_KARYNAKU, karynaku->GetGUID()); } void Register() override diff --git a/src/server/scripts/Spells/spell_dk.cpp b/src/server/scripts/Spells/spell_dk.cpp index 9c6ed2ff120..a98734e8308 100644 --- a/src/server/scripts/Spells/spell_dk.cpp +++ b/src/server/scripts/Spells/spell_dk.cpp @@ -33,6 +33,7 @@ enum DeathKnightSpells SPELL_DK_BLACK_ICE_R1 = 49140, SPELL_DK_BLOOD_BOIL_TRIGGERED = 65658, SPELL_DK_BLOOD_GORGED_HEAL = 50454, + SPELL_DK_BLOOD_PLAGUE = 55078, SPELL_DK_BLOOD_PRESENCE = 48263, SPELL_DK_BLOOD_PRESENCE_TRIGGERED = 61261, SPELL_DK_BLOOD_SHIELD_MASTERY = 77513, @@ -43,9 +44,11 @@ enum DeathKnightSpells SPELL_DK_DEATH_COIL_HEAL = 47633, SPELL_DK_DEATH_STRIKE_HEAL = 45470, SPELL_DK_DEATH_STRIKE_ENABLER = 89832, + SPELL_DK_FROST_FEVER = 55095, SPELL_DK_FROST_PRESENCE = 48266, SPELL_DK_GHOUL_EXPLODE = 47496, SPELL_DK_GLYPH_OF_ICEBOUND_FORTITUDE = 58625, + SPELL_DK_GLYPH_OF_DISEASE = 63334, SPELL_DK_IMPROVED_BLOOD_PRESENCE_R1 = 50365, SPELL_DK_IMPROVED_DEATH_STRIKE = 62905, SPELL_DK_IMPROVED_FROST_PRESENCE_R1 = 50384, @@ -936,6 +939,90 @@ class spell_dk_necrotic_strike : public SpellScriptLoader } }; +// ID - 50842 Pestilence +class spell_dk_pestilence : public SpellScriptLoader +{ + public: + spell_dk_pestilence() : SpellScriptLoader("spell_dk_pestilence") { } + + class spell_dk_pestilence_SpellScript : public SpellScript + { + PrepareSpellScript(spell_dk_pestilence_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_DK_GLYPH_OF_DISEASE) + || !sSpellMgr->GetSpellInfo(SPELL_DK_BLOOD_PLAGUE) + || !sSpellMgr->GetSpellInfo(SPELL_DK_FROST_FEVER)) + return false; + return true; + } + + void OnHit(SpellEffIndex /*effIndex*/) + { + Unit* caster = GetCaster(); + Unit* hitUnit = GetHitUnit(); + Unit* victim = GetExplTargetUnit(); + + if (!victim) + return; + + if (victim != hitUnit || caster->HasAura(SPELL_DK_GLYPH_OF_DISEASE)) + { + if (Aura* aurOld = victim->GetAura(SPELL_DK_BLOOD_PLAGUE, caster->GetGUID())) // Check Blood Plague application on victim. + { + if (AuraEffect* aurEffOld = aurOld->GetEffect(EFFECT_0)) + { + float donePct = aurEffOld->GetDonePct(); + float critChance = aurEffOld->GetCritChance(); + + caster->CastSpell(hitUnit, SPELL_DK_BLOOD_PLAGUE, true); // Spread the disease to hitUnit. + + if (Aura* aurNew = hitUnit->GetAura(SPELL_DK_BLOOD_PLAGUE, caster->GetGUID())) // Check Blood Plague application on hitUnit. + { + if (AuraEffect* aurEffNew = aurNew->GetEffect(EFFECT_0)) + { + aurEffNew->SetCritChance(critChance); // Blood Plague can crit if caster has T9. + aurEffNew->SetDonePct(donePct); + aurEffNew->SetDamage(caster->SpellDamageBonusDone(hitUnit, aurEffNew->GetSpellInfo(), std::max(aurEffNew->GetAmount(), 0), DOT) * donePct); + } + } + } + } + + if (Aura* aurOld = victim->GetAura(SPELL_DK_FROST_FEVER, caster->GetGUID())) // Check Frost Fever application on victim. + { + if (AuraEffect* aurEffOld = aurOld->GetEffect(EFFECT_0)) + { + float donePct = aurEffOld->GetDonePct(); + + caster->CastSpell(hitUnit, SPELL_DK_FROST_FEVER, true); // Spread the disease to hitUnit. + + if (Aura* aurNew = hitUnit->GetAura(SPELL_DK_FROST_FEVER, caster->GetGUID())) // Check Frost Fever application on hitUnit. + { + if (AuraEffect* aurEffNew = aurNew->GetEffect(EFFECT_0)) + { + aurEffNew->SetDonePct(donePct); + aurEffNew->SetDamage(caster->SpellDamageBonusDone(hitUnit, aurEffNew->GetSpellInfo(), std::max(aurEffNew->GetAmount(), 0), DOT) * donePct); + } + } + } + } + } + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_dk_pestilence_SpellScript::OnHit, EFFECT_2, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_dk_pestilence_SpellScript(); + } +}; + // 48266 - Blood Presence // 48263 - Frost Presence // 48265 - Unholy Presence @@ -1415,6 +1502,7 @@ void AddSC_deathknight_spell_scripts() new spell_dk_improved_frost_presence(); new spell_dk_improved_unholy_presence(); new spell_dk_necrotic_strike(); + new spell_dk_pestilence(); new spell_dk_presence(); new spell_dk_raise_dead(); new spell_dk_rune_tap_party(); diff --git a/src/server/scripts/Spells/spell_priest.cpp b/src/server/scripts/Spells/spell_priest.cpp index d804c0cfc8b..ae9edfc3929 100644 --- a/src/server/scripts/Spells/spell_priest.cpp +++ b/src/server/scripts/Spells/spell_priest.cpp @@ -737,10 +737,17 @@ class spell_pri_pain_and_suffering_proc : public SpellScriptLoader void HandleEffectScriptEffect(SpellEffIndex /*effIndex*/) { + Unit* caster = GetCaster(); // Refresh Shadow Word: Pain on target - if (Unit* unitTarget = GetHitUnit()) - if (AuraEffect* aur = unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PRIEST, 0x8000, 0, 0, GetCaster()->GetGUID())) + if (Unit* target = GetHitUnit()) + if (AuraEffect* aur = target->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PRIEST, 0x8000, 0, 0, caster->GetGUID())) + { + uint32 damage = std::max(aur->GetAmount(), 0); + sScriptMgr->ModifyPeriodicDamageAurasTick(target, caster, damage); + aur->SetDamage(caster->SpellDamageBonusDone(target, aur->GetSpellInfo(), damage, DOT) * aur->GetDonePct()); + aur->CalculatePeriodic(caster, false, false); aur->GetBase()->RefreshDuration(); + } } void Register() override diff --git a/src/server/scripts/Spells/spell_warlock.cpp b/src/server/scripts/Spells/spell_warlock.cpp index 2b0a5506a83..86ece72cc56 100644 --- a/src/server/scripts/Spells/spell_warlock.cpp +++ b/src/server/scripts/Spells/spell_warlock.cpp @@ -537,10 +537,17 @@ class spell_warl_everlasting_affliction : public SpellScriptLoader void HandleScriptEffect(SpellEffIndex /*effIndex*/) { - if (Unit* unitTarget = GetHitUnit()) + Unit* caster = GetCaster(); + if (Unit* target = GetHitUnit()) // Refresh corruption on target - if (AuraEffect* aurEff = unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_WARLOCK, 0x2, 0, 0, GetCaster()->GetGUID())) - aurEff->GetBase()->RefreshDuration(); + if (AuraEffect* aurEff = target->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_WARLOCK, 0x2, 0, 0, caster->GetGUID())) + { + uint32 damage = std::max(aurEff->GetAmount(), 0); + sScriptMgr->ModifyPeriodicDamageAurasTick(target, caster, damage); + aurEff->SetDamage(caster->SpellDamageBonusDone(target, aurEff->GetSpellInfo(), damage, DOT) * aurEff->GetDonePct()); + aurEff->CalculatePeriodic(caster, false, false); + aurEff->GetBase()->RefreshDuration(true); + } } void Register() override diff --git a/src/server/scripts/Spells/spell_warrior.cpp b/src/server/scripts/Spells/spell_warrior.cpp index 529d62b5297..e8c95c8392e 100644 --- a/src/server/scripts/Spells/spell_warrior.cpp +++ b/src/server/scripts/Spells/spell_warrior.cpp @@ -36,7 +36,7 @@ enum WarriorSpells SPELL_WARRIOR_DEEP_WOUNDS_RANK_1 = 12162, SPELL_WARRIOR_DEEP_WOUNDS_RANK_2 = 12850, SPELL_WARRIOR_DEEP_WOUNDS_RANK_3 = 12868, - SPELL_WARRIOR_DEEP_WOUNDS_RANK_PERIODIC = 12721, + SPELL_WARRIOR_DEEP_WOUNDS_PERIODIC = 12721, SPELL_WARRIOR_EXECUTE = 20647, SPELL_WARRIOR_GLYPH_OF_EXECUTION = 58367, SPELL_WARRIOR_JUGGERNAUT_CRIT_BONUS_BUFF = 65156, @@ -231,7 +231,7 @@ class spell_warr_deep_wounds : public SpellScriptLoader if (!sSpellMgr->GetSpellInfo(SPELL_WARRIOR_DEEP_WOUNDS_RANK_1) || !sSpellMgr->GetSpellInfo(SPELL_WARRIOR_DEEP_WOUNDS_RANK_2) || !sSpellMgr->GetSpellInfo(SPELL_WARRIOR_DEEP_WOUNDS_RANK_3) || - !sSpellMgr->GetSpellInfo(SPELL_WARRIOR_DEEP_WOUNDS_RANK_PERIODIC)) + !sSpellMgr->GetSpellInfo(SPELL_WARRIOR_DEEP_WOUNDS_PERIODIC)) return false; return true; } @@ -242,23 +242,18 @@ class spell_warr_deep_wounds : public SpellScriptLoader Unit* caster = GetCaster(); if (Unit* target = GetHitUnit()) { - // apply percent damage mods - damage = caster->SpellDamageBonusDone(target, GetSpellInfo(), damage, SPELL_DIRECT_DAMAGE); - ApplyPct(damage, 16 * GetSpellInfo()->GetRank()); - damage = target->SpellDamageBonusTaken(caster, GetSpellInfo(), damage, SPELL_DIRECT_DAMAGE); - - SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(SPELL_WARRIOR_DEEP_WOUNDS_RANK_PERIODIC); + SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(SPELL_WARRIOR_DEEP_WOUNDS_PERIODIC); uint32 ticks = spellInfo->GetDuration() / spellInfo->Effects[EFFECT_0].Amplitude; // Add remaining ticks to damage done - if (AuraEffect const* aurEff = target->GetAuraEffect(SPELL_WARRIOR_DEEP_WOUNDS_RANK_PERIODIC, EFFECT_0, caster->GetGUID())) - damage += aurEff->GetAmount() * (ticks - aurEff->GetTickNumber()); + if (AuraEffect const* aurEff = target->GetAuraEffect(SPELL_WARRIOR_DEEP_WOUNDS_PERIODIC, EFFECT_0, caster->GetGUID())) + damage += aurEff->GetDamage() * (ticks - aurEff->GetTickNumber()); damage /= ticks; - caster->CastCustomSpell(target, SPELL_WARRIOR_DEEP_WOUNDS_RANK_PERIODIC, &damage, NULL, NULL, true); + caster->CastCustomSpell(target, SPELL_WARRIOR_DEEP_WOUNDS_PERIODIC, &damage, NULL, NULL, true); } } diff --git a/src/server/scripts/World/areatrigger_scripts.cpp b/src/server/scripts/World/areatrigger_scripts.cpp index fb438c38efb..4393f72eb1b 100644 --- a/src/server/scripts/World/areatrigger_scripts.cpp +++ b/src/server/scripts/World/areatrigger_scripts.cpp @@ -51,11 +51,7 @@ enum CoilfangGOs class AreaTrigger_at_coilfang_waterfall : public AreaTriggerScript { public: - - AreaTrigger_at_coilfang_waterfall() - : AreaTriggerScript("at_coilfang_waterfall") - { - } + AreaTrigger_at_coilfang_waterfall() : AreaTriggerScript("at_coilfang_waterfall") { } bool OnTrigger(Player* player, AreaTriggerEntry const* /*trigger*/) override { @@ -83,11 +79,7 @@ enum LegionTeleporter class AreaTrigger_at_legion_teleporter : public AreaTriggerScript { public: - - AreaTrigger_at_legion_teleporter() - : AreaTriggerScript("at_legion_teleporter") - { - } + AreaTrigger_at_legion_teleporter() : AreaTriggerScript("at_legion_teleporter") { } bool OnTrigger(Player* player, AreaTriggerEntry const* /*trigger*/) override { @@ -125,11 +117,7 @@ enum StormwrightShelf class AreaTrigger_at_stormwright_shelf : public AreaTriggerScript { public: - - AreaTrigger_at_stormwright_shelf() - : AreaTriggerScript("at_stormwright_shelf") - { - } + AreaTrigger_at_stormwright_shelf() : AreaTriggerScript("at_stormwright_shelf") { } bool OnTrigger(Player* player, AreaTriggerEntry const* /*trigger*/) override { @@ -153,11 +141,7 @@ enum ScentLarkorwi class AreaTrigger_at_scent_larkorwi : public AreaTriggerScript { public: - - AreaTrigger_at_scent_larkorwi() - : AreaTriggerScript("at_scent_larkorwi") - { - } + AreaTrigger_at_scent_larkorwi() : AreaTriggerScript("at_scent_larkorwi") { } bool OnTrigger(Player* player, AreaTriggerEntry const* /*trigger*/) override { @@ -184,11 +168,7 @@ enum AtLastRites class AreaTrigger_at_last_rites : public AreaTriggerScript { public: - - AreaTrigger_at_last_rites() - : AreaTriggerScript("at_last_rites") - { - } + AreaTrigger_at_last_rites() : AreaTriggerScript("at_last_rites") { } bool OnTrigger(Player* player, AreaTriggerEntry const* trigger) override { @@ -246,7 +226,6 @@ enum Waygate class AreaTrigger_at_sholazar_waygate : public AreaTriggerScript { public: - AreaTrigger_at_sholazar_waygate() : AreaTriggerScript("at_sholazar_waygate") { } bool OnTrigger(Player* player, AreaTriggerEntry const* trigger) override diff --git a/src/server/scripts/World/go_scripts.cpp b/src/server/scripts/World/go_scripts.cpp index 9dbcb91dc1a..f73d1c77da4 100644 --- a/src/server/scripts/World/go_scripts.cpp +++ b/src/server/scripts/World/go_scripts.cpp @@ -118,7 +118,8 @@ public: enum GildedBrazier { - NPC_STILLBLADE = 17716, + NPC_STILLBLADE = 17716, + QUEST_THE_FIRST_TRIAL = 9678 }; class go_gilded_brazier : public GameObjectScript @@ -130,7 +131,7 @@ public: { if (go->GetGoType() == GAMEOBJECT_TYPE_GOOBER) { - if (player->GetQuestStatus(9678) == QUEST_STATUS_INCOMPLETE) + if (player->GetQuestStatus(QUEST_THE_FIRST_TRIAL) == QUEST_STATUS_INCOMPLETE) { if (Creature* Stillblade = player->SummonCreature(NPC_STILLBLADE, 8106.11f, -7542.06f, 151.775f, 3.02598f, TEMPSUMMON_DEAD_DESPAWN, 60000)) Stillblade->AI()->AttackStart(player); diff --git a/src/server/scripts/World/guards.cpp b/src/server/scripts/World/guards.cpp index 21a81d37868..a156a41fcef 100644 --- a/src/server/scripts/World/guards.cpp +++ b/src/server/scripts/World/guards.cpp @@ -387,7 +387,7 @@ public: void AddSC_guards() { - new guard_generic; - new guard_shattrath_aldor; - new guard_shattrath_scryer; + new guard_generic(); + new guard_shattrath_aldor(); + new guard_shattrath_scryer(); } diff --git a/src/server/scripts/World/mob_generic_creature.cpp b/src/server/scripts/World/mob_generic_creature.cpp index 30666d5d2ea..2eb91b7b8fe 100644 --- a/src/server/scripts/World/mob_generic_creature.cpp +++ b/src/server/scripts/World/mob_generic_creature.cpp @@ -229,6 +229,6 @@ public: void AddSC_generic_creature() { //new generic_creature; - new trigger_periodic; + new trigger_periodic(); //new trigger_death; } diff --git a/src/server/scripts/World/npc_innkeeper.cpp b/src/server/scripts/World/npc_innkeeper.cpp index b647cccf8ea..be56e57cc9d 100644 --- a/src/server/scripts/World/npc_innkeeper.cpp +++ b/src/server/scripts/World/npc_innkeeper.cpp @@ -134,6 +134,6 @@ public: void AddSC_npc_innkeeper() { - new npc_innkeeper; + new npc_innkeeper(); } diff --git a/src/server/scripts/World/npcs_special.cpp b/src/server/scripts/World/npcs_special.cpp index 321c3d67dc5..d2f0a7898bb 100644 --- a/src/server/scripts/World/npcs_special.cpp +++ b/src/server/scripts/World/npcs_special.cpp @@ -185,7 +185,6 @@ public: } void MoveInLineOfSight(Unit* who) override - { if (!SpawnAssoc) return; @@ -1518,7 +1517,10 @@ class npc_brewfest_reveler : public CreatureScript enum TrainingDummy { NPC_ADVANCED_TARGET_DUMMY = 2674, - NPC_TARGET_DUMMY = 2673 + NPC_TARGET_DUMMY = 2673, + + EVENT_TD_CHECK_COMBAT = 1, + EVENT_TD_DESPAWN = 2 }; class npc_training_dummy : public CreatureScript @@ -1531,20 +1533,22 @@ public: npc_training_dummyAI(Creature* creature) : ScriptedAI(creature) { SetCombatMovement(false); - entry = creature->GetEntry(); } - uint32 entry; - uint32 resetTimer; - uint32 despawnTimer; + EventMap _events; + std::unordered_map<uint64, time_t> _damageTimes; void Reset() override { me->SetControlled(true, UNIT_STATE_STUNNED);//disable rotate me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true);//imune to knock aways like blast wave - resetTimer = 5000; - despawnTimer = 15000; + _events.Reset(); + _damageTimes.clear(); + if (me->GetEntry() != NPC_ADVANCED_TARGET_DUMMY && me->GetEntry() != NPC_TARGET_DUMMY) + _events.ScheduleEvent(EVENT_TD_CHECK_COMBAT, 1000); + else + _events.ScheduleEvent(EVENT_TD_DESPAWN, 15000); } void EnterEvadeMode() override @@ -1555,37 +1559,52 @@ public: Reset(); } - void DamageTaken(Unit* /*doneBy*/, uint32& damage) override + void DamageTaken(Unit* doneBy, uint32& damage) override { - resetTimer = 5000; + me->AddThreat(doneBy, float(damage)); // just to create threat reference + _damageTimes[doneBy->GetGUID()] = time(NULL); damage = 0; } void UpdateAI(uint32 diff) override { - if (!UpdateVictim()) + if (!me->IsInCombat()) return; if (!me->HasUnitState(UNIT_STATE_STUNNED)) me->SetControlled(true, UNIT_STATE_STUNNED);//disable rotate - if (entry != NPC_ADVANCED_TARGET_DUMMY && entry != NPC_TARGET_DUMMY) + _events.Update(diff); + + if (uint32 eventId = _events.ExecuteEvent()) { - if (resetTimer <= diff) + switch (eventId) { - EnterEvadeMode(); - resetTimer = 5000; + case EVENT_TD_CHECK_COMBAT: + { + time_t now = time(NULL); + for (std::unordered_map<uint64, time_t>::iterator itr = _damageTimes.begin(); itr != _damageTimes.end();) + { + // If unit has not dealt damage to training dummy for 5 seconds, remove him from combat + if (itr->second < now - 5) + { + if (Unit* unit = ObjectAccessor::GetUnit(*me, itr->first)) + unit->getHostileRefManager().deleteReference(me); + + itr = _damageTimes.erase(itr); + } + else + ++itr; + } + _events.ScheduleEvent(EVENT_TD_CHECK_COMBAT, 1000); + break; + } + case EVENT_TD_DESPAWN: + me->DespawnOrUnsummon(1); + break; + default: + break; } - else - resetTimer -= diff; - return; - } - else - { - if (despawnTimer <= diff) - me->DespawnOrUnsummon(); - else - despawnTimer -= diff; } } diff --git a/src/server/shared/Cryptography/Authentication/PacketCrypt.cpp b/src/server/shared/Cryptography/Authentication/PacketCrypt.cpp new file mode 100644 index 00000000000..7fac311b8a2 --- /dev/null +++ b/src/server/shared/Cryptography/Authentication/PacketCrypt.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "PacketCrypt.h" + +PacketCrypt::PacketCrypt(uint32 rc4InitSize) + : _clientDecrypt(rc4InitSize), _serverEncrypt(rc4InitSize), _initialized(false) +{ +} + +void PacketCrypt::DecryptRecv(uint8* data, size_t len) +{ + if (!_initialized) + return; + + _clientDecrypt.UpdateData(len, data); +} + +void PacketCrypt::EncryptSend(uint8* data, size_t len) +{ + if (!_initialized) + return; + + _serverEncrypt.UpdateData(len, data); +} diff --git a/src/server/shared/Cryptography/Authentication/AuthCrypt.h b/src/server/shared/Cryptography/Authentication/PacketCrypt.h index 8fa150068a2..36f3b81fb53 100644 --- a/src/server/shared/Cryptography/Authentication/AuthCrypt.h +++ b/src/server/shared/Cryptography/Authentication/PacketCrypt.h @@ -1,6 +1,5 @@ /* * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -16,27 +15,29 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef _AUTHCRYPT_H -#define _AUTHCRYPT_H +#ifndef _PACKETCRYPT_H +#define _PACKETCRYPT_H #include "Cryptography/ARC4.h" class BigNumber; -class AuthCrypt +class PacketCrypt { public: - AuthCrypt(); + PacketCrypt(uint32 rc4InitSize); + virtual ~PacketCrypt() { } - void Init(BigNumber* K); - void DecryptRecv(uint8 *, size_t); - void EncryptSend(uint8 *, size_t); + virtual void Init(BigNumber* K) = 0; + void DecryptRecv(uint8* data, size_t length); + void EncryptSend(uint8* data, size_t length); bool IsInitialized() const { return _initialized; } - private: + protected: ARC4 _clientDecrypt; ARC4 _serverEncrypt; bool _initialized; }; -#endif + +#endif // _PACKETCRYPT_H diff --git a/src/server/shared/Cryptography/Authentication/AuthCrypt.cpp b/src/server/shared/Cryptography/Authentication/WorldPacketCrypt.cpp index ff94f307254..10403b84a1f 100644 --- a/src/server/shared/Cryptography/Authentication/AuthCrypt.cpp +++ b/src/server/shared/Cryptography/Authentication/WorldPacketCrypt.cpp @@ -16,58 +16,36 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "AuthCrypt.h" -#include "Cryptography/HMACSHA1.h" +#include "WorldPacketCrypt.h" +#include "Cryptography/HmacHash.h" #include "Cryptography/BigNumber.h" -AuthCrypt::AuthCrypt() : - _clientDecrypt(SHA_DIGEST_LENGTH), _serverEncrypt(SHA_DIGEST_LENGTH), - _initialized(false) -{ } +WorldPacketCrypt::WorldPacketCrypt() : PacketCrypt(SHA_DIGEST_LENGTH) +{ +} -void AuthCrypt::Init(BigNumber* K) +void WorldPacketCrypt::Init(BigNumber* K) { uint8 ServerEncryptionKey[SEED_KEY_SIZE] = { 0xCC, 0x98, 0xAE, 0x04, 0xE8, 0x97, 0xEA, 0xCA, 0x12, 0xDD, 0xC0, 0x93, 0x42, 0x91, 0x53, 0x57 }; - HmacHash serverEncryptHmac(SEED_KEY_SIZE, (uint8*)ServerEncryptionKey); + HmacSha1 serverEncryptHmac(SEED_KEY_SIZE, (uint8*)ServerEncryptionKey); uint8 *encryptHash = serverEncryptHmac.ComputeHash(K); uint8 ServerDecryptionKey[SEED_KEY_SIZE] = { 0xC2, 0xB3, 0x72, 0x3C, 0xC6, 0xAE, 0xD9, 0xB5, 0x34, 0x3C, 0x53, 0xEE, 0x2F, 0x43, 0x67, 0xCE }; - HmacHash clientDecryptHmac(SEED_KEY_SIZE, (uint8*)ServerDecryptionKey); + HmacSha1 clientDecryptHmac(SEED_KEY_SIZE, (uint8*)ServerDecryptionKey); uint8 *decryptHash = clientDecryptHmac.ComputeHash(K); - //ARC4 _serverDecrypt(encryptHash); _clientDecrypt.Init(decryptHash); _serverEncrypt.Init(encryptHash); - //ARC4 _clientEncrypt(decryptHash); // Drop first 1024 bytes, as WoW uses ARC4-drop1024. uint8 syncBuf[1024]; memset(syncBuf, 0, 1024); _serverEncrypt.UpdateData(1024, syncBuf); - //_clientEncrypt.UpdateData(1024, syncBuf); memset(syncBuf, 0, 1024); - //_serverDecrypt.UpdateData(1024, syncBuf); _clientDecrypt.UpdateData(1024, syncBuf); _initialized = true; } - -void AuthCrypt::DecryptRecv(uint8 *data, size_t len) -{ - if (!_initialized) - return; - - _clientDecrypt.UpdateData(len, data); -} - -void AuthCrypt::EncryptSend(uint8 *data, size_t len) -{ - if (!_initialized) - return; - - _serverEncrypt.UpdateData(len, data); -} - diff --git a/src/server/shared/Cryptography/Authentication/WorldPacketCrypt.h b/src/server/shared/Cryptography/Authentication/WorldPacketCrypt.h new file mode 100644 index 00000000000..7ccca11f09d --- /dev/null +++ b/src/server/shared/Cryptography/Authentication/WorldPacketCrypt.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _WORLDPACKETCRYPT_H +#define _WORLDPACKETCRYPT_H + +#include "PacketCrypt.h" + +class BigNumber; + +class WorldPacketCrypt : public PacketCrypt +{ + public: + WorldPacketCrypt(); + + void Init(BigNumber* K) override; +}; + +#endif // _WORLDPACKETCRYPT_H diff --git a/src/server/shared/Cryptography/BigNumber.cpp b/src/server/shared/Cryptography/BigNumber.cpp index 1f3fc96e28d..1c82314bdba 100644 --- a/src/server/shared/Cryptography/BigNumber.cpp +++ b/src/server/shared/Cryptography/BigNumber.cpp @@ -190,13 +190,19 @@ ACE_Auto_Array_Ptr<uint8> BigNumber::AsByteArray(int32 minSize, bool littleEndia return ret; } -char * BigNumber::AsHexStr() const +std::string BigNumber::AsHexStr() const { - return BN_bn2hex(_bn); + char* ch = BN_bn2hex(_bn); + std::string ret = ch; + OPENSSL_free(ch); + return ret; } -char * BigNumber::AsDecStr() const +std::string BigNumber::AsDecStr() const { - return BN_bn2dec(_bn); + char* ch = BN_bn2dec(_bn); + std::string ret = ch; + OPENSSL_free(ch); + return ret; } diff --git a/src/server/shared/Cryptography/BigNumber.h b/src/server/shared/Cryptography/BigNumber.h index dc553babec9..7de53b442ae 100644 --- a/src/server/shared/Cryptography/BigNumber.h +++ b/src/server/shared/Cryptography/BigNumber.h @@ -21,6 +21,7 @@ #include "Define.h" #include <ace/Auto_Ptr.h> +#include <string> struct bignum_st; @@ -89,8 +90,8 @@ class BigNumber ACE_Auto_Array_Ptr<uint8> AsByteArray(int32 minSize = 0, bool littleEndian = true); - char * AsHexStr() const; - char * AsDecStr() const; + std::string AsHexStr() const; + std::string AsDecStr() const; private: struct bignum_st *_bn; diff --git a/src/server/shared/Cryptography/HMACSHA1.cpp b/src/server/shared/Cryptography/HMACSHA1.cpp deleted file mode 100644 index 2148a3b8a7b..00000000000 --- a/src/server/shared/Cryptography/HMACSHA1.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include "HMACSHA1.h" -#include "BigNumber.h" -#include "Common.h" - -HmacHash::HmacHash(uint32 len, uint8 *seed) -{ - HMAC_CTX_init(&m_ctx); - HMAC_Init_ex(&m_ctx, seed, len, EVP_sha1(), NULL); - memset(m_digest, 0, sizeof(m_digest)); -} - -HmacHash::~HmacHash() -{ - HMAC_CTX_cleanup(&m_ctx); -} - -void HmacHash::UpdateData(const std::string &str) -{ - HMAC_Update(&m_ctx, (uint8 const*)str.c_str(), str.length()); -} - -void HmacHash::UpdateData(const uint8* data, size_t len) -{ - HMAC_Update(&m_ctx, data, len); -} - -void HmacHash::Finalize() -{ - uint32 length = 0; - HMAC_Final(&m_ctx, (uint8*)m_digest, &length); - ASSERT(length == SHA_DIGEST_LENGTH); -} - -uint8 *HmacHash::ComputeHash(BigNumber* bn) -{ - HMAC_Update(&m_ctx, bn->AsByteArray().get(), bn->GetNumBytes()); - Finalize(); - return (uint8*)m_digest; -} diff --git a/src/server/shared/Cryptography/HmacHash.cpp b/src/server/shared/Cryptography/HmacHash.cpp new file mode 100644 index 00000000000..2913b9fa79a --- /dev/null +++ b/src/server/shared/Cryptography/HmacHash.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "HmacHash.h" +#include "BigNumber.h" +#include "Common.h" + +template<HashCreateFn HashCreator, uint32 DigestLength> +HmacHash<HashCreator, DigestLength>::HmacHash(uint32 len, uint8 *seed) +{ + HMAC_CTX_init(&_ctx); + HMAC_Init_ex(&_ctx, seed, len, HashCreator(), NULL); + memset(_digest, 0, DigestLength); +} + +template<HashCreateFn HashCreator, uint32 DigestLength> +HmacHash<HashCreator, DigestLength>::~HmacHash() +{ + HMAC_CTX_cleanup(&_ctx); +} + +template<HashCreateFn HashCreator, uint32 DigestLength> +void HmacHash<HashCreator, DigestLength>::UpdateData(const std::string &str) +{ + HMAC_Update(&_ctx, (uint8 const*)str.c_str(), str.length()); +} + +template<HashCreateFn HashCreator, uint32 DigestLength> +void HmacHash<HashCreator, DigestLength>::UpdateData(const uint8* data, size_t len) +{ + HMAC_Update(&_ctx, data, len); +} + +template<HashCreateFn HashCreator, uint32 DigestLength> +void HmacHash<HashCreator, DigestLength>::Finalize() +{ + uint32 length = 0; + HMAC_Final(&_ctx, _digest, &length); + ASSERT(length == DigestLength); +} + +template<HashCreateFn HashCreator, uint32 DigestLength> +uint8* HmacHash<HashCreator, DigestLength>::ComputeHash(BigNumber* bn) +{ + HMAC_Update(&_ctx, bn->AsByteArray().get(), bn->GetNumBytes()); + Finalize(); + return _digest; +} + +template class HmacHash<EVP_sha1, SHA_DIGEST_LENGTH>; +template class HmacHash<EVP_sha256, SHA256_DIGEST_LENGTH>; diff --git a/src/server/shared/Cryptography/HMACSHA1.h b/src/server/shared/Cryptography/HmacHash.h index de1556d3c98..56ee55edda2 100644 --- a/src/server/shared/Cryptography/HMACSHA1.h +++ b/src/server/shared/Cryptography/HmacHash.h @@ -28,20 +28,26 @@ class BigNumber; #define SEED_KEY_SIZE 16 +typedef EVP_MD const* (*HashCreateFn)(); + +template<HashCreateFn HashCreator, uint32 DigestLength> class HmacHash { public: HmacHash(uint32 len, uint8 *seed); ~HmacHash(); - void UpdateData(const std::string &str); - void UpdateData(const uint8* data, size_t len); + void UpdateData(std::string const& str); + void UpdateData(uint8 const* data, size_t len); void Finalize(); - uint8 *ComputeHash(BigNumber* bn); - uint8 *GetDigest() { return (uint8*)m_digest; } - int GetLength() const { return SHA_DIGEST_LENGTH; } + uint8* ComputeHash(BigNumber* bn); + uint8* GetDigest() { return _digest; } + uint32 GetLength() const { return DigestLength; } private: - HMAC_CTX m_ctx; - uint8 m_digest[SHA_DIGEST_LENGTH]; + HMAC_CTX _ctx; + uint8 _digest[DigestLength]; }; -#endif +typedef HmacHash<EVP_sha1, SHA_DIGEST_LENGTH> HmacSha1; +typedef HmacHash<EVP_sha256, SHA256_DIGEST_LENGTH> HmacSha256; + +#endif diff --git a/src/server/shared/Cryptography/SHA256.cpp b/src/server/shared/Cryptography/SHA256.cpp new file mode 100644 index 00000000000..b58c7db40c6 --- /dev/null +++ b/src/server/shared/Cryptography/SHA256.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "SHA256.h" +#include "BigNumber.h" +#include <stdarg.h> + +SHA256Hash::SHA256Hash() +{ + SHA256_Init(&mC); + memset(mDigest, 0, SHA256_DIGEST_LENGTH * sizeof(uint8)); +} + +SHA256Hash::~SHA256Hash() +{ + SHA256_Init(&mC); +} + +void SHA256Hash::UpdateData(const uint8 *dta, int len) +{ + SHA256_Update(&mC, dta, len); +} + +void SHA256Hash::UpdateData(const std::string &str) +{ + UpdateData((uint8 const*)str.c_str(), str.length()); +} + +void SHA256Hash::UpdateBigNumbers(BigNumber* bn0, ...) +{ + va_list v; + BigNumber* bn; + + va_start(v, bn0); + bn = bn0; + while (bn) + { + UpdateData(bn->AsByteArray().get(), bn->GetNumBytes()); + bn = va_arg(v, BigNumber*); + } + va_end(v); +} + +void SHA256Hash::Initialize() +{ + SHA256_Init(&mC); +} + +void SHA256Hash::Finalize(void) +{ + SHA256_Final(mDigest, &mC); +} diff --git a/src/server/shared/Cryptography/SHA256.h b/src/server/shared/Cryptography/SHA256.h new file mode 100644 index 00000000000..78b3666dca8 --- /dev/null +++ b/src/server/shared/Cryptography/SHA256.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef SHA256_h__ +#define SHA256_h__ + +#include "Define.h" +#include <string> +#include <openssl/sha.h> + +class BigNumber; + +class SHA256Hash +{ + public: + SHA256Hash(); + ~SHA256Hash(); + + void UpdateBigNumbers(BigNumber* bn0, ...); + + void UpdateData(const uint8 *dta, int len); + void UpdateData(const std::string &str); + + void Initialize(); + void Finalize(); + + uint8 *GetDigest(void) { return mDigest; }; + int GetLength(void) const { return SHA256_DIGEST_LENGTH; }; + + private: + SHA256_CTX mC; + uint8 mDigest[SHA256_DIGEST_LENGTH]; +}; + +#endif // SHA256_h__ diff --git a/src/server/shared/Database/Implementation/LoginDatabase.cpp b/src/server/shared/Database/Implementation/LoginDatabase.cpp index de1e5b992e6..5623bd56a95 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.cpp +++ b/src/server/shared/Database/Implementation/LoginDatabase.cpp @@ -22,7 +22,7 @@ void LoginDatabaseConnection::DoPrepareStatements() if (!m_reconnecting) m_stmts.resize(MAX_LOGINDATABASE_STATEMENTS); - PrepareStatement(LOGIN_SEL_REALMLIST, "SELECT id, name, address, localAddress, localSubnetMask, port, icon, flag, timezone, allowedSecurityLevel, population, gamebuild FROM realmlist WHERE flag <> 3 ORDER BY name", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_REALMLIST, "SELECT id, name, address, localAddress, localSubnetMask, port, icon, flag, timezone, allowedSecurityLevel, population, gamebuild, Region, Battlegroup FROM realmlist WHERE flag <> 3 ORDER BY name", CONNECTION_SYNCH); PrepareStatement(LOGIN_DEL_EXPIRED_IP_BANS, "DELETE FROM ip_banned WHERE unbandate<>bandate AND unbandate<=UNIX_TIMESTAMP()", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_EXPIRED_ACCOUNT_BANS, "UPDATE account_banned SET active = 0 WHERE active = 1 AND unbandate<>bandate AND unbandate<=UNIX_TIMESTAMP()", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_IP_BANNED, "SELECT * FROM ip_banned WHERE ip = ?", CONNECTION_SYNCH); @@ -37,13 +37,14 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_SEL_SESSIONKEY, "SELECT a.sessionkey, a.id, aa.gmlevel FROM account a LEFT JOIN account_access aa ON (a.id = aa.id) WHERE username = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_UPD_VS, "UPDATE account SET v = ?, s = ? WHERE username = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_LOGONPROOF, "UPDATE account SET sessionkey = ?, last_ip = ?, last_login = NOW(), locale = ?, failed_logins = 0, os = ? WHERE username = ?", CONNECTION_SYNCH); - PrepareStatement(LOGIN_SEL_LOGONCHALLENGE, "SELECT a.sha_pass_hash, a.id, a.locked, a.lock_country, a.last_ip, aa.gmlevel, a.v, a.s, a.token_key FROM account a LEFT JOIN account_access aa ON (a.id = aa.id) WHERE a.username = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_LOGONCHALLENGE, "SELECT a.sha_pass_hash, a.id, a.locked, a.lock_country, a.last_ip, aa.gmlevel, a.v, a.s, a.token_key, a.battlenet_account FROM account a LEFT JOIN account_access aa ON (a.id = aa.id) WHERE a.username = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_LOGON_COUNTRY, "SELECT country FROM ip2nation WHERE ip < ? ORDER BY ip DESC LIMIT 0,1", CONNECTION_SYNCH); PrepareStatement(LOGIN_UPD_FAILEDLOGINS, "UPDATE account SET failed_logins = failed_logins + 1 WHERE username = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_FAILEDLOGINS, "SELECT id, failed_logins FROM account WHERE username = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_ID_BY_NAME, "SELECT id FROM account WHERE username = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_LIST_BY_NAME, "SELECT id, username FROM account WHERE username = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME, "SELECT id, sessionkey, last_ip, locked, expansion, mutetime, locale, recruiter, os FROM account WHERE username = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_ACCOUNT_INFO_BY_BNET, "SELECT id, sessionkey, last_ip, locked, expansion, mutetime, locale, recruiter, os FROM account WHERE battlenet_account = ? AND battlenet_index = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_LIST_BY_EMAIL, "SELECT id, username FROM account WHERE email = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_NUM_CHARS_ON_REALM, "SELECT numchars FROM realmcharacters WHERE realmid = ? AND acctid= ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_BY_IP, "SELECT id, username FROM account WHERE last_ip = ?", CONNECTION_SYNCH); @@ -101,4 +102,23 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_SEL_RBAC_ACCOUNT_PERMISSIONS, "SELECT permissionId, granted FROM rbac_account_permissions WHERE accountId = ? AND (realmId = ? OR realmId = -1) ORDER BY permissionId, realmId", CONNECTION_SYNCH); PrepareStatement(LOGIN_INS_RBAC_ACCOUNT_PERMISSION, "INSERT INTO rbac_account_permissions (accountId, permissionId, granted, realmId) VALUES (?, ?, ?, ?) ON DUPLICATE KEY UPDATE granted = VALUES(granted)", CONNECTION_ASYNC); PrepareStatement(LOGIN_DEL_RBAC_ACCOUNT_PERMISSION, "DELETE FROM rbac_account_permissions WHERE accountId = ? AND permissionId = ? AND (realmId = ? OR realmId = -1)", CONNECTION_ASYNC); + + PrepareStatement(LOGIN_SEL_BNET_ACCOUNT_INFO, "SELECT sha_pass_hash, id, locked, lock_country, last_ip, v, s FROM battlenet_accounts WHERE email = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_DEL_BNET_EXPIRED_BANS, "UPDATE battlenet_account_bans SET active = 0 WHERE active = 1 AND unbandate <> bandate AND unbandate <= UNIX_TIMESTAMP()", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_BNET_ACTIVE_ACCOUNT_BAN, "SELECT bandate, unbandate FROM battlenet_account_bans WHERE id = ? AND active = 1", CONNECTION_SYNCH); + PrepareStatement(LOGIN_UPD_BNET_VS_FIELDS, "UPDATE battlenet_accounts SET v = ?, s = ? WHERE email = ?", CONNECTION_ASYNC); + PrepareStatement(LOGIN_UPD_BNET_SESSION_KEY, "UPDATE battlenet_accounts SET sessionKey = ?, online = ? WHERE id = ?", CONNECTION_ASYNC); + PrepareStatement(LOGIN_SEL_BNET_RECONNECT_INFO, "SELECT ba.id, ba.sessionKey, a.id FROM battlenet_accounts ba LEFT JOIN account a ON ba.id = a.battlenet_account WHERE ba.email = ? AND a.battlenet_index = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_BNET_GAME_ACCOUNTS, "SELECT a.battlenet_index, a.id, ab.bandate, ab.unbandate, ab.active FROM account a LEFT JOIN account_banned ab ON a.id = ab.id WHERE battlenet_account = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_BNET_GAME_ACCOUNT, "SELECT a.id, ab.bandate, ab.unbandate, ab.active FROM account a LEFT JOIN account_banned ab ON a.id = ab.id WHERE battlenet_index = ? AND battlenet_account = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_UPD_BNET_LAST_LOGIN_INFO, "UPDATE battlenet_accounts SET last_ip = ?, last_login = NOW(), locale = ?, failed_logins = 0, os = ? WHERE id = ?", CONNECTION_ASYNC); + PrepareStatement(LOGIN_SEL_BNET_CHARACTER_COUNTS, "SELECT rc.numchars, r.id, r.Region, r.Battlegroup, r.gamebuild FROM realmcharacters rc INNER JOIN realmlist r ON rc.realmid = r.id WHERE rc.acctid = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_INS_BNET_ACCOUNT, "INSERT INTO battlenet_accounts (`email`,`sha_pass_hash`) VALUES (?, ?)", CONNECTION_ASYNC); + PrepareStatement(LOGIN_SEL_BNET_ACCOUNT_EMAIL_BY_ID, "SELECT email FROM battlenet_accounts WHERE id = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_BNET_ACCOUNT_ID_BY_EMAIL, "SELECT id FROM battlenet_accounts WHERE email = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_UPD_BNET_PASSWORD, "UPDATE account SET v = '', s = '', username = ?, sha_pass_hash = ? WHERE id = ?", CONNECTION_ASYNC); + PrepareStatement(LOGIN_SEL_BNET_CHECK_PASSWORD, "SELECT 1 FROM battlenet_accounts WHERE id = ? AND sha_pass_hash = ?", CONNECTION_ASYNC); + PrepareStatement(LOGIN_UPD_BNET_ACCOUNT_LOCK, "UPDATE battlenet_accounts SET locked = ? WHERE id = ?", CONNECTION_ASYNC); + PrepareStatement(LOGIN_UPD_BNET_ACCOUNT_LOCK_CONTRY, "UPDATE battlenet_accounts SET lock_country = ? WHERE id = ?", CONNECTION_ASYNC); + PrepareStatement(LOGIN_SEL_BNET_ACCOUNT_ID_BY_GAME_ACCOUNT, "SELECT battlenet_account FROM account WHERE id = ?", CONNECTION_SYNCH); } diff --git a/src/server/shared/Database/Implementation/LoginDatabase.h b/src/server/shared/Database/Implementation/LoginDatabase.h index 01f9fd973b6..3b4558874bc 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.h +++ b/src/server/shared/Database/Implementation/LoginDatabase.h @@ -62,6 +62,7 @@ enum LoginDatabaseStatements LOGIN_SEL_ACCOUNT_ID_BY_NAME, LOGIN_SEL_ACCOUNT_LIST_BY_NAME, LOGIN_SEL_ACCOUNT_INFO_BY_NAME, + LOGIN_SEL_ACCOUNT_INFO_BY_BNET, LOGIN_SEL_ACCOUNT_LIST_BY_EMAIL, LOGIN_SEL_NUM_CHARS_ON_REALM, LOGIN_SEL_ACCOUNT_BY_IP, @@ -120,6 +121,26 @@ enum LoginDatabaseStatements LOGIN_SEL_RBAC_ACCOUNT_PERMISSIONS, LOGIN_INS_RBAC_ACCOUNT_PERMISSION, LOGIN_DEL_RBAC_ACCOUNT_PERMISSION, + + LOGIN_SEL_BNET_ACCOUNT_INFO, + LOGIN_DEL_BNET_EXPIRED_BANS, + LOGIN_SEL_BNET_ACTIVE_ACCOUNT_BAN, + LOGIN_UPD_BNET_VS_FIELDS, + LOGIN_UPD_BNET_SESSION_KEY, + LOGIN_SEL_BNET_RECONNECT_INFO, + LOGIN_SEL_BNET_GAME_ACCOUNTS, + LOGIN_SEL_BNET_GAME_ACCOUNT, + LOGIN_UPD_BNET_LAST_LOGIN_INFO, + LOGIN_SEL_BNET_CHARACTER_COUNTS, + LOGIN_INS_BNET_ACCOUNT, + LOGIN_SEL_BNET_ACCOUNT_EMAIL_BY_ID, + LOGIN_SEL_BNET_ACCOUNT_ID_BY_EMAIL, + LOGIN_UPD_BNET_PASSWORD, + LOGIN_SEL_BNET_CHECK_PASSWORD, + LOGIN_UPD_BNET_ACCOUNT_LOCK, + LOGIN_UPD_BNET_ACCOUNT_LOCK_CONTRY, + LOGIN_SEL_BNET_ACCOUNT_ID_BY_GAME_ACCOUNT, + MAX_LOGINDATABASE_STATEMENTS }; diff --git a/src/server/shared/Debugging/WheatyExceptionReport.cpp b/src/server/shared/Debugging/WheatyExceptionReport.cpp index 81825c9055b..d5ad7f15a04 100644 --- a/src/server/shared/Debugging/WheatyExceptionReport.cpp +++ b/src/server/shared/Debugging/WheatyExceptionReport.cpp @@ -60,6 +60,7 @@ HANDLE WheatyExceptionReport::m_hReportFile; HANDLE WheatyExceptionReport::m_hDumpFile; HANDLE WheatyExceptionReport::m_hProcess; SymbolPairs WheatyExceptionReport::symbols; +std::stack<SymbolDetail> WheatyExceptionReport::symbolDetails; // Declare global instance of class WheatyExceptionReport g_WheatyExceptionReport; @@ -767,18 +768,21 @@ ULONG /*SymbolSize*/, PVOID UserContext) { - char szBuffer[1024 * 64]; + char szBuffer[WER_LARGE_BUFFER_SIZE]; + memset(szBuffer, 0, sizeof(szBuffer)); __try { ClearSymbols(); if (FormatSymbolValue(pSymInfo, (STACKFRAME64*)UserContext, szBuffer, sizeof(szBuffer))) - _tprintf(_T("\t%s\r\n"), szBuffer); + _tprintf(_T("%s"), szBuffer); } __except (EXCEPTION_EXECUTE_HANDLER) { - _tprintf(_T("punting on symbol %s\r\n"), pSymInfo->Name); + _tprintf(_T("punting on symbol %s, partial output:\r\n"), pSymInfo->Name); + if (szBuffer[0] != '\0') + _tprintf(_T("%s"), szBuffer); } return TRUE; @@ -797,12 +801,6 @@ unsigned /*cbBuffer*/) { char * pszCurrBuffer = pszBuffer; - // Indicate if the variable is a local or parameter - if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_PARAMETER) - pszCurrBuffer += sprintf(pszCurrBuffer, "Parameter "); - else if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_LOCAL) - pszCurrBuffer += sprintf(pszCurrBuffer, "Local "); - // If it's a function, don't do anything. if (pSym->Tag == SymTagFunction) // SymTagFunction from CVCONST.H from the DIA SDK return false; @@ -824,19 +822,25 @@ unsigned /*cbBuffer*/) // return false; } else if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_REGISTER) - { return false; // Don't try to report register variable - } else { pVariable = (DWORD_PTR)pSym->Address; // It must be a global variable } + pszCurrBuffer = PushSymbolDetail(pszCurrBuffer); + + // Indicate if the variable is a local or parameter + if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_PARAMETER) + symbolDetails.top().Prefix = "Parameter "; + else if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_LOCAL) + symbolDetails.top().Prefix = "Local "; + // Determine if the variable is a user defined type (UDT). IF so, bHandled // will return true. bool bHandled; pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, pSym->ModBase, pSym->TypeIndex, - 0, pVariable, bHandled, pSym->Name, ""); + 0, pVariable, bHandled, pSym->Name, "", false, true); if (!bHandled) { @@ -844,15 +848,19 @@ unsigned /*cbBuffer*/) // variable. Based on the size, we're assuming it's a char, WORD, or // DWORD. BasicType basicType = GetBasicType(pSym->TypeIndex, pSym->ModBase); - pszCurrBuffer += sprintf(pszCurrBuffer, rgBaseType[basicType]); + if (symbolDetails.top().Type.empty()) + symbolDetails.top().Type = rgBaseType[basicType]; // Emit the variable name - pszCurrBuffer += sprintf(pszCurrBuffer, "\'%s\'", pSym->Name); + if (pSym->Name[0] != '\0') + symbolDetails.top().Name = pSym->Name; - pszCurrBuffer = FormatOutputValue(pszCurrBuffer, basicType, pSym->Size, - (PVOID)pVariable); + char buffer[50]; + FormatOutputValue(buffer, basicType, pSym->Size, (PVOID)pVariable, sizeof(buffer)); + symbolDetails.top().Value = buffer; } + pszCurrBuffer = PopSymbolDetail(pszCurrBuffer); return true; } @@ -868,13 +876,15 @@ DWORD dwTypeIndex, unsigned nestingLevel, DWORD_PTR offset, bool & bHandled, -char* Name, -char* suffix) +const char* Name, +char* suffix, +bool newSymbol, +bool logChildren) { bHandled = false; - if (!StoreSymbol(dwTypeIndex, offset)) - return pszCurrBuffer; + if (newSymbol) + pszCurrBuffer = PushSymbolDetail(pszCurrBuffer); DWORD typeTag; if (!SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_SYMTAG, &typeTag)) @@ -890,19 +900,39 @@ char* suffix) if (wcscmp(pwszTypeName, L"std::basic_string<char,std::char_traits<char>,std::allocator<char> >") == 0) { LocalFree(pwszTypeName); - pszCurrBuffer += sprintf(pszCurrBuffer, " %s", "std::string"); - pszCurrBuffer = FormatOutputValue(pszCurrBuffer, btStdString, 0, (PVOID)offset); - pszCurrBuffer += sprintf(pszCurrBuffer, "\r\n"); + symbolDetails.top().Type = "std::string"; + char buffer[50]; + FormatOutputValue(buffer, btStdString, 0, (PVOID)offset, sizeof(buffer)); + symbolDetails.top().Value = buffer; + if (Name != NULL && Name[0] != '\0') + symbolDetails.top().Name = Name; bHandled = true; return pszCurrBuffer; } - pszCurrBuffer += sprintf(pszCurrBuffer, " %ls", pwszTypeName); + char buffer[200]; + wcstombs(buffer, pwszTypeName, sizeof(buffer)); + buffer[199] = '\0'; + if (Name != NULL && Name[0] != '\0') + { + symbolDetails.top().Type = buffer; + symbolDetails.top().Name = Name; + } + else if (buffer[0] != '\0') + symbolDetails.top().Name = buffer; + LocalFree(pwszTypeName); } + else if (Name != NULL && Name[0] != '\0') + symbolDetails.top().Name = Name; - if (strlen(suffix) > 0) - pszCurrBuffer += sprintf(pszCurrBuffer, "%s", suffix); + if (!StoreSymbol(dwTypeIndex, offset)) + { + // Skip printing address and base class if it has been printed already + if (typeTag == SymTagBaseClass) + bHandled = true; + return pszCurrBuffer; + } DWORD innerTypeID; switch (typeTag) @@ -910,11 +940,9 @@ char* suffix) case SymTagPointerType: if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_TYPEID, &innerTypeID)) { -#define MAX_NESTING_LEVEL 5 - if (nestingLevel >= MAX_NESTING_LEVEL) - break; + if (Name != NULL && Name[0] != '\0') + symbolDetails.top().Name = Name; - pszCurrBuffer += sprintf(pszCurrBuffer, " %s", Name); BOOL isReference; SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_IS_REFERENCE, &isReference); @@ -922,44 +950,56 @@ char* suffix) memset(addressStr, 0, sizeof(addressStr)); if (isReference) - addressStr[0] = '&'; + symbolDetails.top().Suffix += "&"; else - addressStr[0] = '*'; + symbolDetails.top().Suffix += "*"; - DWORD_PTR address = *(PDWORD_PTR)offset; - if (address == NULL) - { - pwszTypeName; - if (SymGetTypeInfo(m_hProcess, modBase, innerTypeID, TI_GET_SYMNAME, - &pwszTypeName)) - { - pszCurrBuffer += sprintf(pszCurrBuffer, " %ls", pwszTypeName); - LocalFree(pwszTypeName); - } + // Try to dereference the pointer in a try/except block since it might be invalid + DWORD_PTR address = DereferenceUnsafePointer(offset); - pszCurrBuffer += sprintf(pszCurrBuffer, "%s = NULL\r\n", addressStr); + char buffer[50]; + FormatOutputValue(buffer, btVoid, sizeof(PVOID), (PVOID)offset, sizeof(buffer)); + symbolDetails.top().Value = buffer; - bHandled = true; - return pszCurrBuffer; - } - else - { - FormatOutputValue(&addressStr[1], btVoid, sizeof(PVOID), (PVOID)offset); - pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1, - address, bHandled, "", addressStr); + if (nestingLevel >= WER_MAX_NESTING_LEVEL) + logChildren = false; + + // no need to log any children since the address is invalid anyway + if (address == NULL || address == DWORD_PTR(-1)) + logChildren = false; + + pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1, + address, bHandled, Name, addressStr, false, logChildren); - if (!bHandled) + if (!bHandled) + { + BasicType basicType = GetBasicType(dwTypeIndex, modBase); + if (symbolDetails.top().Type.empty()) + symbolDetails.top().Type = rgBaseType[basicType]; + + if (address == NULL) + symbolDetails.top().Value = "NULL"; + else if (address == DWORD_PTR(-1)) + symbolDetails.top().Value = "<Unable to read memory>"; + else { - BasicType basicType = GetBasicType(dwTypeIndex, modBase); - pszCurrBuffer += sprintf(pszCurrBuffer, rgBaseType[basicType]); // Get the size of the child member ULONG64 length; SymGetTypeInfo(m_hProcess, modBase, innerTypeID, TI_GET_LENGTH, &length); - pszCurrBuffer = FormatOutputValue(pszCurrBuffer, basicType, length, (PVOID)address); - pszCurrBuffer += sprintf(pszCurrBuffer, "\r\n"); - bHandled = true; - return pszCurrBuffer; + char buffer[50]; + FormatOutputValue(buffer, basicType, length, (PVOID)address, sizeof(buffer)); + symbolDetails.top().Value = buffer; } + bHandled = true; + return pszCurrBuffer; + } + else if (address == NULL) + symbolDetails.top().Value = "NULL"; + else if (address == DWORD_PTR(-1)) + { + symbolDetails.top().Value = "<Unable to read memory>"; + bHandled = true; + return pszCurrBuffer; } } break; @@ -970,13 +1010,80 @@ char* suffix) if (!SymGetTypeInfo(m_hProcess, modBase, innerTypeID, TI_GET_SYMTAG, &innerTypeTag)) break; - if (innerTypeTag == SymTagPointerType) + switch (innerTypeTag) { - pszCurrBuffer += sprintf(pszCurrBuffer, " %s", Name); + case SymTagUDT: + if (nestingLevel >= WER_MAX_NESTING_LEVEL) + logChildren = false; + pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1, + offset, bHandled, symbolDetails.top().Name.c_str(), "", false, logChildren); + break; + case SymTagPointerType: + if (Name != NULL && Name[0] != '\0') + symbolDetails.top().Name = Name; + pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1, + offset, bHandled, symbolDetails.top().Name.c_str(), "", false, logChildren); + break; + case SymTagArrayType: + pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1, + offset, bHandled, symbolDetails.top().Name.c_str(), "", false, logChildren); + break; + default: + break; + } + } + break; + case SymTagArrayType: + if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_TYPEID, &innerTypeID)) + { + symbolDetails.top().HasChildren = true; + + BasicType basicType = btNoType; + pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1, + offset, bHandled, Name, "", false, false); + + // Set Value back to an empty string since the Array object itself has no value, only its elements have + symbolDetails.top().Value = ""; + + DWORD elementsCount; + if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_COUNT, &elementsCount)) + symbolDetails.top().Suffix += "[" + std::to_string(elementsCount) + "]"; + else + symbolDetails.top().Suffix += "[<unknown count>]"; - pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1, - offset, bHandled, "", ""); + if (!bHandled) + { + basicType = GetBasicType(dwTypeIndex, modBase); + if (symbolDetails.top().Type.empty()) + symbolDetails.top().Type = rgBaseType[basicType]; + bHandled = true; + } + + // Get the size of the child member + ULONG64 length; + SymGetTypeInfo(m_hProcess, modBase, innerTypeID, TI_GET_LENGTH, &length); + + char buffer[50]; + switch (basicType) + { + case btChar: + case btStdString: + FormatOutputValue(buffer, basicType, length, (PVOID)offset, sizeof(buffer)); + symbolDetails.top().Value = buffer; + break; + default: + for (DWORD index = 0; index < elementsCount && index < WER_MAX_ARRAY_ELEMENTS_COUNT; index++) + { + pszCurrBuffer = PushSymbolDetail(pszCurrBuffer); + symbolDetails.top().Suffix += "[" + std::to_string(index) + "]"; + FormatOutputValue(buffer, basicType, length, (PVOID)(offset + length * index), sizeof(buffer)); + symbolDetails.top().Value = buffer; + pszCurrBuffer = PopSymbolDetail(pszCurrBuffer); + } + break; } + + return pszCurrBuffer; } break; case SymTagBaseType: @@ -1013,26 +1120,37 @@ char* suffix) return pszCurrBuffer; } - // Append a line feed - pszCurrBuffer += sprintf(pszCurrBuffer, "\r\n"); - // Iterate through each of the children for (unsigned i = 0; i < dwChildrenCount; i++) { DWORD symTag; SymGetTypeInfo(m_hProcess, modBase, children.ChildId[i], TI_GET_SYMTAG, &symTag); - if (symTag == SymTagFunction || symTag == SymTagTypedef) + if (symTag == SymTagFunction || + symTag == SymTagEnum || + symTag == SymTagTypedef || + symTag == SymTagVTable) continue; - // Add appropriate indentation level (since this routine is recursive) - for (unsigned j = 0; j <= nestingLevel+1; j++) - pszCurrBuffer += sprintf(pszCurrBuffer, "\t"); + // Ignore static fields + DWORD dataKind; + SymGetTypeInfo(m_hProcess, modBase, children.ChildId[i], TI_GET_DATAKIND, &dataKind); + if (dataKind == DataIsStaticLocal || + dataKind == DataIsGlobal || + dataKind == DataIsStaticMember) + continue; + + + symbolDetails.top().HasChildren = true; + if (!logChildren) + { + bHandled = false; + return pszCurrBuffer; + } // Recurse for each of the child types bool bHandled2; BasicType basicType = GetBasicType(children.ChildId[i], modBase); - pszCurrBuffer += sprintf(pszCurrBuffer, rgBaseType[basicType]); // Get the offset of the child member, relative to its parent DWORD dwMemberOffset; @@ -1044,11 +1162,14 @@ char* suffix) pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, children.ChildId[i], nestingLevel+1, - dwFinalOffset, bHandled2, ""/*Name */, ""); + dwFinalOffset, bHandled2, ""/*Name */, "", true, true); // If the child wasn't a UDT, format it appropriately if (!bHandled2) { + if (symbolDetails.top().Type.empty()) + symbolDetails.top().Type = rgBaseType[basicType]; + // Get the real "TypeId" of the child. We need this for the // SymGetTypeInfo(TI_GET_TYPEID) call below. DWORD typeId; @@ -1059,75 +1180,75 @@ char* suffix) ULONG64 length; SymGetTypeInfo(m_hProcess, modBase, typeId, TI_GET_LENGTH, &length); - pszCurrBuffer = FormatOutputValue(pszCurrBuffer, basicType, - length, (PVOID)dwFinalOffset); - - pszCurrBuffer += sprintf(pszCurrBuffer, "\r\n"); + char buffer[50]; + FormatOutputValue(buffer, basicType, length, (PVOID)dwFinalOffset, sizeof(buffer)); + symbolDetails.top().Value = buffer; } + + pszCurrBuffer = PopSymbolDetail(pszCurrBuffer); } bHandled = true; return pszCurrBuffer; } -char * WheatyExceptionReport::FormatOutputValue(char * pszCurrBuffer, +void WheatyExceptionReport::FormatOutputValue(char * pszCurrBuffer, BasicType basicType, DWORD64 length, -PVOID pAddress) +PVOID pAddress, +size_t bufferSize) { __try { switch (basicType) { case btChar: - pszCurrBuffer += sprintf(pszCurrBuffer, " = \"%s\"", pAddress); + { + if (strlen((char*)pAddress) > bufferSize - 6) + pszCurrBuffer += sprintf(pszCurrBuffer, "\"%.*s...\"", bufferSize - 6, (char*)pAddress); + else + pszCurrBuffer += sprintf(pszCurrBuffer, "\"%s\"", (char*)pAddress); break; + } case btStdString: - pszCurrBuffer += sprintf(pszCurrBuffer, " = \"%s\"", static_cast<std::string*>(pAddress)->c_str()); + { + std::string* value = static_cast<std::string*>(pAddress); + if (value->length() > bufferSize - 6) + pszCurrBuffer += sprintf(pszCurrBuffer, "\"%.*s...\"", bufferSize - 6, value->c_str()); + else + pszCurrBuffer += sprintf(pszCurrBuffer, "\"%s\"", value->c_str()); break; + } default: // Format appropriately (assuming it's a 1, 2, or 4 bytes (!!!) if (length == 1) - pszCurrBuffer += sprintf(pszCurrBuffer, " = %X", *(PBYTE)pAddress); + pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", *(PBYTE)pAddress); else if (length == 2) - pszCurrBuffer += sprintf(pszCurrBuffer, " = %X", *(PWORD)pAddress); + pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", *(PWORD)pAddress); else if (length == 4) { if (basicType == btFloat) - { - pszCurrBuffer += sprintf(pszCurrBuffer, " = %f", *(PFLOAT)pAddress); - } - else if (basicType == btChar) - { - if (!IsBadStringPtr(*(PSTR*)pAddress, 32)) - { - pszCurrBuffer += sprintf(pszCurrBuffer, " = \"%.31s\"", - *(PSTR*)pAddress); - } - else - pszCurrBuffer += sprintf(pszCurrBuffer, " = %X", - *(PDWORD)pAddress); - } + pszCurrBuffer += sprintf(pszCurrBuffer, "%f", *(PFLOAT)pAddress); else - pszCurrBuffer += sprintf(pszCurrBuffer, " = %X", *(PDWORD)pAddress); + pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", *(PDWORD)pAddress); } else if (length == 8) { if (basicType == btFloat) { - pszCurrBuffer += sprintf(pszCurrBuffer, " = %lf", + pszCurrBuffer += sprintf(pszCurrBuffer, "%lf", *(double *)pAddress); } else - pszCurrBuffer += sprintf(pszCurrBuffer, " = %I64X", + pszCurrBuffer += sprintf(pszCurrBuffer, "0x%I64X", *(DWORD64*)pAddress); } else { #if _WIN64 - pszCurrBuffer += sprintf(pszCurrBuffer, " = %I64X", (DWORD64*)pAddress); + pszCurrBuffer += sprintf(pszCurrBuffer, "0x%I64X", (DWORD64*)pAddress); #else - pszCurrBuffer += sprintf(pszCurrBuffer, " = %X", (PDWORD)pAddress); + pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", (PDWORD)pAddress); #endif } break; @@ -1136,13 +1257,11 @@ PVOID pAddress) __except (EXCEPTION_EXECUTE_HANDLER) { #if _WIN64 - pszCurrBuffer += sprintf(pszCurrBuffer, " <Unable to read memory> = %I64X", (DWORD64*)pAddress); + pszCurrBuffer += sprintf(pszCurrBuffer, "0x%I64X <Unable to read memory>", (DWORD64*)pAddress); #else - pszCurrBuffer += sprintf(pszCurrBuffer, " <Unable to read memory> = %X", (PDWORD)pAddress); + pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X <Unable to read memory>", (PDWORD)pAddress); #endif } - - return pszCurrBuffer; } BasicType @@ -1170,13 +1289,25 @@ WheatyExceptionReport::GetBasicType(DWORD typeIndex, DWORD64 modBase) return btNoType; } +DWORD_PTR WheatyExceptionReport::DereferenceUnsafePointer(DWORD_PTR address) +{ + __try + { + return *(PDWORD_PTR)address; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return DWORD_PTR(-1); + } +} + //============================================================================ // Helper function that writes to the report file, and allows the user to use // printf style formating //============================================================================ int __cdecl WheatyExceptionReport::_tprintf(const TCHAR * format, ...) { - TCHAR szBuff[1024 * 64]; + TCHAR szBuff[WER_LARGE_BUFFER_SIZE]; int retValue; DWORD cbWritten; va_list argptr; @@ -1198,6 +1329,41 @@ bool WheatyExceptionReport::StoreSymbol(DWORD type, DWORD_PTR offset) void WheatyExceptionReport::ClearSymbols() { symbols.clear(); + while (!symbolDetails.empty()) + symbolDetails.pop(); +} + +char* WheatyExceptionReport::PushSymbolDetail(char* pszCurrBuffer) +{ + // Log current symbol and then add another to the stack to keep the hierarchy format + pszCurrBuffer = PrintSymbolDetail(pszCurrBuffer); + symbolDetails.emplace(); + return pszCurrBuffer; +} + +char* WheatyExceptionReport::PopSymbolDetail(char* pszCurrBuffer) +{ + pszCurrBuffer = PrintSymbolDetail(pszCurrBuffer); + symbolDetails.pop(); + return pszCurrBuffer; +} + +char* WheatyExceptionReport::PrintSymbolDetail(char* pszCurrBuffer) +{ + if (symbolDetails.empty()) + return pszCurrBuffer; + + // Don't log anything if has been logged already or if it's empty + if (symbolDetails.top().Logged || symbolDetails.top().empty()) + return pszCurrBuffer; + + // Add appropriate indentation level (since this routine is recursive) + for (size_t i = 0; i < symbolDetails.size(); i++) + pszCurrBuffer += sprintf(pszCurrBuffer, "\t"); + + pszCurrBuffer += sprintf(pszCurrBuffer, "%s\r\n", symbolDetails.top().ToString().c_str()); + + return pszCurrBuffer; } #endif // _WIN32 diff --git a/src/server/shared/Debugging/WheatyExceptionReport.h b/src/server/shared/Debugging/WheatyExceptionReport.h index e1cc3050929..9137b91aac9 100644 --- a/src/server/shared/Debugging/WheatyExceptionReport.h +++ b/src/server/shared/Debugging/WheatyExceptionReport.h @@ -5,12 +5,13 @@ #include <dbghelp.h> #include <set> -#if _MSC_VER < 1400 -# define countof(array) (sizeof(array) / sizeof(array[0])) -#else -# include <stdlib.h> -# define countof _countof -#endif // _MSC_VER < 1400 +#include <stdlib.h> +#include <stack> +#define countof _countof + +#define WER_MAX_ARRAY_ELEMENTS_COUNT 10 +#define WER_MAX_NESTING_LEVEL 5 +#define WER_LARGE_BUFFER_SIZE 1024 * 128 enum BasicType // Stolen from CVCONST.H in the DIA 2.0 SDK { @@ -37,40 +38,54 @@ enum BasicType // Stolen from CVCON btStdString = 101 }; +enum DataKind // Stolen from CVCONST.H in the DIA 2.0 SDK +{ + DataIsUnknown, + DataIsLocal, + DataIsStaticLocal, + DataIsParam, + DataIsObjectPtr, + DataIsFileStatic, + DataIsGlobal, + DataIsMember, + DataIsStaticMember, + DataIsConstant +}; + const char* const rgBaseType[] = { - " <user defined> ", // btNoType = 0, - " void ", // btVoid = 1, - " char* ", // btChar = 2, - " wchar_t* ", // btWChar = 3, - " signed char ", - " unsigned char ", - " int ", // btInt = 6, - " unsigned int ", // btUInt = 7, - " float ", // btFloat = 8, - " <BCD> ", // btBCD = 9, - " bool ", // btBool = 10, - " short ", - " unsigned short ", - " long ", // btLong = 13, - " unsigned long ", // btULong = 14, - " __int8 ", - " __int16 ", - " __int32 ", - " __int64 ", - " __int128 ", - " unsigned __int8 ", - " unsigned __int16 ", - " unsigned __int32 ", - " unsigned __int64 ", - " unsigned __int128 ", - " <currency> ", // btCurrency = 25, - " <date> ", // btDate = 26, - " VARIANT ", // btVariant = 27, - " <complex> ", // btComplex = 28, - " <bit> ", // btBit = 29, - " BSTR ", // btBSTR = 30, - " HRESULT " // btHresult = 31 + "<user defined>", // btNoType = 0, + "void", // btVoid = 1, + "char",//char* // btChar = 2, + "wchar_t*", // btWChar = 3, + "signed char", + "unsigned char", + "int", // btInt = 6, + "unsigned int", // btUInt = 7, + "float", // btFloat = 8, + "<BCD>", // btBCD = 9, + "bool", // btBool = 10, + "short", + "unsigned short", + "long", // btLong = 13, + "unsigned long", // btULong = 14, + "int8", + "int16", + "int32", + "int64", + "int128", + "uint8", + "uint16", + "uint32", + "uint64", + "uint128", + "<currency>", // btCurrency = 25, + "<date>", // btDate = 26, + "VARIANT", // btVariant = 27, + "<complex>", // btComplex = 28, + "<bit>", // btBit = 29, + "BSTR", // btBSTR = 30, + "HRESULT" // btHresult = 31 }; struct SymbolPair @@ -92,6 +107,39 @@ struct SymbolPair }; typedef std::set<SymbolPair> SymbolPairs; +struct SymbolDetail +{ + SymbolDetail() : Prefix(), Type(), Suffix(), Name(), Value(), Logged(false), HasChildren(false) {} + + std::string ToString() + { + Logged = true; + std::string formatted = Prefix + Type + Suffix; + if (!Name.empty()) + { + if (!formatted.empty()) + formatted += " "; + formatted += Name; + } + if (!Value.empty()) + formatted += " = " + Value; + return formatted; + } + + bool empty() const + { + return Value.empty() && !HasChildren; + } + + std::string Prefix; + std::string Type; + std::string Suffix; + std::string Name; + std::string Value; + bool Logged; + bool HasChildren; +}; + class WheatyExceptionReport { public: @@ -122,11 +170,12 @@ class WheatyExceptionReport static bool FormatSymbolValue(PSYMBOL_INFO, STACKFRAME64 *, char * pszBuffer, unsigned cbBuffer); - static char * DumpTypeIndex(char *, DWORD64, DWORD, unsigned, DWORD_PTR, bool &, char*, char*); + static char * DumpTypeIndex(char *, DWORD64, DWORD, unsigned, DWORD_PTR, bool &, const char*, char*, bool, bool); - static char * FormatOutputValue(char * pszCurrBuffer, BasicType basicType, DWORD64 length, PVOID pAddress); + static void FormatOutputValue(char * pszCurrBuffer, BasicType basicType, DWORD64 length, PVOID pAddress, size_t bufferSize); static BasicType GetBasicType(DWORD typeIndex, DWORD64 modBase); + static DWORD_PTR DereferenceUnsafePointer(DWORD_PTR address); static int __cdecl _tprintf(const TCHAR * format, ...); @@ -141,6 +190,12 @@ class WheatyExceptionReport static HANDLE m_hDumpFile; static HANDLE m_hProcess; static SymbolPairs symbols; + static std::stack<SymbolDetail> symbolDetails; + + static char* PushSymbolDetail(char* pszCurrBuffer); + static char* PopSymbolDetail(char* pszCurrBuffer); + static char* PrintSymbolDetail(char* pszCurrBuffer); + }; extern WheatyExceptionReport g_WheatyExceptionReport; // global instance of class diff --git a/src/server/shared/Utilities/Util.cpp b/src/server/shared/Utilities/Util.cpp index f2a6f1b7622..4c54492f5ad 100644 --- a/src/server/shared/Utilities/Util.cpp +++ b/src/server/shared/Utilities/Util.cpp @@ -524,6 +524,17 @@ void vutf8printf(FILE* out, const char *str, va_list* ap) #endif } +bool Utf8ToUpperOnlyLatin(std::string& utf8String) +{ + std::wstring wstr; + if (!Utf8toWStr(utf8String, wstr)) + return false; + + std::transform(wstr.begin(), wstr.end(), wstr.begin(), wcharToUpperOnlyLatin); + + return WStrToUtf8(wstr, utf8String); +} + std::string ByteArrayToHexStr(uint8 const* bytes, uint32 arrayLen, bool reverse /* = false */) { int32 init = 0; @@ -547,3 +558,37 @@ std::string ByteArrayToHexStr(uint8 const* bytes, uint32 arrayLen, bool reverse return ss.str(); } + +uint32 EventMap::GetTimeUntilEvent(uint32 eventId) const +{ + for (EventStore::const_iterator itr = _eventMap.begin(); itr != _eventMap.end(); ++itr) + if (eventId == (itr->second & 0x0000FFFF)) + return itr->first - _time; + + return std::numeric_limits<uint32>::max(); +} + +void HexStrToByteArray(std::string const& str, uint8* out, bool reverse /*= false*/) +{ + // string must have even number of characters + if (str.length() & 1) + return; + + int32 init = 0; + int32 end = str.length(); + int8 op = 1; + + if (reverse) + { + init = str.length() - 2; + end = -2; + op = -1; + } + + uint32 j = 0; + for (int32 i = init; i != end; i += 2 * op) + { + char buffer[3] = { str[i], str[i + 1], '\0' }; + out[j++] = strtoul(buffer, NULL, 16); + } +} diff --git a/src/server/shared/Utilities/Util.h b/src/server/shared/Utilities/Util.h index 4d7a37d77cf..538264c9cfe 100644 --- a/src/server/shared/Utilities/Util.h +++ b/src/server/shared/Utilities/Util.h @@ -344,6 +344,7 @@ bool consoleToUtf8(const std::string& conStr, std::string& utf8str); bool Utf8FitTo(const std::string& str, std::wstring search); void utf8printf(FILE* out, const char *str, ...); void vutf8printf(FILE* out, const char *str, va_list* ap); +bool Utf8ToUpperOnlyLatin(std::string& utf8String); bool IsIPAddress(char const* ipaddress); @@ -356,6 +357,7 @@ std::string GetAddressString(ACE_INET_Addr const& addr); uint32 CreatePIDFile(const std::string& filename); std::string ByteArrayToHexStr(uint8 const* bytes, uint32 length, bool reverse = false); +void HexStrToByteArray(std::string const& str, uint8* out, bool reverse = false); #endif //handler for operations on large flags @@ -866,14 +868,7 @@ class EventMap * @param Id of the event. * @return Time of next event. */ - uint32 GetTimeUntilEvent(uint32 eventId) const - { - for (EventStore::const_iterator itr = _eventMap.begin(); itr != _eventMap.end(); ++itr) - if (eventId == (itr->second & 0x0000FFFF)) - return itr->first - _time; - - return std::numeric_limits<uint32>::max(); - } + uint32 GetTimeUntilEvent(uint32 eventId) const; private: /** diff --git a/src/server/worldserver/RemoteAccess/RASocket.cpp b/src/server/worldserver/RemoteAccess/RASocket.cpp index 6e621ddfffe..f2c7a8e0f02 100644 --- a/src/server/worldserver/RemoteAccess/RASocket.cpp +++ b/src/server/worldserver/RemoteAccess/RASocket.cpp @@ -184,7 +184,7 @@ int RASocket::check_access_level(const std::string& user) { std::string safeUser = user; - AccountMgr::normalizeString(safeUser); + Utf8ToUpperOnlyLatin(safeUser); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_ACCESS); stmt->setString(0, safeUser); @@ -215,10 +215,10 @@ int RASocket::check_access_level(const std::string& user) int RASocket::check_password(const std::string& user, const std::string& pass) { std::string safe_user = user; - AccountMgr::normalizeString(safe_user); + Utf8ToUpperOnlyLatin(safe_user); std::string safe_pass = pass; - AccountMgr::normalizeString(safe_pass); + Utf8ToUpperOnlyLatin(safe_pass); std::string hash = AccountMgr::CalculateShaPassHash(safe_user, safe_pass); |
