From 2af7b6ab93ce366a48f6c261d28c66292e49e4a8 Mon Sep 17 00:00:00 2001 From: Lolwutt Date: Sat, 11 Nov 2017 22:26:04 -0500 Subject: [PATCH] Initial commit.. --- release/docs/MultiSend.txt | 16 ++ release/docs/XML Structure.xml | 10 + release/plugins/MultiSend.dll | Bin 0 -> 73728 bytes src/MultiSend.sln | 28 +++ src/MultiSend/Commands.cpp | 241 ++++++++++++++++++++++++ src/MultiSend/Exports.def | 5 + src/MultiSend/Follow.cpp | 43 +++++ src/MultiSend/Groups.cpp | 126 +++++++++++++ src/MultiSend/IO.cpp | 147 +++++++++++++++ src/MultiSend/Main.cpp | 126 +++++++++++++ src/MultiSend/MultiSend.h | 109 +++++++++++ src/MultiSend/MultiSend.vcxproj | 156 +++++++++++++++ src/MultiSend/MultiSend.vcxproj.filters | 56 ++++++ src/MultiSend/MultiSend.vcxproj.user | 4 + src/MultiSend/Name.cpp | 19 ++ src/MultiSend/Structs.h | 49 +++++ src/MultiSend/Substitute.cpp | 63 +++++++ src/MultiSend/Thread.cpp | 85 +++++++++ 18 files changed, 1283 insertions(+) create mode 100644 release/docs/MultiSend.txt create mode 100644 release/docs/XML Structure.xml create mode 100644 release/plugins/MultiSend.dll create mode 100644 src/MultiSend.sln create mode 100644 src/MultiSend/Commands.cpp create mode 100644 src/MultiSend/Exports.def create mode 100644 src/MultiSend/Follow.cpp create mode 100644 src/MultiSend/Groups.cpp create mode 100644 src/MultiSend/IO.cpp create mode 100644 src/MultiSend/Main.cpp create mode 100644 src/MultiSend/MultiSend.h create mode 100644 src/MultiSend/MultiSend.vcxproj create mode 100644 src/MultiSend/MultiSend.vcxproj.filters create mode 100644 src/MultiSend/MultiSend.vcxproj.user create mode 100644 src/MultiSend/Name.cpp create mode 100644 src/MultiSend/Structs.h create mode 100644 src/MultiSend/Substitute.cpp create mode 100644 src/MultiSend/Thread.cpp diff --git a/release/docs/MultiSend.txt b/release/docs/MultiSend.txt new file mode 100644 index 0000000..7a1e68c --- /dev/null +++ b/release/docs/MultiSend.txt @@ -0,0 +1,16 @@ +Multisend is a replacement for servo. No synchronization is needed, just load and go. +Commands are as follows(all can be prefixed with /ms or /multisend): + +/ms send [command] - Sends the command to all characters with MultiSend loaded. +/ms sendto CharName [command] - Sends the command to a specific character, if they have MultiSend loaded. +/ms sendgroup GroupName [command] - Sends the command to all characters listed in a group. Groups can be defined in Ashita/Config/MultiSend.xml. See XML Structure file for example. +/ms followme on/off - Enables or disables followme. When followme is enabled, any characters with follow enabled will follow the player who last activated followme. +/ms follow on/off - Enables or disables follow. Any character with follow enabled with follow the player who last activated followme. +/ms ignoreself on/off - When enabled, any command that would effect the local character is not executed by the local character. +/ms debug on/off - When enabled, all received commands are printed to log and any character with followme updated will spam log with position updates. For debug purposes, obviously. +/ms reload - Will reload groups xml. +/ms help - Print an ingame reference. + +You may use [t] [me] or [p0] [p1] [p2] [p3] [p4] [p5] to replace the <> equivalents, if you wish to resolve them on local character. This will replace them with the appropriate server IDs, allowing the command to resolve on receiving character. + +Example: Typing /ms send /ma "Fire IV" [t] will make all characters with multisend loaded cast Fire IV on the character who typed the command's target, rather than their own current target. \ No newline at end of file diff --git a/release/docs/XML Structure.xml b/release/docs/XML Structure.xml new file mode 100644 index 0000000..3820e71 --- /dev/null +++ b/release/docs/XML Structure.xml @@ -0,0 +1,10 @@ + + + Avesta + Stanlee + + + Deadpool + Wolverine + + \ No newline at end of file diff --git a/release/plugins/MultiSend.dll b/release/plugins/MultiSend.dll new file mode 100644 index 0000000000000000000000000000000000000000..1bb6b2c968ee2b383985ef0c4b1d9c7622cf1a1a GIT binary patch literal 73728 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 literal 0 HcmV?d00001 diff --git a/src/MultiSend.sln b/src/MultiSend.sln new file mode 100644 index 0000000..f786c16 --- /dev/null +++ b/src/MultiSend.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MultiSend", "MultiSend\MultiSend.vcxproj", "{3C74E1A4-E44B-4523-85DC-9A94AC2D6457}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3C74E1A4-E44B-4523-85DC-9A94AC2D6457}.Debug|x64.ActiveCfg = Debug|x64 + {3C74E1A4-E44B-4523-85DC-9A94AC2D6457}.Debug|x64.Build.0 = Debug|x64 + {3C74E1A4-E44B-4523-85DC-9A94AC2D6457}.Debug|x86.ActiveCfg = Debug|Win32 + {3C74E1A4-E44B-4523-85DC-9A94AC2D6457}.Debug|x86.Build.0 = Debug|Win32 + {3C74E1A4-E44B-4523-85DC-9A94AC2D6457}.Release|x64.ActiveCfg = Release|x64 + {3C74E1A4-E44B-4523-85DC-9A94AC2D6457}.Release|x64.Build.0 = Release|x64 + {3C74E1A4-E44B-4523-85DC-9A94AC2D6457}.Release|x86.ActiveCfg = Release|Win32 + {3C74E1A4-E44B-4523-85DC-9A94AC2D6457}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/MultiSend/Commands.cpp b/src/MultiSend/Commands.cpp new file mode 100644 index 0000000..65a50d4 --- /dev/null +++ b/src/MultiSend/Commands.cpp @@ -0,0 +1,241 @@ +#include "MultiSend.h" + +bool MultiSend::HandleCommand(const char* command, int32_t type) +{ + std::string arg; + const char* com = command + GetArg(command, &arg); + if ((_stricmp(arg.c_str(), "/ms")) + && (_stricmp(arg.c_str(), "/multisend"))) + { + return false; + } + + if (strlen(com) < 2) return true; + com++; + com += GetArg(com, &arg); + + + if (_stricmp(arg.c_str(), "send") == 0) + { + if (strlen(com) < 2) return true; + SendCommand(0xFFFF0000, com + 1); + return true; + } + + if (_stricmp(arg.c_str(), "sendto") == 0) + { + if (strlen(com) < 2) + { + m_AshitaCore->GetChatManager()->Write("MultiSend: Invalid command."); + return true; + } + com++; + com += GetArg(com, &arg); + + Claim(&(MMF_Pointer->Name.ProcessID), 0); + for (int x = 0; x < 100; x++) + { + if (MMF_Pointer->Name.Names[x].Active) + { + if (_stricmp((const char*)&(MMF_Pointer->Name.Names[x].Name), arg.c_str()) == 0) + { + SendCommand(MMF_Pointer->Name.Names[x].Process, com + 1); + InterlockedExchange(&(MMF_Pointer->Name.ProcessID), 0); + return true; + } + } + } + + InterlockedExchange(&(MMF_Pointer->Name.ProcessID), 0); + m_AshitaCore->GetChatManager()->Write("MultiSend: Character not found."); + } + + if (_stricmp(arg.c_str(), "sendgroup") == 0) + { + if (strlen(com) < 3) + { + m_AshitaCore->GetChatManager()->Write("MultiSend: Invalid command."); + return true; + } + com++; + com += GetArg(com, &arg); + + for (std::map::iterator it = m_Group.Map.begin(); it != m_Group.Map.end(); it++) + { + if (_stricmp((*it).second.c_str(), arg.c_str()) == 0) + { + SendCommand(0x8FFF0000 + (*it).first, com + 1); + return true; + } + } + + m_AshitaCore->GetChatManager()->Write("MultiSend: Group not found."); + return true; + } + + if (_stricmp(arg.c_str(), "followme") == 0) + { + if (strlen(com) < 2) return true; + com++; + com += GetArg(com, &arg); + + if (_stricmp(arg.c_str(), "on") == 0) + { + InterlockedExchange(&(MMF_Pointer->Follow.FollowID), GetCurrentProcessId()); + if (!Zoning) + { + Following = false; + uint16_t myindex = m_AshitaCore->GetDataManager()->GetParty()->GetMemberTargetIndex(0); + uint32_t mPosX = (uint32_t)floor(m_AshitaCore->GetDataManager()->GetEntity()->GetLocalX(myindex) * 100); + uint32_t mPosZ = (uint32_t)floor(m_AshitaCore->GetDataManager()->GetEntity()->GetLocalZ(myindex) * 100); + MMF_Pointer->Follow.PosX = mPosX; + MMF_Pointer->Follow.PosZ = mPosZ; + MMF_Pointer->Follow.Follow = 1; + } + else + { + Following = false; + MMF_Pointer->Follow.Follow = 3; + } + m_AshitaCore->GetChatManager()->Write("MultiSend: Followme enabled."); + } + + else if (_stricmp(arg.c_str(), "off") == 0) + { + InterlockedExchange(&(MMF_Pointer->Follow.FollowID), 0); + MMF_Pointer->Follow.Follow = 0; + m_AshitaCore->GetChatManager()->Write("MultiSend: Followme disabled."); + } + + else + { + m_AshitaCore->GetChatManager()->Writef("MultiSend: Followme is currently %s.", (MMF_Pointer->Follow.FollowID == GetCurrentProcessId()) ? "enabled" : "disabled"); + } + + return true; + } + + if (_stricmp(arg.c_str(), "follow") == 0) + { + if (strlen(com) < 2) return true; + com++; + com += GetArg(com, &arg); + + if (_stricmp(arg.c_str(), "on") == 0) + { + FollowEnabled = true; + m_AshitaCore->GetChatManager()->Write("MultiSend: Follow enabled. Note that if someone is not currently using followme, no movement will occur."); + } + + else if (_stricmp(arg.c_str(), "off") == 0) + { + FollowEnabled = false; + m_AshitaCore->GetChatManager()->Write("MultiSend: Follow disabled."); + } + + else + { + m_AshitaCore->GetChatManager()->Writef("MultiSend: Follow is currently %s.", FollowEnabled ? "enabled" : "disabled"); + } + + return true; + } + + if (_stricmp(arg.c_str(), "ignoreself") == 0) + { + if (strlen(com) < 2) return true; + com++; + com += GetArg(com, &arg); + + if (_stricmp(arg.c_str(), "on") == 0) + { + IgnoreSelf = true; + m_AshitaCore->GetChatManager()->Write("MultiSend: Now ignoring self-published commands."); + } + + else if (_stricmp(arg.c_str(), "off") == 0) + { + IgnoreSelf = false; + m_AshitaCore->GetChatManager()->Write("MultiSend: Now accepting self-published commands."); + } + + else + { + m_AshitaCore->GetChatManager()->Writef("MultiSend: Ignore self is currently %s.", IgnoreSelf ? "enabled" : "disabled"); + } + return true; + } + + if (_stricmp(arg.c_str(), "debug") == 0) + { + if (strlen(com) < 2) return true; + com++; + com += GetArg(com, &arg); + + if (_stricmp(arg.c_str(), "on") == 0) + { + IgnoreSelf = true; + m_AshitaCore->GetChatManager()->Write("MultiSend: Debug prints enabled."); + } + + else if (_stricmp(arg.c_str(), "off") == 0) + { + IgnoreSelf = false; + m_AshitaCore->GetChatManager()->Write("MultiSend: Debug prints disabled."); + } + + else + { + m_AshitaCore->GetChatManager()->Writef("MultiSend: Debug prints currently %s.", _Debug ? "enabled" : "disabled"); + } + + return true; + } + + if (_stricmp(arg.c_str(), "reload") == 0) + { + LoadGroups(); + return true; + } + + if (_stricmp(arg.c_str(), "help") == 0) + { + m_AshitaCore->GetChatManager()->Write("Multisend Command Listing"); + m_AshitaCore->GetChatManager()->Write("/ms send [command] - Sends [command] to all characters with multisend loaded."); + m_AshitaCore->GetChatManager()->Write("/ms sendto [char name] [command] - Sends [command] to all characters with multisend loaded named [char name]."); + m_AshitaCore->GetChatManager()->Write("/ms sendgroup [group name] [command] - Sends [command] to all characters with multisend loaded that are defined within the group [group name]."); + m_AshitaCore->GetChatManager()->Write("/ms follow on/off - When enabled, the current character will obey followme."); + m_AshitaCore->GetChatManager()->Write("/ms followme on/off - When enabled, all characters with follow enabled will follow this character. Only one character can have this active at a time, if you activate it on a second the first will deactivate automatically."); + m_AshitaCore->GetChatManager()->Write("/ms reload - Reloads group file without reloading MultiSend."); + m_AshitaCore->GetChatManager()->Write("/ms ignoreself on/off - When enabled, send and sendgroup commands sent by this character will not execute on this character."); + m_AshitaCore->GetChatManager()->Write("/ms debug on/off - When enabled, debug prints will be visible."); + return true; + } + + return true; +} + +uint32_t MultiSend::GetArg(const char* text, std::string* buffer) +{ + std::string working(text); + + if (working[0] == '"') + { + size_t second = working.substr(1).find_first_of('"'); + if (second != string::npos) + { + *buffer = working.substr(1, second); + return second + 1; + } + } + + size_t space = working.find_first_of(' '); + if (space != string::npos) + { + *buffer = working.substr(0, space); + return space; + } + + *buffer = string(text); + return strlen(text); +} \ No newline at end of file diff --git a/src/MultiSend/Exports.def b/src/MultiSend/Exports.def new file mode 100644 index 0000000..f04134d --- /dev/null +++ b/src/MultiSend/Exports.def @@ -0,0 +1,5 @@ +LIBRARY "MultiSend" +EXPORTS + GetInterfaceVersion + CreatePluginInfo + CreatePlugin \ No newline at end of file diff --git a/src/MultiSend/Follow.cpp b/src/MultiSend/Follow.cpp new file mode 100644 index 0000000..121a6c9 --- /dev/null +++ b/src/MultiSend/Follow.cpp @@ -0,0 +1,43 @@ +#include "MultiSend.h" + +bool MultiSend::Direct3DInitialize(IDirect3DDevice8* lpDevice) +{ + this->m_Direct3DDevice = lpDevice; + return true; +} + +/** +* @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 MultiSend::Direct3DPreRender(void) +{ + if (FollowEnabled) + { + if (Following) + { + uint16_t myindex = m_AshitaCore->GetDataManager()->GetParty()->GetMemberTargetIndex(0); + float MyX = m_AshitaCore->GetDataManager()->GetEntity()->GetLocalX(myindex); + float MyZ = m_AshitaCore->GetDataManager()->GetEntity()->GetLocalZ(myindex); + double Distance = sqrt(pow(PositionX - MyX, 2) + pow(PositionZ - MyZ, 2)); + + if (Distance > 0.4f) + { + StructPointer->DirX = PositionX - MyX; + StructPointer->DirY = 0; + StructPointer->DirZ = PositionZ - MyZ; + StructPointer->Autorun = 1; + } + else + { + StructPointer->Autorun = 0; + } + } + else if (StopFollow) + { + StructPointer->Autorun = 0; + StopFollow = false; + } + } +} \ No newline at end of file diff --git a/src/MultiSend/Groups.cpp b/src/MultiSend/Groups.cpp new file mode 100644 index 0000000..0b97005 --- /dev/null +++ b/src/MultiSend/Groups.cpp @@ -0,0 +1,126 @@ +#include "MultiSend.h" +#include +#include +using namespace rapidxml; + +bool MultiSend::MatchID(uint32_t ID) +{ + if ((ID & 0xFFFF0000) == 0xFFFF0000) + { + return true; + } + if ((ID & 0x8FFF0000) == 0x8FFF0000) + { + uint16_t GroupID = (ID & 0x0000FFFF); + return (std::find(Groups.begin(), Groups.end(), GroupID) != Groups.end()); + } + return (::GetCurrentProcessId() == ID); +} + +void MultiSend::LoadGroups() +{ + m_Group.Map.clear(); + Groups.clear(); + string Path = m_AshitaCore->GetAshitaInstallPathA(); + Path += "config\\MultiSend.xml"; + + std::ifstream Reader(Path, ios::in | ios::binary | ios::ate); + if (Reader.is_open()) + { + Reader.seekg(0, ios::end); + uint32_t Size = (uint32_t)Reader.tellg(); + + m_Group.rawdata = new char[Size + 1]; + Reader.seekg(0, ios::beg); + Reader.read(m_Group.rawdata, Size); + Reader.close(); + m_Group.rawdata[Size] = '\0'; + try + { + m_Group.doc.parse<0>(m_Group.rawdata); + m_AshitaCore->GetChatManager()->Write("MultiSend: Groups loaded."); + m_Group.Loaded = true; + } + catch (...) + { + m_AshitaCore->GetChatManager()->Write("MultiSend: Groups failed to parse."); + m_Group.doc.clear(); + m_Group.Loaded = false; + delete m_Group.rawdata; + } + } + else + { + if (m_Group.Loaded) + { + m_Group.doc.clear(); + delete m_Group.rawdata; + m_Group.Loaded = false; + } + m_AshitaCore->GetChatManager()->Write("MultiSend: No groups file found."); + } + + if (m_Group.Loaded) + { + ReadXML(); + MatchGroups(); + } +} + +void MultiSend::ReadXML() +{ + m_Group.Map.clear(); + + xml_node<> *Node = m_Group.doc.first_node(); + if (_stricmp(Node->name(), "multisend") == 0) Node = Node->first_node(); + while (Node) + { + if (_stricmp(Node->name(), "group") == 0) + { + xml_attribute<> *Attr = Node->first_attribute("index"); + if (Attr) + { + xml_attribute<> *Attr2 = Node->first_attribute("name"); + if (Attr2) + { + m_Group.Map.insert(std::make_pair((uint16_t)atoi(Attr->value()), std::string(Attr2->value()))); + } + } + } + Node = Node->next_sibling(); + } +} + +void MultiSend::MatchGroups() +{ + Groups.clear(); + if (CurrentName.length() < 3) return; + if (!m_Group.Loaded) return; + + xml_node<> *Node = m_Group.doc.first_node(); + if (_stricmp(Node->name(), "multisend") == 0) Node = Node->first_node(); + while (Node) + { + if (_stricmp(Node->name(), "group") == 0) + { + xml_attribute<> *Attr = Node->first_attribute("index"); + if (Attr) + { + xml_attribute<> *Attr2 = Node->first_attribute("name"); + if (Attr2) + { + uint16_t Index = (uint16_t)atoi(Attr->value()); + for (xml_node<> *SubNode = Node->first_node("char"); SubNode != NULL; SubNode = SubNode->next_sibling("char")) + { + if (_stricmp(CurrentName.c_str(), SubNode->value()) == 0) + { + Groups.push_back(Index); + break; + } + } + } + } + } + Node = Node->next_sibling(); + } +} \ No newline at end of file diff --git a/src/MultiSend/IO.cpp b/src/MultiSend/IO.cpp new file mode 100644 index 0000000..cbe8bde --- /dev/null +++ b/src/MultiSend/IO.cpp @@ -0,0 +1,147 @@ +#include "MultiSend.h" + +bool MultiSend::ReadCommand() +{ + if (MMF_Pointer->Command.Command[Position].Active) + { + if (MatchID(MMF_Pointer->Command.Command[Position].Targets)) + { + if ((!IgnoreSelf) + || (GetCurrentProcessId() != MMF_Pointer->Command.Command[Position].SendProcess)) + { + const char* text = new char[248]; + memset((void*)text, 0, 248); + memcpy((void*)text, &(MMF_Pointer->Command.Command[Position].Command), 248); + if (_Debug) + { + m_AshitaCore->GetChatManager()->Writef("Sending command: %s", text); + } + m_AshitaCore->GetChatManager()->QueueCommand(text, 0); + delete text; + } + } + Position++; + if (Position == 100) Position = 0; + return true; + } + return false; +} + +void MultiSend::SetFollow(bool Active) +{ + if (Active) + { + Following = false; + uint16_t myindex = m_AshitaCore->GetDataManager()->GetParty()->GetMemberTargetIndex(0); + uint32_t mPosX = (uint32_t)floor(m_AshitaCore->GetDataManager()->GetEntity()->GetLocalX(myindex) * 100); + uint32_t mPosZ = (uint32_t)floor(m_AshitaCore->GetDataManager()->GetEntity()->GetLocalZ(myindex) * 100); + MMF_Pointer->Follow.PosX = mPosX; + MMF_Pointer->Follow.PosZ = mPosZ; + MMF_Pointer->Follow.Follow = 1; + } + else + { + MMF_Pointer->Follow.Follow = 0; + } +} + +void MultiSend::SendCommand(uint32_t ID, const char* Command) +{ + char* Text = new char[248]; + memset((void*)Text, 0, 248); + memcpy(Text, Command, strlen(Command)); + SubValues(Text); + + Claim(&(MMF_Pointer->Command.ProcessID), 0); + + int NextPosition = MMF_Pointer->Command.Position + 1; + if (NextPosition == 100) NextPosition = 0; + + MMF_Pointer->Command.Command[NextPosition].Active = false; + + memset(&(MMF_Pointer->Command.Command[MMF_Pointer->Command.Position].Command), 0, 248); + if (strlen(Text) > 247) + { + memcpy(&(MMF_Pointer->Command.Command[MMF_Pointer->Command.Position].Command), Text, 247); + } + else + { + memcpy(&(MMF_Pointer->Command.Command[MMF_Pointer->Command.Position].Command), Text, strlen(Text)); + } + if (_Debug) + { + m_AshitaCore->GetChatManager()->Writef("Publishing position %d : %s", MMF_Pointer->Command.Position, Text); + } + MMF_Pointer->Command.Command[MMF_Pointer->Command.Position].SendProcess = GetCurrentProcessId(); + MMF_Pointer->Command.Command[MMF_Pointer->Command.Position].Targets = ID; + MMF_Pointer->Command.Command[MMF_Pointer->Command.Position].Active = true; + MMF_Pointer->Command.Position = NextPosition; + InterlockedExchange(&(MMF_Pointer->Command.ProcessID), 0); + delete Text; +} + +void MultiSend::UpdateName(std::string Name) +{ + Claim(&(MMF_Pointer->Name.ProcessID), 0xFFFF0000); + bool Written = false; + for (int x = 0; x < 100; x++) + { + if (!MMF_Pointer->Name.Names[x].Active) + { + if (!Written) + { + memcpy(&(MMF_Pointer->Name.Names[x].Name), Name.c_str(), strlen(Name.c_str()) + 1); + MMF_Pointer->Name.Names[x].Process = GetCurrentProcessId(); + MMF_Pointer->Name.Names[x].Active = 1; + Written = true; + } + continue; + } + + else if (MMF_Pointer->Name.Names[x].Process == GetCurrentProcessId()) + { + memset(&(MMF_Pointer->Name.Names[x]), 0, sizeof(MMF_Name_Single)); + if (!Written) + { + memcpy(&(MMF_Pointer->Name.Names[x].Name), Name.c_str(), strlen(Name.c_str()) + 1); + MMF_Pointer->Name.Names[x].Process = GetCurrentProcessId(); + MMF_Pointer->Name.Names[x].Active = 1; + Written = true; + } + } + + else if (strcmp((const char*)&(MMF_Pointer->Name.Names[x].Name), Name.c_str()) == 0) + { + memset(&(MMF_Pointer->Name.Names[x]), 0, sizeof(MMF_Name_Single)); + if (!Written) + { + memcpy(&(MMF_Pointer->Name.Names[x].Name), Name.c_str(), strlen(Name.c_str()) + 1); + MMF_Pointer->Name.Names[x].Process = GetCurrentProcessId(); + MMF_Pointer->Name.Names[x].Active = 1; + Written = true; + } + } + } + CurrentName = Name; + MatchGroups(); + InterlockedExchange(&(MMF_Pointer->Name.ProcessID), 0); +} + +void MultiSend::Claim(uint32_t* Target, uint32_t Mod) +{ + uint32_t val = GetCurrentProcessId() + Mod; + int FailCount = 0; + InterlockedCompareExchange(Target, val, 0); + + while (*Target != val) + { + FailCount++; + if (FailCount == 50) + { + InterlockedExchange(Target, val); + return; + } + ::Sleep(1); + InterlockedCompareExchange(Target, val, 0); + } +} \ No newline at end of file diff --git a/src/MultiSend/Main.cpp b/src/MultiSend/Main.cpp new file mode 100644 index 0000000..e55fe9a --- /dev/null +++ b/src/MultiSend/Main.cpp @@ -0,0 +1,126 @@ +#include "MultiSend.h" +#pragma comment(lib, "psapi.lib") +#include +#include + +MultiSend::MultiSend(void) + : m_AshitaCore(NULL) + , m_PluginId(0) + , m_Direct3DDevice(NULL) +{ } +MultiSend::~MultiSend(void) +{ } + +plugininfo_t* g_PluginInfo = NULL; + +plugininfo_t MultiSend::GetPluginInfo(void) +{ + return (*g_PluginInfo); +} + +bool MultiSend::Initialize(IAshitaCore* core, ILogManager* log, uint32_t id) +{ + this->m_AshitaCore = core; + this->m_PluginId = id; + this->m_LogManager = log; + + LoadGroups(); + + MODULEINFO mod = { 0 }; + if (!::GetModuleInformation(::GetCurrentProcess(), ::GetModuleHandle("FFXiMain.dll"), &mod, sizeof(MODULEINFO))) + return false; + + unsigned char* Pointer = (unsigned char*)Ashita::Memory::FindPattern((uintptr_t)mod.lpBaseOfDll, (uintptr_t)mod.SizeOfImage, + "8BCFE8????FFFF8B0D????????E8????????8BE885ED750CB9", + 0, 0); + if (Pointer == NULL) return false; + + Pointer += 25; + StructPointer = (sFollow*)(*((DWORD*)Pointer)); + + //create a handle to the MMF, size matches the struct we're using for it + HANDLE hMapFile = CreateFileMapping( + INVALID_HANDLE_VALUE, + NULL, + PAGE_READWRITE, + 0, // maximum object size (high-order DWORD) + sizeof(MMF_Global), // maximum object size (low-order DWORD) + "FFXI_MultiSend"); + + bool made = (GetLastError() == 0); + + if (hMapFile == NULL) + { + throw exception("Could not open or create MMF."); + } + + + MMF_Pointer = (MMF_Global*)MapViewOfFile(hMapFile, // handle to map object + FILE_MAP_ALL_ACCESS, // read/write permission + 0, + 0, + sizeof(MMF_Global)); + if (MMF_Pointer == NULL) + { + CloseHandle(hMapFile); + throw exception("Could not map MMF."); + } + + if (made) + { + memset(MMF_Pointer, 0, sizeof(MMF_Global)); + } + Position = MMF_Pointer->Command.Position; + + FollowEnabled = true; + ZoneExtra = false; + IgnoreSelf = false; + + CurrentName = ""; + if (m_AshitaCore->GetDataManager()->GetParty()->GetMemberActive(0)) + { + uint16_t myindex = m_AshitaCore->GetDataManager()->GetParty()->GetMemberTargetIndex(0); + UpdateName(std::string(m_AshitaCore->GetDataManager()->GetEntity()->GetName(myindex))); + } + + _Debug = false; + + this->Start(); + + return true; +} + +void MultiSend::Release(void) +{ + this->Stop(); + if (MMF_Pointer) + { + UnmapViewOfFile((LPCVOID)MMF_Pointer); + } + if (hMapFile) + { + CloseHandle(hMapFile); + } +} + +__declspec(dllexport) double __stdcall GetInterfaceVersion(void) +{ + return ASHITA_INTERFACE_VERSION; +} + +__declspec(dllexport) void __stdcall CreatePluginInfo(plugininfo_t* lpBuffer) +{ + g_PluginInfo = lpBuffer; + + strcpy_s(g_PluginInfo->Name, sizeof(g_PluginInfo->Name), "MultiSend"); + strcpy_s(g_PluginInfo->Author, sizeof(g_PluginInfo->Author), "Thorny"); + + g_PluginInfo->InterfaceVersion = ASHITA_INTERFACE_VERSION; + g_PluginInfo->PluginVersion = 1.00f; + g_PluginInfo->Priority = 0; +} + +__declspec(dllexport) IPlugin* __stdcall CreatePlugin(void) +{ + return (IPlugin*)new MultiSend(); +} diff --git a/src/MultiSend/MultiSend.h b/src/MultiSend/MultiSend.h new file mode 100644 index 0000000..32c025f --- /dev/null +++ b/src/MultiSend/MultiSend.h @@ -0,0 +1,109 @@ +#ifndef __ASHITA_MMF_H_INCLUDED__ +#define __ASHITA_MMF_H_INCLUDED__ + +#if defined (_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif +#define SAFE_DELETE(p) if(p) { delete p; p = NULL; } + +#include "C:\Ashita 3\Plugins\ADK\Ashita.h" +#include "Structs.h" +#include "..\..\pluginheaders\Utilities.h" +#include "..\..\pluginheaders\rapidxml.hpp" +#include +#include +#include + +using namespace std; + + +extern plugininfo_t* g_PluginInfo; + +struct GroupData +{ + bool Loaded; + char* rawdata; + rapidxml::xml_document<> doc; + std::map Map; +}; + +struct sFollow +{ // 42 bytes + unsigned int _unknown_0_4; // 0- 3 Looks like a pointer + unsigned short TargetIndex; // 4- 5+2 + unsigned int TargetID; // 8-11 + float DirX; // 12-15 + float DirY; // 16-19 + float DirZ; // 20-23 + unsigned char _unknown_24_27[4]; // 24-27 + unsigned int _unknown_28_31; // 28-31 Same as _unknown_0_4 + unsigned int FollowIndex; // 32-33+2 + unsigned int FollowID; // 36-39 Once set will overwrite DirX, DirZ and DirY with directional values + unsigned char _zero_40_40; // 40-40 + unsigned char Autorun; // 41-41 +}; + +class MultiSend : IPlugin, Ashita::Threading::AS_Thread +{ + IAshitaCore* m_AshitaCore; + ILogManager* m_LogManager; + DWORD m_PluginId; + IDirect3DDevice8* m_Direct3DDevice; + sFollow* StructPointer; + GroupData m_Group; + + HANDLE hMapFile; + MMF_Global* MMF_Pointer; + + uint32_t Position; + volatile bool ZoneExtra; + volatile bool Following; + volatile float PositionX; + volatile float PositionZ; + std::list Groups; + + std::string CurrentName; + + uint32_t Zoning; //0 = not zoning, 1 = waiting to zone, 2 = zoned and waiting to finish + volatile bool FollowEnabled; + volatile bool StopFollow; + volatile bool IgnoreSelf; + + volatile bool _Debug; + +public: + MultiSend(void); + virtual ~MultiSend(void); + +public: + plugininfo_t GetPluginInfo(void); + +public: + bool Initialize(IAshitaCore* core, ILogManager* log, uint32_t id); + void Release(void); + bool Direct3DInitialize(IDirect3DDevice8* lpDevice); + void Direct3DPreRender(void); + bool HandleIncomingPacket(uint16_t id, uint32_t size, void* data, void* modified, bool blocked) override; + bool HandleCommand(const char* command, int32_t type); + uint32_t ThreadEntry(void) override; + + bool MatchID(uint32_t ID); + bool ReadCommand(); + void SetFollow(bool Active); + void SendCommand(uint32_t ID, const char* Command); + void SubValues(char* Input); + void UpdateName(std::string Name); + void Claim(uint32_t* Target, uint32_t Mod); + + void LoadGroups(); + void ReadXML(); + void MatchGroups(); + + uint32_t GetArg(const char* text, std::string* buffer); +}; + +__declspec(dllexport) double __stdcall GetInterfaceVersion(void); +__declspec(dllexport) void __stdcall CreatePluginInfo(plugininfo_t* lpBuffer); +__declspec(dllexport) IPlugin* __stdcall CreatePlugin(void); + +#endif // __ASHITA_MMF_H_INCLUDED__ diff --git a/src/MultiSend/MultiSend.vcxproj b/src/MultiSend/MultiSend.vcxproj new file mode 100644 index 0000000..e427e45 --- /dev/null +++ b/src/MultiSend/MultiSend.vcxproj @@ -0,0 +1,156 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {3C74E1A4-E44B-4523-85DC-9A94AC2D6457} + MultiSend + + + + Application + true + v140 + MultiByte + + + DynamicLibrary + false + v140_xp + true + MultiByte + + + Application + true + v140 + MultiByte + + + DynamicLibrary + false + v140_xp + true + MultiByte + + + + + + + + + + + + + + + + + + + + + ..\..\bin\ + + + ..\..\bin\ + + + + Level3 + Disabled + true + + + Exports.def + + + + + Level3 + Disabled + true + + + Exports.def + + + + + Level3 + Full + false + true + true + true + true + Async + + + true + true + Exports.def + + + copy "..\..\bin\MultiSend.dll" "C:\Ashita 3\plugins\MultiSend.dll" + + + + + Level3 + Full + false + true + true + true + true + Async + + + true + true + Exports.def + + + copy "..\..\bin\MultiSend.dll" "C:\Ashita 3\plugins\MultiSend.dll" + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/MultiSend/MultiSend.vcxproj.filters b/src/MultiSend/MultiSend.vcxproj.filters new file mode 100644 index 0000000..10142f1 --- /dev/null +++ b/src/MultiSend/MultiSend.vcxproj.filters @@ -0,0 +1,56 @@ + + + + + {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 + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Source Files + + + \ No newline at end of file diff --git a/src/MultiSend/MultiSend.vcxproj.user b/src/MultiSend/MultiSend.vcxproj.user new file mode 100644 index 0000000..6fb136b --- /dev/null +++ b/src/MultiSend/MultiSend.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/MultiSend/Name.cpp b/src/MultiSend/Name.cpp new file mode 100644 index 0000000..e56c9ab --- /dev/null +++ b/src/MultiSend/Name.cpp @@ -0,0 +1,19 @@ +#include "MultiSend.h" + + +bool MultiSend::HandleIncomingPacket(uint16_t id, uint32_t size, void* data, void* modified, bool blocked) +{ + if (id == 0x00A) + { + if (strcmp(CurrentName.c_str(), (const char*)data + 0x84)) + { + UpdateName(std::string((const char*)data + 0x84)); + } + } + if (id == 0x00B) + { + Zoning = 1; + } + + return false; +} \ No newline at end of file diff --git a/src/MultiSend/Structs.h b/src/MultiSend/Structs.h new file mode 100644 index 0000000..47f8aa1 --- /dev/null +++ b/src/MultiSend/Structs.h @@ -0,0 +1,49 @@ +#ifndef _STRUCTS_H_ +#define _STRUCTS_H_ + +#include + +struct MMF_Name_Single +{ + uint32_t Process; + uint8_t Name[64]; + uint8_t Active; +}; + +struct MMF_Name +{ + uint32_t ProcessID; + MMF_Name_Single Names[100]; +}; + +struct MMF_ICommand_Single +{ + uint8_t Active; + uint32_t Targets; + uint32_t SendProcess; + uint8_t Command[248]; +}; + +struct MMF_ICommand +{ + uint32_t ProcessID; + uint32_t Position; + MMF_ICommand_Single Command[100]; +}; + +struct MMF_IFollow +{ + uint16_t Zone; + uint32_t FollowID; + uint32_t Follow; + int32_t PosX; + int32_t PosZ; +}; + +struct MMF_Global +{ + MMF_Name Name; + MMF_ICommand Command; + MMF_IFollow Follow; +}; +#endif \ No newline at end of file diff --git a/src/MultiSend/Substitute.cpp b/src/MultiSend/Substitute.cpp new file mode 100644 index 0000000..063210a --- /dev/null +++ b/src/MultiSend/Substitute.cpp @@ -0,0 +1,63 @@ +#include "MultiSend.h" + +void MultiSend::SubValues(char* Input) +{ + std::string Working(Input); + + size_t find = Working.find("[me]"); + if (find != string::npos) + { + Working.replace(find, 4, std::to_string(m_AshitaCore->GetDataManager()->GetParty()->GetMemberServerId(0))); + } + + find = Working.find("[p0]"); + if (find != string::npos) + { + Working.replace(find, 4, std::to_string(m_AshitaCore->GetDataManager()->GetParty()->GetMemberServerId(0))); + } + + find = Working.find("[p1]"); + if (find != string::npos) + { + Working.replace(find, 4, std::to_string(m_AshitaCore->GetDataManager()->GetParty()->GetMemberServerId(1))); + } + + find = Working.find("[p2]"); + if (find != string::npos) + { + Working.replace(find, 4, std::to_string(m_AshitaCore->GetDataManager()->GetParty()->GetMemberServerId(2))); + } + + find = Working.find("[p3]"); + if (find != string::npos) + { + Working.replace(find, 4, std::to_string(m_AshitaCore->GetDataManager()->GetParty()->GetMemberServerId(3))); + } + + find = Working.find("[p4]"); + if (find != string::npos) + { + Working.replace(find, 4, std::to_string(m_AshitaCore->GetDataManager()->GetParty()->GetMemberServerId(4))); + } + + find = Working.find("[p5]"); + if (find != string::npos) + { + Working.replace(find, 4, std::to_string(m_AshitaCore->GetDataManager()->GetParty()->GetMemberServerId(5))); + } + + find = Working.find("[t]"); + if (find != string::npos) + { + unsigned int TargetIndex = m_AshitaCore->GetDataManager()->GetTarget()->GetTargetIndex(); + if (m_AshitaCore->GetDataManager()->GetTarget()->GetSubTargetActive()) + { + TargetIndex = m_AshitaCore->GetDataManager()->GetTarget()->GetSubTargetIndex(); + } + Working.replace(find, 3, std::to_string(m_AshitaCore->GetDataManager()->GetEntity()->GetServerId(TargetIndex))); + } + + const char* base = Working.c_str(); + memset(Input, 0, 248); + memcpy(Input, base, strlen(base)); +} \ No newline at end of file diff --git a/src/MultiSend/Thread.cpp b/src/MultiSend/Thread.cpp new file mode 100644 index 0000000..46b612b --- /dev/null +++ b/src/MultiSend/Thread.cpp @@ -0,0 +1,85 @@ +#include "MultiSend.h" + +uint32_t MultiSend::ThreadEntry(void) +{ + while (!this->IsTerminated()) + { + if (m_AshitaCore->GetDataManager()->GetParty()->GetMemberActive(0)) + { + if (Zoning == 2) Zoning = 0; + } + else if (Zoning == 1) + { + Zoning = 2; + } + + if (MMF_Pointer->Follow.Follow) + { + if (((MMF_Global*)MMF_Pointer)->Follow.FollowID == GetCurrentProcessId()) + { + if (!Zoning) + { + Following = false; + uint16_t myindex = m_AshitaCore->GetDataManager()->GetParty()->GetMemberTargetIndex(0); + int32_t mPosX = (int32_t)floor(m_AshitaCore->GetDataManager()->GetEntity()->GetLocalX(myindex) * 100); + int32_t mPosZ = (int32_t)floor(m_AshitaCore->GetDataManager()->GetEntity()->GetLocalZ(myindex) * 100); + MMF_Pointer->Follow.PosX = mPosX; + MMF_Pointer->Follow.PosZ = mPosZ; + MMF_Pointer->Follow.Follow = 1; + MMF_Pointer->Follow.Zone = m_AshitaCore->GetDataManager()->GetParty()->GetMemberZone(0); + } + else + { + Following = false; + MMF_Pointer->Follow.Follow = 2; + } + } + else if (MMF_Pointer->Follow.Follow != 3) + { + if (m_AshitaCore->GetDataManager()->GetParty()->GetMemberActive(0)) + { + if (MMF_Pointer->Follow.Follow == 2) + { + if (!ZoneExtra) + { + Following = false; + uint16_t myindex = m_AshitaCore->GetDataManager()->GetParty()->GetMemberTargetIndex(0); + float MyX = m_AshitaCore->GetDataManager()->GetEntity()->GetLocalX(myindex); + float MyZ = m_AshitaCore->GetDataManager()->GetEntity()->GetLocalZ(myindex); + PositionX = (float)MMF_Pointer->Follow.PosX / 100.0f; + PositionZ = (float)MMF_Pointer->Follow.PosZ / 100.0f; + float Scale = 1.0f + (8.0f / sqrt(pow(PositionX - MyX, 2) + pow(PositionZ - MyZ, 2))); + PositionX = (PositionX * Scale) + MyX; + PositionZ = (PositionZ * Scale) + MyZ; + ZoneExtra = true; + Following = true; + } + } + else + { + ZoneExtra = false; + PositionX = (float)MMF_Pointer->Follow.PosX / 100.0f; + PositionZ = (float)MMF_Pointer->Follow.PosZ / 100.0f; + Following = true; + } + } + } + else + { + if (Following) StopFollow = true; + Following = false; + } + } + else + { + if (Following) StopFollow = true; + Following = false; + } + + while (ReadCommand()) {} + + ::Sleep(1); + } + return 0; +} +