From cf1e9df70faf8208304093a1f1723c9ab3146da0 Mon Sep 17 00:00:00 2001 From: Lolwutt Date: Tue, 24 Oct 2017 22:39:20 -0400 Subject: [PATCH] Added monitoring for packets that are double sent - should be more accurate --- Deeps/Deeps.h | 442 +++++----- Deeps/Deeps.vcxproj | 343 +++---- Deeps/Deeps.vcxproj.filters | 68 +- Deeps/Exports.def | 8 +- Deeps/main.cpp | 1669 ++++++++++++++++++----------------- release/plugins/Deeps.dll | Bin 112128 -> 112640 bytes 6 files changed, 1281 insertions(+), 1249 deletions(-) diff --git a/Deeps/Deeps.h b/Deeps/Deeps.h index 4d981f7..e120b88 100644 --- a/Deeps/Deeps.h +++ b/Deeps/Deeps.h @@ -1,220 +1,222 @@ -/** -* Copyright (c) 2011-2014 - Ashita Development Team -* -* Ashita 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. -* -* Ashita 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 Ashita. If not, see . -*/ - -#ifndef __ASHITA_Deeps_H_INCLUDED__ -#define __ASHITA_Deeps_H_INCLUDED__ - -#if defined (_MSC_VER) && (_MSC_VER >= 1020) -#pragma once -#endif - -enum REACTION -{ - REACTION_NONE = 0x00, - REACTION_MISS = 0x01, - REACTION_PARRY = 0x03, - REACTION_BLOCK = 0x04, - REACTION_HIT = 0x08, - REACTION_EVADE = 0x09, - REACTION_HIT2 = 0x10, - REACTION_GUARD = 0x14 -}; - -enum SPECEFFECT -{ - SPECEFFECT_NONE = 0x00, - SPECEFFECT_BLOOD = 0x02, - SPECEFFECT_HIT = 0x10, - SPECEFFECT_RAISE = 0x11, - SPECEFFECT_RECOIL = 0x20, - SPECEFFECT_CRITICAL_HIT = 0x22 -}; - -/** - * @brief Required includes for an extension. - */ -#include "C:\Ashita 3\plugins\ADK\Ashita.h" -#include -#include -#include - -struct damage_t -{ - uint64_t total; - uint32_t max; - uint32_t min; - uint32_t count; - - damage_t() - { - total = 0; - max = 0; - min = 0; - count = 0; - } - bool operator > (const damage_t& o) const - { - return (count > o.count); - } - uint32_t avg() - { - return count > 0 ? (total / count) : 0; - } -}; - -struct source_t -{ - std::string name; - std::map damage; - - source_t() - { - - } - - uint64_t total() const - { - uint64_t tot = 0; - for (auto d : damage) - { - tot += d.second.total; - } - return tot; - } - - bool operator > (const source_t& o) const - { - return (total() > o.total()); - } -}; - -struct entitysources_t -{ - std::string name; - uint32_t color; - std::map sources; - - uint64_t total() const - { - int64_t total = 0; - for (auto s : sources) - { - total += s.second.total(); - } - return total; - } - bool operator == (const entitysources_t& o) const - { - return (total() == o.total()); - } - - bool operator > (const entitysources_t& o) const - { - return (total() > o.total()); - } -}; - -std::map entities; -std::map clickMap; - -static const std::vector hitMessages = { 1, 2, 77, 132, 157, 161, 163, 185, 187, 197, 227, 264, 281, 317, 352, 413, 522, 576, 577 }; -static const std::vector critMessages = { 67, 252, 265, 274, 353, 379 }; -static const std::vector missMessages = { 15, 85, 158, 188, 245, 284, 324, 354 }; -static const std::vector evadeMessages = { 14, 30, 31, 32, 33, 189, 248, 282, 283, 323, 355 }; -static const std::vector parryMessages = { 69, 70 }; - -static const std::vector Colors = { D3DCOLOR_ARGB(255, 12, 0, 155), D3DCOLOR_ARGB(255, 140, 0, 0), D3DCOLOR_ARGB(255, 255, 177, 32), D3DCOLOR_ARGB(255, 143, 143, 143), - D3DCOLOR_ARGB(255, 68, 68, 68), D3DCOLOR_ARGB(255, 255, 0, 0), D3DCOLOR_ARGB(255, 0, 164, 49), D3DCOLOR_ARGB(255, 198, 198, 0), - D3DCOLOR_ARGB(255, 116, 0, 145), D3DCOLOR_ARGB(255, 165, 153, 10), D3DCOLOR_ARGB(255, 184, 128, 10), D3DCOLOR_ARGB(255, 224, 0, 230), - D3DCOLOR_ARGB(255, 234, 100, 0), D3DCOLOR_ARGB(255, 119, 0, 0), D3DCOLOR_ARGB(255, 130, 17, 255), D3DCOLOR_ARGB(255, 79, 196, 0), - D3DCOLOR_ARGB(255, 0, 16, 217), D3DCOLOR_ARGB(255, 136, 68, 0), D3DCOLOR_ARGB(255, 244, 98, 0), D3DCOLOR_ARGB(255, 15, 190, 220), - D3DCOLOR_ARGB(255, 0, 123, 145) }; - -void g_onClick(int, void*, float, float); - -/** - * @brief Global copy of our plugin data. - */ -plugininfo_t* g_PluginInfo = NULL; - -/** - * @brief Our Main Plugin Class - * - * @note The main class of your plugin MUST use PluginBase as a base class. This is the - * internal base class that Ashita uses to communicate with your plugin! - */ -class Deeps : IPlugin -{ - /** - * @brief Internal class variables. - */ - IAshitaCore* m_AshitaCore; - ILogManager* m_LogManager; - DWORD m_PluginId; - IDirect3DDevice8* m_Direct3DDevice; - -private: - source_t* getDamageSource(entitysources_t* entityInfo, uint8_t actionType, uint16_t actionID); - bool updateDamageSource(source_t* source, uint16_t message, uint32_t damage); - void repairBars(IFontObject* deepsBase, uint8_t size); - void report(char mode, int max); - uint16_t getIndex(std::function); - uint32_t m_charInfo; - std::string m_sourceInfo; - uint8_t m_bars; - bool m_debug; - -public: - /** - * @brief Constructor and deconstructor. - */ - Deeps(void); - virtual ~Deeps(void); - - /** - * @brief GetPluginData implementation. - */ - plugininfo_t GetPluginInfo(void); - - /** - * @brief PluginBase virtual overrides. - */ - bool Initialize(IAshitaCore* core, ILogManager* log, uint32_t id); - void Release(void); - bool HandleCommand(const char* command, int32_t type); - bool HandleIncomingText(int16_t mode, const char* message, int16_t* modifiedMode, char* modifiedMessage, bool blocked); - bool HandleIncomingPacket(uint16_t id, uint32_t size, void* data, void* modified, bool blocked); - bool HandleOutgoingPacket(uint16_t id, uint32_t size, void* data, void* modified, bool blocked); - bool Direct3DInitialize(IDirect3DDevice8* device); - void Direct3DRelease(void); - void Direct3DPreRender(void); - void Direct3DRender(void); - void onClick(int, IFontObject*, float, float); -}; - -// Global pointer to this - -Deeps* g_Deeps = NULL; - -/** - * @brief Required Plugin Exports - */ -__declspec(dllexport) double __stdcall GetInterfaceVersion(void); -__declspec(dllexport) void __stdcall CreatePluginInfo(plugininfo_t* lpBuffer); -__declspec(dllexport) IPlugin* __stdcall CreatePlugin(void); - -#endif // __ASHITA_Deeps_H_INCLUDED__ +/** +* Copyright (c) 2011-2014 - Ashita Development Team +* +* Ashita 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. +* +* Ashita 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 Ashita. If not, see . +*/ + +#ifndef __ASHITA_Deeps_H_INCLUDED__ +#define __ASHITA_Deeps_H_INCLUDED__ + +#if defined (_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +enum REACTION +{ + REACTION_NONE = 0x00, + REACTION_MISS = 0x01, + REACTION_PARRY = 0x03, + REACTION_BLOCK = 0x04, + REACTION_HIT = 0x08, + REACTION_EVADE = 0x09, + REACTION_HIT2 = 0x10, + REACTION_GUARD = 0x14 +}; + +enum SPECEFFECT +{ + SPECEFFECT_NONE = 0x00, + SPECEFFECT_BLOOD = 0x02, + SPECEFFECT_HIT = 0x10, + SPECEFFECT_RAISE = 0x11, + SPECEFFECT_RECOIL = 0x20, + SPECEFFECT_CRITICAL_HIT = 0x22 +}; + +/** + * @brief Required includes for an extension. + */ +#include "C:\Ashita 3\plugins\ADK\Ashita.h" +#include +#include +#include +#include + +struct damage_t +{ + uint64_t total; + uint32_t max; + uint32_t min; + uint32_t count; + + damage_t() + { + total = 0; + max = 0; + min = 0; + count = 0; + } + bool operator > (const damage_t& o) const + { + return (count > o.count); + } + uint32_t avg() + { + return count > 0 ? (total / count) : 0; + } +}; + +struct source_t +{ + std::string name; + std::map damage; + + source_t() + { + + } + + uint64_t total() const + { + uint64_t tot = 0; + for (auto d : damage) + { + tot += d.second.total; + } + return tot; + } + + bool operator > (const source_t& o) const + { + return (total() > o.total()); + } +}; + +struct entitysources_t +{ + std::string name; + uint32_t color; + std::map sources; + + uint64_t total() const + { + int64_t total = 0; + for (auto s : sources) + { + total += s.second.total(); + } + return total; + } + bool operator == (const entitysources_t& o) const + { + return (total() == o.total()); + } + + bool operator > (const entitysources_t& o) const + { + return (total() > o.total()); + } +}; + +std::map entities; +std::map clickMap; + +static const std::vector hitMessages = { 1, 2, 77, 132, 157, 161, 163, 185, 187, 197, 227, 264, 281, 317, 352, 413, 522, 576, 577 }; +static const std::vector critMessages = { 67, 252, 265, 274, 353, 379 }; +static const std::vector missMessages = { 15, 85, 158, 188, 245, 284, 324, 354 }; +static const std::vector evadeMessages = { 14, 30, 31, 32, 33, 189, 248, 282, 283, 323, 355 }; +static const std::vector parryMessages = { 69, 70 }; + +static const std::vector Colors = { D3DCOLOR_ARGB(255, 12, 0, 155), D3DCOLOR_ARGB(255, 140, 0, 0), D3DCOLOR_ARGB(255, 255, 177, 32), D3DCOLOR_ARGB(255, 143, 143, 143), + D3DCOLOR_ARGB(255, 68, 68, 68), D3DCOLOR_ARGB(255, 255, 0, 0), D3DCOLOR_ARGB(255, 0, 164, 49), D3DCOLOR_ARGB(255, 198, 198, 0), + D3DCOLOR_ARGB(255, 116, 0, 145), D3DCOLOR_ARGB(255, 165, 153, 10), D3DCOLOR_ARGB(255, 184, 128, 10), D3DCOLOR_ARGB(255, 224, 0, 230), + D3DCOLOR_ARGB(255, 234, 100, 0), D3DCOLOR_ARGB(255, 119, 0, 0), D3DCOLOR_ARGB(255, 130, 17, 255), D3DCOLOR_ARGB(255, 79, 196, 0), + D3DCOLOR_ARGB(255, 0, 16, 217), D3DCOLOR_ARGB(255, 136, 68, 0), D3DCOLOR_ARGB(255, 244, 98, 0), D3DCOLOR_ARGB(255, 15, 190, 220), + D3DCOLOR_ARGB(255, 0, 123, 145) }; + +void g_onClick(int, void*, float, float); + +/** + * @brief Global copy of our plugin data. + */ +plugininfo_t* g_PluginInfo = NULL; + +/** + * @brief Our Main Plugin Class + * + * @note The main class of your plugin MUST use PluginBase as a base class. This is the + * internal base class that Ashita uses to communicate with your plugin! + */ +class Deeps : IPlugin +{ + /** + * @brief Internal class variables. + */ + IAshitaCore* m_AshitaCore; + ILogManager* m_LogManager; + DWORD m_PluginId; + IDirect3DDevice8* m_Direct3DDevice; + std::list m_Packets; + +private: + source_t* getDamageSource(entitysources_t* entityInfo, uint8_t actionType, uint16_t actionID); + bool updateDamageSource(source_t* source, uint16_t message, uint32_t damage); + void repairBars(IFontObject* deepsBase, uint8_t size); + void report(char mode, int max); + uint16_t getIndex(std::function); + uint32_t m_charInfo; + std::string m_sourceInfo; + uint8_t m_bars; + bool m_debug; + +public: + /** + * @brief Constructor and deconstructor. + */ + Deeps(void); + virtual ~Deeps(void); + + /** + * @brief GetPluginData implementation. + */ + plugininfo_t GetPluginInfo(void); + + /** + * @brief PluginBase virtual overrides. + */ + bool Initialize(IAshitaCore* core, ILogManager* log, uint32_t id); + void Release(void); + bool HandleCommand(const char* command, int32_t type); + bool HandleIncomingText(int16_t mode, const char* message, int16_t* modifiedMode, char* modifiedMessage, bool blocked); + bool HandleIncomingPacket(uint16_t id, uint32_t size, void* data, void* modified, bool blocked); + bool HandleOutgoingPacket(uint16_t id, uint32_t size, void* data, void* modified, bool blocked); + bool Direct3DInitialize(IDirect3DDevice8* device); + void Direct3DRelease(void); + void Direct3DPreRender(void); + void Direct3DRender(void); + void onClick(int, IFontObject*, float, float); +}; + +// Global pointer to this + +Deeps* g_Deeps = NULL; + +/** + * @brief Required Plugin Exports + */ +__declspec(dllexport) double __stdcall GetInterfaceVersion(void); +__declspec(dllexport) void __stdcall CreatePluginInfo(plugininfo_t* lpBuffer); +__declspec(dllexport) IPlugin* __stdcall CreatePlugin(void); + +#endif // __ASHITA_Deeps_H_INCLUDED__ diff --git a/Deeps/Deeps.vcxproj b/Deeps/Deeps.vcxproj index 03ecc57..f67dc40 100644 --- a/Deeps/Deeps.vcxproj +++ b/Deeps/Deeps.vcxproj @@ -1,169 +1,176 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {012F77AE-D2F5-4F5B-A531-DA4FF57494DA} - Win32Proj - Deeps - 8.1 - - - - DynamicLibrary - true - v140 - Unicode - - - DynamicLibrary - false - v140_xp - true - MultiByte - - - DynamicLibrary - true - v140 - Unicode - - - DynamicLibrary - false - v140 - true - Unicode - - - - - - - - - - - - - - - - - - - - - true - - - true - - - false - ..\..\..\..\..\..\..\..\Ashita 3\plugins - - - false - - - - - - Level3 - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;DEEPS_EXPORTS;%(PreprocessorDefinitions) - true - - - Windows - true - Exports.def - - - - - - - Level3 - Disabled - _DEBUG;_WINDOWS;_USRDLL;DEEPS_EXPORTS;%(PreprocessorDefinitions) - true - - - Windows - true - Exports.def - - - - - Level3 - - - Full - false - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;DEEPS_EXPORTS;%(PreprocessorDefinitions) - true - true - true - Async - - - Windows - true - true - true - Exports.def - - - - - Level3 - - - MaxSpeed - true - true - NDEBUG;_WINDOWS;_USRDLL;DEEPS_EXPORTS;%(PreprocessorDefinitions) - true - - - Windows - true - true - true - Exports.def - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {012F77AE-D2F5-4F5B-A531-DA4FF57494DA} + Win32Proj + Deeps + 8.1 + + + + DynamicLibrary + true + v140 + Unicode + + + DynamicLibrary + false + v140_xp + true + MultiByte + + + DynamicLibrary + true + v140 + Unicode + + + DynamicLibrary + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + true + + + false + ..\..\bin\ + + + false + ..\..\bin\ + + + + + + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;DEEPS_EXPORTS;%(PreprocessorDefinitions) + true + + + Windows + true + Exports.def + + + + + + + Level3 + Disabled + _DEBUG;_WINDOWS;_USRDLL;DEEPS_EXPORTS;%(PreprocessorDefinitions) + true + + + Windows + true + Exports.def + + + + + Level3 + + + Full + false + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;DEEPS_EXPORTS;%(PreprocessorDefinitions) + true + true + true + Async + + + Windows + true + true + true + Exports.def + + + copy "..\..\bin\Deeps.dll" "C:\Ashita 3\plugins\Deeps.dll" + + + + + Level3 + + + MaxSpeed + true + true + NDEBUG;_WINDOWS;_USRDLL;DEEPS_EXPORTS;%(PreprocessorDefinitions) + true + + + Windows + true + true + true + Exports.def + + + copy "..\..\bin\Deeps.dll" "C:\Ashita 3\plugins\Deeps.dll" + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Deeps/Deeps.vcxproj.filters b/Deeps/Deeps.vcxproj.filters index 6e1c279..96b133a 100644 --- a/Deeps/Deeps.vcxproj.filters +++ b/Deeps/Deeps.vcxproj.filters @@ -1,35 +1,35 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Header Files - - - Header Files - - - - - Source Files - - - - - Source Files - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + + + Source Files + + + + + Source Files + + \ No newline at end of file diff --git a/Deeps/Exports.def b/Deeps/Exports.def index 9c60f62..2e0de98 100644 --- a/Deeps/Exports.def +++ b/Deeps/Exports.def @@ -1,5 +1,5 @@ -LIBRARY "Deeps" -EXPORTS - GetInterfaceVersion - CreatePluginInfo +LIBRARY "Deeps" +EXPORTS + GetInterfaceVersion + CreatePluginInfo CreatePlugin \ No newline at end of file diff --git a/Deeps/main.cpp b/Deeps/main.cpp index 5791f0d..d57d993 100644 --- a/Deeps/main.cpp +++ b/Deeps/main.cpp @@ -1,824 +1,847 @@ -/** -* Copyright (c) 2011-2014 - Ashita Development Team -* -* Ashita 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. -* -* Ashita 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 Ashita. If not, see . -*/ - -#include "Deeps.h" -#include "DSP-Utils.h" - -#include -#include - -source_t* Deeps::getDamageSource(entitysources_t* entityInfo, uint8_t actionType, uint16_t actionID) -{ - uint32_t key = (actionID << 8) + actionType; - auto sourcesIt = entityInfo->sources.find(key); - - source_t* source; - - if (sourcesIt != entityInfo->sources.end()) - { - source = &sourcesIt->second; - } - else - { - source_t newsource; - - sourcesIt = entityInfo->sources.insert(std::make_pair(key, newsource)).first; - - source = &sourcesIt->second; - if (actionType == 1) { source->name.append("Attack"); } - else if (actionType == 2) { source->name.append("Ranged Attack"); } - else if (actionType == 3 || actionType == 11){ source->name.append(m_AshitaCore->GetResourceManager()->GetAbilityById(actionID)->Name[2]); } - else if (actionType == 4) { source->name.append(m_AshitaCore->GetResourceManager()->GetSpellById(actionID)->Name[2]); } - else if (actionType == 6 || actionType == 14 || actionType == 15) { source->name.append(m_AshitaCore->GetResourceManager()->GetAbilityById(actionID + 512)->Name[2]); } - - } - return source; -} - -bool Deeps::updateDamageSource(source_t* source, uint16_t message, uint32_t damage) -{ - damage_t* type = NULL; - bool val = false; - if (std::find(hitMessages.begin(), hitMessages.end(), message) != hitMessages.end()) - { - type = &source->damage["Hit"]; - val = true; - } - else if (std::find(critMessages.begin(), critMessages.end(), message) != critMessages.end()) - { - type = &source->damage["Crit"]; - val = true; - } - else if (std::find(missMessages.begin(), missMessages.end(), message) != missMessages.end()) - { - type = &source->damage["Miss"]; - } - else if (std::find(evadeMessages.begin(), evadeMessages.end(), message) != evadeMessages.end()) - { - type = &source->damage["Evade"]; - } - else if (std::find(parryMessages.begin(), parryMessages.end(), message) != parryMessages.end()) - { - type = &source->damage["Parry"]; - } - if (type) - { - damage = val ? damage : 0; - type->total += damage; - type->count++; - type->min = (damage < type->min ? damage : type->min); - type->max = (damage > type->max ? damage : type->max); - return true; - } - return false; -} - -uint16_t Deeps::getIndex(std::function func) -{ - for (int i = 0; i < 2048; i++) - { - if (func(m_AshitaCore->GetDataManager()->GetEntity(), i)) - { - return i; - } - } - return 0; -} - -/** - * @brief Constructor and Deconstructor - */ -Deeps::Deeps(void) -: m_AshitaCore(NULL) -, m_PluginId(0) -, m_Direct3DDevice(NULL) -{ } -Deeps::~Deeps(void) -{ } - -/** - * @brief Obtains the plugin data for this plugin. - * - * @return The PluginData structure for this plugin. - */ -plugininfo_t Deeps::GetPluginInfo(void) -{ - return (*g_PluginInfo); -} - -/** - * @brief Initializes our plugin. This is the main call that happens when your plugin is loaded. - * - * @param ashitaCore The main Ashita Core object interface to interact with Ashita. - * @param scriptEngine The main script engine object interface to interact with the script engine. - * @param dwPluginId The base address of your plugin. This is used as the ID. - * - * @return True on success, false otherwise. - * - * @note If your plugin returns false here, it will be unloaded immediately! - */ -bool Deeps::Initialize(IAshitaCore* core, ILogManager* log, uint32_t id) -{ - // Store the variables we are passed.. - this->m_AshitaCore = core; - this->m_PluginId = id; - this->m_LogManager = log; - - g_Deeps = this; - srand(time(NULL)); - - m_charInfo = 0; - m_bars = 0; - - m_AshitaCore->GetConfigurationManager()->Load("Deeps", "Deeps.xml"); - - return true; -} - -/** - * @brief Releases this plugin. This is called when your plugin is unloaded. - * - * @note Your plugin should cleanup all its data here before it unloads. Anything such as: - * - Font objects. - * - Gui objects. - * - Bindings to the script engine (if you extended it any). - */ -void Deeps::Release(void) -{ -} - -/** - * @brief Allows a plugin to attempt to handle a game command. - * - * @param pszCommand The command being processed. - * @param nCommandType The type of command being processed. - * - * @return True on handled, false otherwise. - */ -bool Deeps::HandleCommand(const char* command, int32_t type) -{ - std::vector args; - auto count = Ashita::Commands::GetCommandArgs(command, &args); - if (count <= 0) return false; - HANDLECOMMAND("/deeps", "/dps") - { - if (count >= 2) - { - if (args[1] == "reset") - { - entities.clear(); - m_sourceInfo.clear(); - m_charInfo = 0; - return true; - } - else if (args[1] == "report") - { - char mode = 0x00; - int max = 3; - if (count > 2) - { - if (std::all_of(args[2].begin(), args[2].end(), ::isdigit)) - { - max = atoi(args[2].c_str()); - } - else - { - mode = args[2][0]; - if (count > 3) - { - if (std::all_of(args[2].begin(), args[2].end(), ::isdigit)) - { - max = atoi(args[2].c_str()); - } - } - } - } - - std::thread(&Deeps::report, this, mode, max).detach(); - - return true; - } - else if (args[1] == "debug") - { - m_debug = !m_debug; - if (m_debug) - { - m_AshitaCore->GetChatManager()->AddChatMessage(5, "Deeps: Debug on"); - } - else - { - m_AshitaCore->GetChatManager()->AddChatMessage(5, "Deeps: Debug off"); - } - return true; - } - } - m_AshitaCore->GetChatManager()->AddChatMessage(5, "Deeps usage: /dps reset, /dps report [s/p/l] [#]"); - return true; - } - return false; -} - -void Deeps::report(char mode, int max) -{ - IFontObject* deepsBase = m_AshitaCore->GetFontManager()->Get("DeepsBackground"); - if (deepsBase) - { - std::string line; - char buff[256]; - if (mode != 0x00) - { - sprintf_s(buff, 256, "/%c ", mode); - line.append(buff); - } - line.append(deepsBase->GetText()); - m_AshitaCore->GetChatManager()->QueueCommand(line.c_str(), (int32_t)Ashita::CommandInputType::Typed); - for (int i = 0; i < m_bars; i++) - { - if (i > max) - break; - std::this_thread::sleep_for(std::chrono::milliseconds(1100)); - line.clear(); - memset(buff, sizeof buff, 0); - if (mode != 0x00) - { - sprintf_s(buff, 256, "/%c ", mode); - line.append(buff); - } - sprintf_s(buff, 256, "%d -", i + 1); - line.append(buff); - char name[32]; - sprintf_s(name, 32, "DeepsBar%d", i); - IFontObject* bar = m_AshitaCore->GetFontManager()->Get(name); - line.append(bar->GetText()); - m_AshitaCore->GetChatManager()->QueueCommand(line.c_str(), (int32_t)Ashita::CommandInputType::Typed); - } - } -} - -/** - * @brief Allows a plugin to attempt to handle a new chat line. - * - * @param sMode The chat type being added. - * @param pszChatLine The chat line being added. - * - * @return True on handled, false otherwise. - */ -bool Deeps::HandleIncomingText(int16_t mode, const char* message, int16_t* modifiedMode, char* modifiedMessage, bool blocked) -{ - return false; -} - -/** - * @brief Allows a plugin to attempt to handle an incoming packet. - * - * @param uiPacketId The id of the packet. - * @param uiPacketSize The size of the packet. - * @param lpRawData The raw packet data. - * - * @return True on handled, false otherwise. - * - * @note Returning true on this will block the packet from being handled! This can - * have undesired effects! Use with caution as this can get you banned! - */ -bool Deeps::HandleIncomingPacket(uint16_t id, uint32_t size, void* data, void* modified, bool blocked) -{ - if (id == 0x28) //action - { - uint8_t actionNum = (uint8_t)(unpackBitsBE((unsigned char*)data, 182, 4)); - uint8_t targetNum = RBUFB(data, 0x09); - uint8_t actionType = (uint8_t)(unpackBitsBE((unsigned char*)data, 82, 4)); - //uint8_t reaction = 0; - //uint8_t speceffect = 0; - uint16_t actionID = (uint16_t)(unpackBitsBE((unsigned char*)data, 86, 10)); - uint32_t userID = RBUFL(data, 0x05); - uint16_t startBit = 150; - uint16_t damage = 0; - - if (userID > 0x1000000) - return false; - - auto it = entities.find(userID); - entitysources_t* entityInfo = NULL; - - if (it != entities.end()) - { - entityInfo = &it->second; - } - else - { - uint16_t index = getIndex([&](IEntity* entities, int i){if (entities->GetServerId(i) == userID) return true; return false; }); - if (index != 0) - { - entitysources_t newInfo; - newInfo.name = m_AshitaCore->GetDataManager()->GetEntity()->GetName(index); - newInfo.color = Colors[rand() % Colors.size()]; - entityInfo = &entities.insert(std::make_pair(userID, newInfo)).first->second; - } - } - - if (entityInfo) - { - if (m_debug) - { - m_AshitaCore->GetChatManager()->Writef("Action Type: %d Action ID: %d", actionType, actionID); - } - - if ((actionType >= 1 && actionType <= 4) || (actionType == 6) || (actionType == 11) || (actionType == 14) || (actionType == 15)) - { - if (actionID == 0) - return false; - source_t* source = getDamageSource(entityInfo, actionType, actionID); - uint16_t messageID = (uint16_t)(unpackBitsBE((unsigned char*)data, startBit + 80, 10)); - - uint32_t addEffectDamage = 0; - uint8_t addEffectCount = 0; - uint16_t addMessageID = 0; - for (int i = 0; i < targetNum; i++) - { - for (int j = 0; j < actionNum; j++) - { - uint8_t reaction = (uint8_t)(unpackBitsBE((unsigned char*)data, startBit + 36, 5)); - uint16_t animation = (uint16_t)(unpackBitsBE((unsigned char*)data, startBit + 41, 12)); - uint32_t mainDamage = (uint16_t)(unpackBitsBE((unsigned char*)data, startBit + 63, 17)); - uint8_t speceffect = (uint8_t)(unpackBitsBE((unsigned char*)data, startBit + 53, 9)); - - if (m_debug) - { - m_AshitaCore->GetChatManager()->Writef("Reaction: %d Animation: %d", reaction, animation); - m_AshitaCore->GetChatManager()->Writef("Speceffect: %d Param: %d", speceffect, mainDamage); - } - - //Daken (ranged attack on attack) - if (actionType == 1 && animation == 4) - source = getDamageSource(entityInfo, actionType+1, actionID); - - if (!updateDamageSource(source, messageID, mainDamage)) - return false; - - if ((unpackBitsBE((unsigned char*)data, startBit + 121, 1) & 0x1) && actionType != 6) - { - addMessageID = (uint16_t)(unpackBitsBE((unsigned char*)data, startBit + 149, 10)); - if (addMessageID == 163 || addMessageID == 229 || (addMessageID >= 288 && addMessageID <= 302)) - { - addEffectDamage = (uint16_t)(unpackBitsBE((unsigned char*)data, startBit + 132, 16)); - uint32_t key = 0; - if (addMessageID == 163 || addMessageID == 229) - key = 1 << 8; - else - key = 2 << 8; - auto sourcesIt = entityInfo->sources.find(key); - - source_t* source; - - if (sourcesIt != entityInfo->sources.end()) - { - source = &sourcesIt->second; - } - else - { - source_t newsource; - if (key == 1 << 8) { newsource.name.append("Additional Effect"); } - else { newsource.name.append("Skillchain"); } - - sourcesIt = entityInfo->sources.insert(std::make_pair(key, newsource)).first; - source = &sourcesIt->second; - } - source->damage["Hit"].count += 1; - source->damage["Hit"].total += addEffectDamage; - source->damage["Hit"].min = (addEffectDamage < source->damage["Hit"].min ? addEffectDamage : source->damage["Hit"].min); - source->damage["Hit"].max = (addEffectDamage > source->damage["Hit"].max ? addEffectDamage : source->damage["Hit"].max); - } - - startBit += 37; - } - startBit += 1; - if (unpackBitsBE((unsigned char*)data, startBit + 121, 1) & 0x1) - { - startBit += 34; - } - startBit += 86; - } - startBit += 36; - } - } - } - } - return false; -} - -/** - * @brief Allows a plugin to attempt to handle an outgoing packet. - * - * @param uiPacketId The id of the packet. - * @param uiPacketSize The size of the packet. - * @param lpRawData The raw packet data. - * - * @return True on handled, false otherwise. - * - * @note Returning true on this will block the packet from being handled! This can - * have undesired effects! Use with caution as this can get you banned! - */ -bool Deeps::HandleOutgoingPacket(uint16_t id, uint32_t size, void* data, void* modified, bool blocked) -{ - return false; -} - -/** - * @brief Direct3D initialize call to prepare this plugin for Direct3D calls. - * - * @param lpDevice The Direct3D device currently wrapped by Ashita. - * - * @return True on success, false otherwise. - * - * @note Plugins that do not return true on this call will not receive any other - * Direct3D calls listed below! - */ -bool Deeps::Direct3DInitialize(IDirect3DDevice8* device) -{ - this->m_Direct3DDevice = device; - - float xpos = m_AshitaCore->GetConfigurationManager()->get_float("Deeps", "xpos", 300.0f); - float ypos = m_AshitaCore->GetConfigurationManager()->get_float("Deeps", "ypos", 300.0f); - - IFontObject* font = m_AshitaCore->GetFontManager()->Create("DeepsBackground"); - font->SetFontFamily("Consolas"); - font->SetFontHeight(10); - font->SetAutoResize(false); - font->GetBackground()->SetColor(D3DCOLOR_ARGB(0xCC, 0x00, 0x00, 0x00)); - font->GetBackground()->SetVisibility(true); - font->GetBackground()->SetWidth(158); - font->GetBackground()->SetHeight(256); - font->SetColor(D3DCOLOR_ARGB(0xFF, 0xFF, 0xFF, 0xFF)); - font->SetBold(false); - font->SetText(""); - font->SetPositionX(xpos); - font->SetPositionY(ypos); - font->SetVisibility(true); - font->SetMouseEventFunction(g_onClick); - - return true; -} - -/** - * @brief Direct3D release call to allow this plugin to cleanup any Direct3D objects. - */ -void Deeps::Direct3DRelease(void) -{ - IFontObject* deepsBase = m_AshitaCore->GetFontManager()->Get("DeepsBackground"); - - m_AshitaCore->GetConfigurationManager()->set_value("Deeps", "xpos", std::to_string(deepsBase->GetPositionX()).c_str()); - m_AshitaCore->GetConfigurationManager()->set_value("Deeps", "ypos", std::to_string(deepsBase->GetPositionY()).c_str()); - m_AshitaCore->GetConfigurationManager()->Save("Deeps", "Deeps.xml"); - - m_AshitaCore->GetFontManager()->Delete("DeepsBackground"); - - for (int i = 0; i < m_bars; i++) - { - char name[32]; - sprintf_s(name, 32, "DeepsBar%d", i); - m_AshitaCore->GetFontManager()->Delete(name); - memset(name, 0, sizeof name); - sprintf_s(name, 32, "DeepsBarClick%d", i); - m_AshitaCore->GetFontManager()->Delete(name); - } -} - -/** - * @brief Direct3D prerender call to allow this plugin to prepare for rendering. - * - * @note This will only be called if you returned true in Direct3DInitialize! - */ -void Deeps::Direct3DPreRender(void) -{ -} - -/** - * @brief Direct3D render call to allow this plugin to render any custom things. - * - * @note This will only be called if you returned true in Direct3DInitialize! - */ -void Deeps::Direct3DRender(void) -{ - IFontObject* deepsBase = m_AshitaCore->GetFontManager()->Get("DeepsBackground"); - - if (m_charInfo == 0) - { - deepsBase->SetText(" Deeps - Damage Done"); - deepsBase->GetBackground()->SetWidth(158); - std::vector temp; - uint64_t total = 0; - for (auto e : entities) - { - if (e.second.total() != 0 && temp.size() < 15) - { - temp.push_back(e.second); - total += e.second.total(); - } - } - std::sort(temp.begin(), temp.end(), [](entitysources_t a, entitysources_t b){return a > b; }); - repairBars(deepsBase, temp.size()); - - int i = 0; - uint64_t max = 0; - clickMap.clear(); - for (auto e : temp) - { - char name[32]; - sprintf_s(name, 32, "DeepsBar%d", i); - IFontObject* bar = m_AshitaCore->GetFontManager()->Get(name); - if (e.total() > max) max = e.total(); - bar->GetBackground()->SetWidth(150 * (total == 0 ? 1 : ((float)e.total() / (float)max))); - bar->GetBackground()->SetColor(e.color); - char string[256]; - sprintf_s(string, 256, " %-10.10s %6llu %03.1f%%\n", e.name.c_str(), e.total(), total == 0 ? 0 : 100 * ((float)e.total() / (float)total)); - bar->SetText(string); - memset(name, 0, sizeof name); - sprintf_s(name, 32, "DeepsBarClick%d", i); - bar = m_AshitaCore->GetFontManager()->Get(name); - bar->GetBackground()->SetWidth(150); - clickMap.insert(std::pair(bar, e.name)); - i++; - } - } - else - { - auto it = entities.find(m_charInfo); - if (it != entities.end()) - { - if (m_sourceInfo == "") - { - std::vector temp; - uint64_t total = 0; - for (auto s : it->second.sources) - { - if (s.second.total() != 0 && temp.size() < 15) - { - temp.push_back(s.second); - total += s.second.total(); - } - } - std::sort(temp.begin(), temp.end(), [](source_t a, source_t b){return a > b; }); - char string[256]; - sprintf_s(string, 256, " %s - Sources\n", it->second.name.c_str()); - deepsBase->SetText(string); - deepsBase->GetBackground()->SetWidth(158); - - repairBars(deepsBase, temp.size()); - int i = 0; - uint64_t max = 0; - clickMap.clear(); - for (auto s : temp) - { - char name[32]; - sprintf_s(name, 32, "DeepsBar%d", i); - IFontObject* bar = m_AshitaCore->GetFontManager()->Get(name); - if (s.total() > max) max = s.total(); - bar->GetBackground()->SetWidth(150 * (total == 0 ? 1 : ((float)s.total() / (float)max))); - bar->GetBackground()->SetColor(it->second.color); - char string[256]; - sprintf_s(string, 256, " %-10.10s %6llu %03.1f%%\n", s.name.c_str(), s.total(), total == 0 ? 0 : 100 * ((float)s.total() / (float)total)); - bar->SetText(string); - memset(name, 0, sizeof name); - sprintf_s(name, 32, "DeepsBarClick%d", i); - bar = m_AshitaCore->GetFontManager()->Get(name); - bar->GetBackground()->SetWidth(150); - clickMap.insert(std::pair(bar, s.name)); - i++; - } - } - else - { - for (auto s : it->second.sources) - { - if (s.second.name == m_sourceInfo) - { - std::vector > temp; - uint32_t count = 0; - for (auto d : s.second.damage) - { - if (d.second.count != 0 && temp.size() < 15) - { - temp.push_back(d); - count += d.second.count; - } - } - std::sort(temp.begin(), temp.end(), [](std::pair a, std::pair b){return a.second > b.second; }); - char string[256]; - sprintf_s(string, 256, " %s - %s\n", it->second.name.c_str(), s.second.name.c_str()); - deepsBase->SetText(string); - deepsBase->GetBackground()->SetWidth(262); - repairBars(deepsBase, temp.size()); - int i = 0; - uint32_t max = 0; - for (auto s : temp) - { - char name[32]; - sprintf_s(name, 32, "DeepsBar%d", i); - IFontObject* bar = m_AshitaCore->GetFontManager()->Get(name); - if (s.second.count > max) max = s.second.count; - bar->GetBackground()->SetWidth(254 * (count == 0 ? 1 : 1 * ((float)s.second.count / (float)max))); - bar->GetBackground()->SetColor(it->second.color); - char string[256]; - sprintf_s(string, 256, " %-5s Cnt:%4d Avg:%5d Max:%5d %3.1f%%\n", s.first, s.second.count, s.second.avg(), s.second.max, count == 0 ? 0 : 100 * ((float)s.second.count / (float)count)); - bar->SetText(string); - i++; - } - break; - } - } - } - } - } - deepsBase->GetBackground()->SetHeight(m_bars * 16 + 17); -} - -void Deeps::repairBars(IFontObject* deepsBase, uint8_t size) -{ - IFontObject* previous = deepsBase; - if (m_AshitaCore->GetFontManager()->Get("DeepsBar0") != NULL) - { - char name[32] = "DeepsBar0"; - int i = 1; - while (m_AshitaCore->GetFontManager()->Get(name) != NULL) - { - previous = m_AshitaCore->GetFontManager()->Get(name); - sprintf_s(name, 32, "DeepsBar%d", i); - i++; - } - } - while (m_bars != size) - { - if (m_bars > size) - { - char name[32]; - sprintf_s(name, 32, "DeepsBar%d", m_bars - 1); - m_AshitaCore->GetFontManager()->Delete(name); - memset(name, 0, sizeof name); - sprintf_s(name, 32, "DeepsBarClick%d", m_bars - 1); - m_AshitaCore->GetFontManager()->Delete(name); - m_bars--; - } - else if (m_bars < size) - { - char name[32]; - sprintf_s(name, 32, "DeepsBar%d", m_bars); - IFontObject* bar = m_AshitaCore->GetFontManager()->Create(name); - bar->SetParent(previous); - if (previous == deepsBase) - { - bar->SetPositionX(4); - bar->SetPositionY(15); - } - else - { - bar->SetAnchorParent((uint32_t)Ashita::FrameAnchor::BottomLeft); - bar->SetPositionX(0); - bar->SetPositionY(3); - } - bar->SetAutoResize(false); - bar->SetFontFamily("Consolas"); - bar->SetFontHeight(8); - bar->GetBackground()->SetColor(D3DCOLOR_ARGB(0xFF, 0x00, 0x7C, 0x5C)); - bar->GetBackground()->SetVisibility(true); - std::string path = m_AshitaCore->GetAshitaInstallPathA(); - path.append("\\Resources\\Deeps\\bar.tga"); - bar->GetBackground()->SetTextureFromFile(path.c_str()); - bar->GetBackground()->SetWidth(254); - bar->GetBackground()->SetHeight(13); - bar->SetVisibility(true); - - memset(name, 0, sizeof name); - sprintf_s(name, 32, "DeepsBarClick%d", m_bars); - IFontObject* clickBar = m_AshitaCore->GetFontManager()->Create(name); - clickBar->SetParent(bar); - clickBar->SetPositionX(0); - clickBar->SetPositionY(0); - clickBar->SetAutoResize(false); - clickBar->GetBackground()->SetColor(D3DCOLOR_ARGB(0x00, 0x00, 0x00, 0x00)); - clickBar->GetBackground()->SetVisibility(true); - clickBar->GetBackground()->SetWidth(254); - clickBar->GetBackground()->SetHeight(13); - clickBar->SetVisibility(true); - clickBar->SetMouseEventFunction(g_onClick); - - m_bars++; - previous = bar; - } - } -} - -void Deeps::onClick(int type, IFontObject* font, float xPos, float yPos) -{ - if (type == 1 && font == m_AshitaCore->GetFontManager()->Get("DeepsBackground")) - { - if (m_sourceInfo != "") - { - m_sourceInfo = ""; - } - else - { - m_charInfo = 0; - } - return; - } - - if (m_charInfo == 0) - { - //Char was clicked - if (type == 0) - { - // left click - try - { - auto name = clickMap.at(font); - for (auto entity : entities) - { - if (entity.second.name == name) - { - m_charInfo = entity.first; - break; - } - } - } - catch (...) - { - return; - } - } - } - else - { - if (m_sourceInfo == "") - { - //source was clicked - if (type == 0) - { - try - { - auto name = clickMap.at(font); - m_sourceInfo.assign(name); - } - catch (...) - { - return; - } - } - } - } -} - -/** - * @brief Gets the interface version this plugin was compiled with. - * - * @note This is a required export, your plugin must implement this! - */ -__declspec(dllexport) double __stdcall GetInterfaceVersion(void) -{ - return ASHITA_INTERFACE_VERSION; -} - -/** - * @brief Gets the plugin data for this plugin. - * - * @note This is a required export, your plugin must implement this! - */ -__declspec(dllexport) void __stdcall CreatePluginInfo(plugininfo_t* lpBuffer) -{ - g_PluginInfo = lpBuffer; - - strcpy_s(g_PluginInfo->Name, sizeof(g_PluginInfo->Name), "Deeps"); - strcpy_s(g_PluginInfo->Author, sizeof(g_PluginInfo->Author), "kjLotus"); - - g_PluginInfo->InterfaceVersion = ASHITA_INTERFACE_VERSION; - g_PluginInfo->PluginVersion = 2.03f; - g_PluginInfo->Priority = 0; -} - -/** - * @brief Creates an instance of this plugin object. - * - * @note This is a required export, your plugin must implement this! - */ -__declspec(dllexport) IPlugin* __stdcall CreatePlugin(void) -{ - return (IPlugin*)new Deeps(); -} - -void g_onClick(int type, void* font, float xPos, float yPos) -{ - g_Deeps->onClick(type, (IFontObject*)font, xPos, yPos); +/** +* Copyright (c) 2011-2014 - Ashita Development Team +* +* Ashita 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. +* +* Ashita 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 Ashita. If not, see . +*/ + +#include "Deeps.h" +#include "DSP-Utils.h" + +#include +#include + +source_t* Deeps::getDamageSource(entitysources_t* entityInfo, uint8_t actionType, uint16_t actionID) +{ + uint32_t key = (actionID << 8) + actionType; + auto sourcesIt = entityInfo->sources.find(key); + + source_t* source; + + if (sourcesIt != entityInfo->sources.end()) + { + source = &sourcesIt->second; + } + else + { + source_t newsource; + + sourcesIt = entityInfo->sources.insert(std::make_pair(key, newsource)).first; + + source = &sourcesIt->second; + if (actionType == 1) { source->name.append("Attack"); } + else if (actionType == 2) { source->name.append("Ranged Attack"); } + else if (actionType == 3 || actionType == 11){ source->name.append(m_AshitaCore->GetResourceManager()->GetAbilityById(actionID)->Name[2]); } + else if (actionType == 4) { source->name.append(m_AshitaCore->GetResourceManager()->GetSpellById(actionID)->Name[2]); } + else if (actionType == 6 || actionType == 14 || actionType == 15) { source->name.append(m_AshitaCore->GetResourceManager()->GetAbilityById(actionID + 512)->Name[2]); } + + } + return source; +} + +bool Deeps::updateDamageSource(source_t* source, uint16_t message, uint32_t damage) +{ + damage_t* type = NULL; + bool val = false; + if (std::find(hitMessages.begin(), hitMessages.end(), message) != hitMessages.end()) + { + type = &source->damage["Hit"]; + val = true; + } + else if (std::find(critMessages.begin(), critMessages.end(), message) != critMessages.end()) + { + type = &source->damage["Crit"]; + val = true; + } + else if (std::find(missMessages.begin(), missMessages.end(), message) != missMessages.end()) + { + type = &source->damage["Miss"]; + } + else if (std::find(evadeMessages.begin(), evadeMessages.end(), message) != evadeMessages.end()) + { + type = &source->damage["Evade"]; + } + else if (std::find(parryMessages.begin(), parryMessages.end(), message) != parryMessages.end()) + { + type = &source->damage["Parry"]; + } + if (type) + { + damage = val ? damage : 0; + type->total += damage; + type->count++; + type->min = (damage < type->min ? damage : type->min); + type->max = (damage > type->max ? damage : type->max); + return true; + } + return false; +} + +uint16_t Deeps::getIndex(std::function func) +{ + for (int i = 0; i < 2048; i++) + { + if (func(m_AshitaCore->GetDataManager()->GetEntity(), i)) + { + return i; + } + } + return 0; +} + +/** + * @brief Constructor and Deconstructor + */ +Deeps::Deeps(void) +: m_AshitaCore(NULL) +, m_PluginId(0) +, m_Direct3DDevice(NULL) +{ } +Deeps::~Deeps(void) +{ } + +/** + * @brief Obtains the plugin data for this plugin. + * + * @return The PluginData structure for this plugin. + */ +plugininfo_t Deeps::GetPluginInfo(void) +{ + return (*g_PluginInfo); +} + +/** + * @brief Initializes our plugin. This is the main call that happens when your plugin is loaded. + * + * @param ashitaCore The main Ashita Core object interface to interact with Ashita. + * @param scriptEngine The main script engine object interface to interact with the script engine. + * @param dwPluginId The base address of your plugin. This is used as the ID. + * + * @return True on success, false otherwise. + * + * @note If your plugin returns false here, it will be unloaded immediately! + */ +bool Deeps::Initialize(IAshitaCore* core, ILogManager* log, uint32_t id) +{ + // Store the variables we are passed.. + this->m_AshitaCore = core; + this->m_PluginId = id; + this->m_LogManager = log; + + g_Deeps = this; + srand(time(NULL)); + + m_charInfo = 0; + m_bars = 0; + + m_AshitaCore->GetConfigurationManager()->Load("Deeps", "Deeps.xml"); + + return true; +} + +/** + * @brief Releases this plugin. This is called when your plugin is unloaded. + * + * @note Your plugin should cleanup all its data here before it unloads. Anything such as: + * - Font objects. + * - Gui objects. + * - Bindings to the script engine (if you extended it any). + */ +void Deeps::Release(void) +{ + while (m_Packets.size() > 0) + { + free(*m_Packets.begin()); + m_Packets.pop_front(); + } +} + +/** + * @brief Allows a plugin to attempt to handle a game command. + * + * @param pszCommand The command being processed. + * @param nCommandType The type of command being processed. + * + * @return True on handled, false otherwise. + */ +bool Deeps::HandleCommand(const char* command, int32_t type) +{ + std::vector args; + auto count = Ashita::Commands::GetCommandArgs(command, &args); + if (count <= 0) return false; + HANDLECOMMAND("/deeps", "/dps") + { + if (count >= 2) + { + if (args[1] == "reset") + { + entities.clear(); + m_sourceInfo.clear(); + m_charInfo = 0; + return true; + } + else if (args[1] == "report") + { + char mode = 0x00; + int max = 3; + if (count > 2) + { + if (std::all_of(args[2].begin(), args[2].end(), ::isdigit)) + { + max = atoi(args[2].c_str()); + } + else + { + mode = args[2][0]; + if (count > 3) + { + if (std::all_of(args[2].begin(), args[2].end(), ::isdigit)) + { + max = atoi(args[2].c_str()); + } + } + } + } + + std::thread(&Deeps::report, this, mode, max).detach(); + + return true; + } + else if (args[1] == "debug") + { + m_debug = !m_debug; + if (m_debug) + { + m_AshitaCore->GetChatManager()->AddChatMessage(5, "Deeps: Debug on"); + } + else + { + m_AshitaCore->GetChatManager()->AddChatMessage(5, "Deeps: Debug off"); + } + return true; + } + } + m_AshitaCore->GetChatManager()->AddChatMessage(5, "Deeps usage: /dps reset, /dps report [s/p/l] [#]"); + return true; + } + return false; +} + +void Deeps::report(char mode, int max) +{ + IFontObject* deepsBase = m_AshitaCore->GetFontManager()->Get("DeepsBackground"); + if (deepsBase) + { + std::string line; + char buff[256]; + if (mode != 0x00) + { + sprintf_s(buff, 256, "/%c ", mode); + line.append(buff); + } + line.append(deepsBase->GetText()); + m_AshitaCore->GetChatManager()->QueueCommand(line.c_str(), (int32_t)Ashita::CommandInputType::Typed); + for (int i = 0; i < m_bars; i++) + { + if (i > max) + break; + std::this_thread::sleep_for(std::chrono::milliseconds(1100)); + line.clear(); + memset(buff, sizeof buff, 0); + if (mode != 0x00) + { + sprintf_s(buff, 256, "/%c ", mode); + line.append(buff); + } + sprintf_s(buff, 256, "%d -", i + 1); + line.append(buff); + char name[32]; + sprintf_s(name, 32, "DeepsBar%d", i); + IFontObject* bar = m_AshitaCore->GetFontManager()->Get(name); + line.append(bar->GetText()); + m_AshitaCore->GetChatManager()->QueueCommand(line.c_str(), (int32_t)Ashita::CommandInputType::Typed); + } + } +} + +/** + * @brief Allows a plugin to attempt to handle a new chat line. + * + * @param sMode The chat type being added. + * @param pszChatLine The chat line being added. + * + * @return True on handled, false otherwise. + */ +bool Deeps::HandleIncomingText(int16_t mode, const char* message, int16_t* modifiedMode, char* modifiedMessage, bool blocked) +{ + return false; +} + +/** + * @brief Allows a plugin to attempt to handle an incoming packet. + * + * @param uiPacketId The id of the packet. + * @param uiPacketSize The size of the packet. + * @param lpRawData The raw packet data. + * + * @return True on handled, false otherwise. + * + * @note Returning true on this will block the packet from being handled! This can + * have undesired effects! Use with caution as this can get you banned! + */ +bool Deeps::HandleIncomingPacket(uint16_t id, uint32_t size, void* data, void* modified, bool blocked) +{ + for (std::list::iterator it = m_Packets.begin(); it != m_Packets.end(); it++) + { + if (memcmp(data, (*it), size) == 0) + { + return false; + } + } + + void* packet = malloc(1024); + memset(packet, 0, 1024); + memcpy(packet, data, size); + m_Packets.push_back(packet); + while (m_Packets.size() > 200) + { + free(*m_Packets.begin()); + m_Packets.pop_front(); + } + + if (id == 0x28) //action + { + uint8_t actionNum = (uint8_t)(unpackBitsBE((unsigned char*)data, 182, 4)); + uint8_t targetNum = RBUFB(data, 0x09); + uint8_t actionType = (uint8_t)(unpackBitsBE((unsigned char*)data, 82, 4)); + //uint8_t reaction = 0; + //uint8_t speceffect = 0; + uint16_t actionID = (uint16_t)(unpackBitsBE((unsigned char*)data, 86, 10)); + uint32_t userID = RBUFL(data, 0x05); + uint16_t startBit = 150; + uint16_t damage = 0; + + if (userID > 0x1000000) + return false; + + auto it = entities.find(userID); + entitysources_t* entityInfo = NULL; + + if (it != entities.end()) + { + entityInfo = &it->second; + } + else + { + uint16_t index = getIndex([&](IEntity* entities, int i){if (entities->GetServerId(i) == userID) return true; return false; }); + if (index != 0) + { + entitysources_t newInfo; + newInfo.name = m_AshitaCore->GetDataManager()->GetEntity()->GetName(index); + newInfo.color = Colors[rand() % Colors.size()]; + entityInfo = &entities.insert(std::make_pair(userID, newInfo)).first->second; + } + } + + if (entityInfo) + { + if (m_debug) + { + m_AshitaCore->GetChatManager()->Writef("Action Type: %d Action ID: %d", actionType, actionID); + } + + if ((actionType >= 1 && actionType <= 4) || (actionType == 6) || (actionType == 11) || (actionType == 14) || (actionType == 15)) + { + if (actionID == 0) + return false; + source_t* source = getDamageSource(entityInfo, actionType, actionID); + uint16_t messageID = (uint16_t)(unpackBitsBE((unsigned char*)data, startBit + 80, 10)); + + uint32_t addEffectDamage = 0; + uint8_t addEffectCount = 0; + uint16_t addMessageID = 0; + for (int i = 0; i < targetNum; i++) + { + for (int j = 0; j < actionNum; j++) + { + uint8_t reaction = (uint8_t)(unpackBitsBE((unsigned char*)data, startBit + 36, 5)); + uint16_t animation = (uint16_t)(unpackBitsBE((unsigned char*)data, startBit + 41, 12)); + uint32_t mainDamage = (uint32_t)(unpackBitsBE((unsigned char*)data, startBit + 63, 17)); + uint8_t speceffect = (uint8_t)(unpackBitsBE((unsigned char*)data, startBit + 53, 9)); + + if (m_debug) + { + m_AshitaCore->GetChatManager()->Writef("Reaction: %d Animation: %d", reaction, animation); + m_AshitaCore->GetChatManager()->Writef("Speceffect: %d Param: %d", speceffect, mainDamage); + } + + //Daken (ranged attack on attack) + if (actionType == 1 && animation == 4) + source = getDamageSource(entityInfo, actionType+1, actionID); + + if (!updateDamageSource(source, messageID, mainDamage)) + return false; + + if ((unpackBitsBE((unsigned char*)data, startBit + 121, 1) & 0x1) && actionType != 6) + { + addMessageID = (uint16_t)(unpackBitsBE((unsigned char*)data, startBit + 149, 10)); + if (addMessageID == 163 || addMessageID == 229 || (addMessageID >= 288 && addMessageID <= 302)) + { + addEffectDamage = (uint16_t)(unpackBitsBE((unsigned char*)data, startBit + 132, 16)); + uint32_t key = 0; + if (addMessageID == 163 || addMessageID == 229) + key = 1 << 8; + else + key = 2 << 8; + auto sourcesIt = entityInfo->sources.find(key); + + source_t* source; + + if (sourcesIt != entityInfo->sources.end()) + { + source = &sourcesIt->second; + } + else + { + source_t newsource; + if (key == 1 << 8) { newsource.name.append("Additional Effect"); } + else { newsource.name.append("Skillchain"); } + + sourcesIt = entityInfo->sources.insert(std::make_pair(key, newsource)).first; + source = &sourcesIt->second; + } + source->damage["Hit"].count += 1; + source->damage["Hit"].total += addEffectDamage; + source->damage["Hit"].min = (addEffectDamage < source->damage["Hit"].min ? addEffectDamage : source->damage["Hit"].min); + source->damage["Hit"].max = (addEffectDamage > source->damage["Hit"].max ? addEffectDamage : source->damage["Hit"].max); + } + + startBit += 37; + } + startBit += 1; + if (unpackBitsBE((unsigned char*)data, startBit + 121, 1) & 0x1) + { + startBit += 34; + } + startBit += 86; + } + startBit += 36; + } + } + } + } + return false; +} + +/** + * @brief Allows a plugin to attempt to handle an outgoing packet. + * + * @param uiPacketId The id of the packet. + * @param uiPacketSize The size of the packet. + * @param lpRawData The raw packet data. + * + * @return True on handled, false otherwise. + * + * @note Returning true on this will block the packet from being handled! This can + * have undesired effects! Use with caution as this can get you banned! + */ +bool Deeps::HandleOutgoingPacket(uint16_t id, uint32_t size, void* data, void* modified, bool blocked) +{ + return false; +} + +/** + * @brief Direct3D initialize call to prepare this plugin for Direct3D calls. + * + * @param lpDevice The Direct3D device currently wrapped by Ashita. + * + * @return True on success, false otherwise. + * + * @note Plugins that do not return true on this call will not receive any other + * Direct3D calls listed below! + */ +bool Deeps::Direct3DInitialize(IDirect3DDevice8* device) +{ + this->m_Direct3DDevice = device; + + float xpos = m_AshitaCore->GetConfigurationManager()->get_float("Deeps", "xpos", 300.0f); + float ypos = m_AshitaCore->GetConfigurationManager()->get_float("Deeps", "ypos", 300.0f); + + IFontObject* font = m_AshitaCore->GetFontManager()->Create("DeepsBackground"); + font->SetFontFamily("Consolas"); + font->SetFontHeight(10); + font->SetAutoResize(false); + font->GetBackground()->SetColor(D3DCOLOR_ARGB(0xCC, 0x00, 0x00, 0x00)); + font->GetBackground()->SetVisibility(true); + font->GetBackground()->SetWidth(158); + font->GetBackground()->SetHeight(256); + font->SetColor(D3DCOLOR_ARGB(0xFF, 0xFF, 0xFF, 0xFF)); + font->SetBold(false); + font->SetText(""); + font->SetPositionX(xpos); + font->SetPositionY(ypos); + font->SetVisibility(true); + font->SetMouseEventFunction(g_onClick); + + return true; +} + +/** + * @brief Direct3D release call to allow this plugin to cleanup any Direct3D objects. + */ +void Deeps::Direct3DRelease(void) +{ + IFontObject* deepsBase = m_AshitaCore->GetFontManager()->Get("DeepsBackground"); + + m_AshitaCore->GetConfigurationManager()->set_value("Deeps", "xpos", std::to_string(deepsBase->GetPositionX()).c_str()); + m_AshitaCore->GetConfigurationManager()->set_value("Deeps", "ypos", std::to_string(deepsBase->GetPositionY()).c_str()); + m_AshitaCore->GetConfigurationManager()->Save("Deeps", "Deeps.xml"); + + m_AshitaCore->GetFontManager()->Delete("DeepsBackground"); + + for (int i = 0; i < m_bars; i++) + { + char name[32]; + sprintf_s(name, 32, "DeepsBar%d", i); + m_AshitaCore->GetFontManager()->Delete(name); + memset(name, 0, sizeof name); + sprintf_s(name, 32, "DeepsBarClick%d", i); + m_AshitaCore->GetFontManager()->Delete(name); + } +} + +/** + * @brief Direct3D prerender call to allow this plugin to prepare for rendering. + * + * @note This will only be called if you returned true in Direct3DInitialize! + */ +void Deeps::Direct3DPreRender(void) +{ +} + +/** + * @brief Direct3D render call to allow this plugin to render any custom things. + * + * @note This will only be called if you returned true in Direct3DInitialize! + */ +void Deeps::Direct3DRender(void) +{ + IFontObject* deepsBase = m_AshitaCore->GetFontManager()->Get("DeepsBackground"); + + if (m_charInfo == 0) + { + deepsBase->SetText(" Deeps - Damage Done"); + deepsBase->GetBackground()->SetWidth(158); + std::vector temp; + uint64_t total = 0; + for (auto e : entities) + { + if (e.second.total() != 0 && temp.size() < 15) + { + temp.push_back(e.second); + total += e.second.total(); + } + } + std::sort(temp.begin(), temp.end(), [](entitysources_t a, entitysources_t b){return a > b; }); + repairBars(deepsBase, temp.size()); + + int i = 0; + uint64_t max = 0; + clickMap.clear(); + for (auto e : temp) + { + char name[32]; + sprintf_s(name, 32, "DeepsBar%d", i); + IFontObject* bar = m_AshitaCore->GetFontManager()->Get(name); + if (e.total() > max) max = e.total(); + bar->GetBackground()->SetWidth(150 * (total == 0 ? 1 : ((float)e.total() / (float)max))); + bar->GetBackground()->SetColor(e.color); + char string[256]; + sprintf_s(string, 256, " %-10.10s %6llu %03.1f%%\n", e.name.c_str(), e.total(), total == 0 ? 0 : 100 * ((float)e.total() / (float)total)); + bar->SetText(string); + memset(name, 0, sizeof name); + sprintf_s(name, 32, "DeepsBarClick%d", i); + bar = m_AshitaCore->GetFontManager()->Get(name); + bar->GetBackground()->SetWidth(150); + clickMap.insert(std::pair(bar, e.name)); + i++; + } + } + else + { + auto it = entities.find(m_charInfo); + if (it != entities.end()) + { + if (m_sourceInfo == "") + { + std::vector temp; + uint64_t total = 0; + for (auto s : it->second.sources) + { + if (s.second.total() != 0 && temp.size() < 15) + { + temp.push_back(s.second); + total += s.second.total(); + } + } + std::sort(temp.begin(), temp.end(), [](source_t a, source_t b){return a > b; }); + char string[256]; + sprintf_s(string, 256, " %s - Sources\n", it->second.name.c_str()); + deepsBase->SetText(string); + deepsBase->GetBackground()->SetWidth(158); + + repairBars(deepsBase, temp.size()); + int i = 0; + uint64_t max = 0; + clickMap.clear(); + for (auto s : temp) + { + char name[32]; + sprintf_s(name, 32, "DeepsBar%d", i); + IFontObject* bar = m_AshitaCore->GetFontManager()->Get(name); + if (s.total() > max) max = s.total(); + bar->GetBackground()->SetWidth(150 * (total == 0 ? 1 : ((float)s.total() / (float)max))); + bar->GetBackground()->SetColor(it->second.color); + char string[256]; + sprintf_s(string, 256, " %-10.10s %6llu %03.1f%%\n", s.name.c_str(), s.total(), total == 0 ? 0 : 100 * ((float)s.total() / (float)total)); + bar->SetText(string); + memset(name, 0, sizeof name); + sprintf_s(name, 32, "DeepsBarClick%d", i); + bar = m_AshitaCore->GetFontManager()->Get(name); + bar->GetBackground()->SetWidth(150); + clickMap.insert(std::pair(bar, s.name)); + i++; + } + } + else + { + for (auto s : it->second.sources) + { + if (s.second.name == m_sourceInfo) + { + std::vector > temp; + uint32_t count = 0; + for (auto d : s.second.damage) + { + if (d.second.count != 0 && temp.size() < 15) + { + temp.push_back(d); + count += d.second.count; + } + } + std::sort(temp.begin(), temp.end(), [](std::pair a, std::pair b){return a.second > b.second; }); + char string[256]; + sprintf_s(string, 256, " %s - %s\n", it->second.name.c_str(), s.second.name.c_str()); + deepsBase->SetText(string); + deepsBase->GetBackground()->SetWidth(262); + repairBars(deepsBase, temp.size()); + int i = 0; + uint32_t max = 0; + for (auto s : temp) + { + char name[32]; + sprintf_s(name, 32, "DeepsBar%d", i); + IFontObject* bar = m_AshitaCore->GetFontManager()->Get(name); + if (s.second.count > max) max = s.second.count; + bar->GetBackground()->SetWidth(254 * (count == 0 ? 1 : 1 * ((float)s.second.count / (float)max))); + bar->GetBackground()->SetColor(it->second.color); + char string[256]; + sprintf_s(string, 256, " %-5s Cnt:%4d Avg:%5d Max:%5d %3.1f%%\n", s.first, s.second.count, s.second.avg(), s.second.max, count == 0 ? 0 : 100 * ((float)s.second.count / (float)count)); + bar->SetText(string); + i++; + } + break; + } + } + } + } + } + deepsBase->GetBackground()->SetHeight(m_bars * 16 + 17); +} + +void Deeps::repairBars(IFontObject* deepsBase, uint8_t size) +{ + IFontObject* previous = deepsBase; + if (m_AshitaCore->GetFontManager()->Get("DeepsBar0") != NULL) + { + char name[32] = "DeepsBar0"; + int i = 1; + while (m_AshitaCore->GetFontManager()->Get(name) != NULL) + { + previous = m_AshitaCore->GetFontManager()->Get(name); + sprintf_s(name, 32, "DeepsBar%d", i); + i++; + } + } + while (m_bars != size) + { + if (m_bars > size) + { + char name[32]; + sprintf_s(name, 32, "DeepsBar%d", m_bars - 1); + m_AshitaCore->GetFontManager()->Delete(name); + memset(name, 0, sizeof name); + sprintf_s(name, 32, "DeepsBarClick%d", m_bars - 1); + m_AshitaCore->GetFontManager()->Delete(name); + m_bars--; + } + else if (m_bars < size) + { + char name[32]; + sprintf_s(name, 32, "DeepsBar%d", m_bars); + IFontObject* bar = m_AshitaCore->GetFontManager()->Create(name); + bar->SetParent(previous); + if (previous == deepsBase) + { + bar->SetPositionX(4); + bar->SetPositionY(15); + } + else + { + bar->SetAnchorParent((uint32_t)Ashita::FrameAnchor::BottomLeft); + bar->SetPositionX(0); + bar->SetPositionY(3); + } + bar->SetAutoResize(false); + bar->SetFontFamily("Consolas"); + bar->SetFontHeight(8); + bar->GetBackground()->SetColor(D3DCOLOR_ARGB(0xFF, 0x00, 0x7C, 0x5C)); + bar->GetBackground()->SetVisibility(true); + std::string path = m_AshitaCore->GetAshitaInstallPathA(); + path.append("\\Resources\\Deeps\\bar.tga"); + bar->GetBackground()->SetTextureFromFile(path.c_str()); + bar->GetBackground()->SetWidth(254); + bar->GetBackground()->SetHeight(13); + bar->SetVisibility(true); + + memset(name, 0, sizeof name); + sprintf_s(name, 32, "DeepsBarClick%d", m_bars); + IFontObject* clickBar = m_AshitaCore->GetFontManager()->Create(name); + clickBar->SetParent(bar); + clickBar->SetPositionX(0); + clickBar->SetPositionY(0); + clickBar->SetAutoResize(false); + clickBar->GetBackground()->SetColor(D3DCOLOR_ARGB(0x00, 0x00, 0x00, 0x00)); + clickBar->GetBackground()->SetVisibility(true); + clickBar->GetBackground()->SetWidth(254); + clickBar->GetBackground()->SetHeight(13); + clickBar->SetVisibility(true); + clickBar->SetMouseEventFunction(g_onClick); + + m_bars++; + previous = bar; + } + } +} + +void Deeps::onClick(int type, IFontObject* font, float xPos, float yPos) +{ + if (type == 1 && font == m_AshitaCore->GetFontManager()->Get("DeepsBackground")) + { + if (m_sourceInfo != "") + { + m_sourceInfo = ""; + } + else + { + m_charInfo = 0; + } + return; + } + + if (m_charInfo == 0) + { + //Char was clicked + if (type == 0) + { + // left click + try + { + auto name = clickMap.at(font); + for (auto entity : entities) + { + if (entity.second.name == name) + { + m_charInfo = entity.first; + break; + } + } + } + catch (...) + { + return; + } + } + } + else + { + if (m_sourceInfo == "") + { + //source was clicked + if (type == 0) + { + try + { + auto name = clickMap.at(font); + m_sourceInfo.assign(name); + } + catch (...) + { + return; + } + } + } + } +} + +/** + * @brief Gets the interface version this plugin was compiled with. + * + * @note This is a required export, your plugin must implement this! + */ +__declspec(dllexport) double __stdcall GetInterfaceVersion(void) +{ + return ASHITA_INTERFACE_VERSION; +} + +/** + * @brief Gets the plugin data for this plugin. + * + * @note This is a required export, your plugin must implement this! + */ +__declspec(dllexport) void __stdcall CreatePluginInfo(plugininfo_t* lpBuffer) +{ + g_PluginInfo = lpBuffer; + + strcpy_s(g_PluginInfo->Name, sizeof(g_PluginInfo->Name), "Deeps"); + strcpy_s(g_PluginInfo->Author, sizeof(g_PluginInfo->Author), "kjLotus"); + + g_PluginInfo->InterfaceVersion = ASHITA_INTERFACE_VERSION; + g_PluginInfo->PluginVersion = 2.03f; + g_PluginInfo->Priority = 0; +} + +/** + * @brief Creates an instance of this plugin object. + * + * @note This is a required export, your plugin must implement this! + */ +__declspec(dllexport) IPlugin* __stdcall CreatePlugin(void) +{ + return (IPlugin*)new Deeps(); +} + +void g_onClick(int type, void* font, float xPos, float yPos) +{ + g_Deeps->onClick(type, (IFontObject*)font, xPos, yPos); } \ No newline at end of file diff --git a/release/plugins/Deeps.dll b/release/plugins/Deeps.dll index 3df6b281415c9d08896559d577fa88c20af0c9ff..7ab9995b95335338b9432f299d6a0731b65638d0 100644 GIT binary patch delta 41537 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 N@@HS^b^f3E{|DpLcy|B* delta 40695 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 gIu