From ed2ab118af195115a61540649aa97790cb9beadb Mon Sep 17 00:00:00 2001 From: Thorny Date: Wed, 10 Jun 2020 20:15:47 -0400 Subject: [PATCH] 1.15 - Rewrote follow system, new features added, see documentation for usage. --- .gitignore | 5 +- release/docs/MultiSend.txt | 31 ++++- release/plugins/MultiSend.dll | Bin 75776 -> 68608 bytes src/MultiSend/Commands.cpp | 168 +++++++++++++++--------- src/MultiSend/Follow.cpp | 71 +++++++--- src/MultiSend/Groups.cpp | 100 +++++++++----- src/MultiSend/IO.cpp | 122 +++++++---------- src/MultiSend/Main.cpp | 59 ++++----- src/MultiSend/MultiSend.h | 47 ++++--- src/MultiSend/MultiSend.vcxproj | 24 ++-- src/MultiSend/MultiSend.vcxproj.filters | 16 +-- src/MultiSend/Structs.h | 30 +++-- src/MultiSend/Thread.cpp | 84 ++++-------- src/MultiSend/packets.cpp | 25 ++++ src/MultiSend/text_sanitizing.cpp | 87 ++++++++++++ 15 files changed, 534 insertions(+), 335 deletions(-) create mode 100644 src/MultiSend/packets.cpp create mode 100644 src/MultiSend/text_sanitizing.cpp diff --git a/.gitignore b/.gitignore index 821962c..8f258ad 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ -*.vs/* -*ipch/* -*src*Release/* \ No newline at end of file +src/.vs/ +src/MultiSend/Release/ \ No newline at end of file diff --git a/release/docs/MultiSend.txt b/release/docs/MultiSend.txt index 7a1e68c..b620689 100644 --- a/release/docs/MultiSend.txt +++ b/release/docs/MultiSend.txt @@ -1,13 +1,32 @@ 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): +Commands to send input to other instances on the same PC: /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 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 sendothers [command] - Sends a command to all characters except for the current character. +/ms sendparty - Sends a command to all characters in the current character's immediate party. This includes the current character unless ignoreself is turned on. +/ms sendally - Sends a command to all characters in the current character's immediate alliance. This includes the current character unless ignoreself is turned on. + +These have hardcoded aliases as well: +/mss = /ms send +/mst = /ms sendto +/mso = /ms sendothers +/msp = /ms sendparty +/msa = /ms sendally +/msg = /ms sendgroup + +Configuration: +/ms followmax # - Sets a max range(in yalms). If follow target is more than this many yalms away, but in same zone, follow won't move. +-I recommend setting between 30 and 100 to prevent following from trying to use portals. +-Default is 5000, which will be the same behavior as before this setting was added. +/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. Default: OFF. +/ms follow on/off - Enables or disables follow. Any character with follow enabled with follow the player who last activated followme. Default: ON +/ms attemptzone on/off - Enables or disables attempted zoning. When enabled, if the leader zones, the other characters will continue running in the direction they were last running to follow suit. Default: OFF +NOTE: If you are using a home point, survival guide, etc, it will be detected as long as you stand still throughout the process and nobody will run off. +CONT: If you move after first acting upon the object or sending an uberwarp command, chars may run off. +/ms ignoreself on/off - When enabled, any command that would effect the local character is not executed by the local character. Default: OFF +/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. Default: OFF /ms reload - Will reload groups xml. /ms help - Print an ingame reference. diff --git a/release/plugins/MultiSend.dll b/release/plugins/MultiSend.dll index e8dd582eb40eb9e61a8006f7ddbdf1f8f62b020e..561286c279786f8920629a47818ac641dabd4fb4 100644 GIT binary patch literal 68608 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 r31HL%s^RfYwD3H=0IzPName.ProcessID), 0); + Claim(&(p_MMF->Name.ProcessID), 0); for (int x = 0; x < 100; x++) { - if (MMF_Pointer->Name.Names[x].Active) + if (p_MMF->Name.Names[x].Active) { - if (_stricmp((const char*)&(MMF_Pointer->Name.Names[x].Name), arg.c_str()) == 0) + if (_stricmp((const char*)&(p_MMF->Name.Names[x].Name), arg.c_str()) == 0) { - SendCommand(MMF_Pointer->Name.Names[x].Process, com + 1); - InterlockedExchange(&(MMF_Pointer->Name.ProcessID), 0); + SendCommand(multisend_type::single, p_MMF->Name.Names[x].Process, com + 1); + InterlockedExchange(&(p_MMF->Name.ProcessID), 0); return true; } } } - InterlockedExchange(&(MMF_Pointer->Name.ProcessID), 0); + InterlockedExchange(&(p_MMF->Name.ProcessID), 0); m_AshitaCore->GetChatManager()->Write("MultiSend: Character not found."); return true; } + else if ((_stricmp(arg.c_str(), "sendothers") == 0) + || (_stricmp(arg.c_str(), "/mso") == 0)) + { + if (strlen(com) < 2) return true; + SendCommand(multisend_type::others, ::GetCurrentProcessId(), com + 1); + return true; + } + + else if ((_stricmp(arg.c_str(), "sendparty") == 0) + || (_stricmp(arg.c_str(), "/msp") == 0)) + { + if (strlen(com) < 2) return true; + SendCommand(multisend_type::party, m_AshitaCore->GetDataManager()->GetParty()->GetMemberServerId(0), com + 1); + return true; + } + + else if ((_stricmp(arg.c_str(), "sendally") == 0) + || (_stricmp(arg.c_str(), "/msa") == 0)) + { + if (strlen(com) < 2) return true; + SendCommand(multisend_type::alliance, m_AshitaCore->GetDataManager()->GetParty()->GetMemberServerId(0), com + 1); + return true; + } + else if ((_stricmp(arg.c_str(), "sendgroup") == 0) || (_stricmp(arg.c_str(), "/msg") == 0)) { @@ -70,11 +93,11 @@ bool MultiSend::HandleCommand(const char* command, int32_t type) com++; com += GetArg(com, &arg); - for (std::map::iterator it = m_Group.Map.begin(); it != m_Group.Map.end(); it++) + for (std::map::iterator it = s_group.Map.begin(); it != s_group.Map.end(); it++) { if (_stricmp((*it).second.c_str(), arg.c_str()) == 0) { - SendCommand(0x8FFF0000 + (*it).first, com + 1); + SendCommand(multisend_type::group, (*it).first, com + 1); return true; } } @@ -89,43 +112,76 @@ bool MultiSend::HandleCommand(const char* command, int32_t type) com++; com += GetArg(com, &arg); - if (_stricmp(arg.c_str(), "on") == 0) + bool toggle = !(p_MMF->Follow.target_process_id == GetCurrentProcessId()); + if (_stricmp(arg.c_str(), "on") == 0) toggle = true; + else if (_stricmp(arg.c_str(), "off") == 0) toggle = false; + + if (toggle) { - InterlockedExchange(&(MMF_Pointer->Follow.FollowID), GetCurrentProcessId()); - if (!Zoning) + InterlockedExchange(&(p_MMF->Follow.target_process_id), GetCurrentProcessId()); + uint16_t zone = m_AshitaCore->GetDataManager()->GetParty()->GetMemberZone(0); + uint16_t myindex = m_AshitaCore->GetDataManager()->GetParty()->GetMemberTargetIndex(0); + if ((zone != 0) && (myindex != 0)) { - 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; + p_MMF->Follow.zone = zone; + p_MMF->Follow.position_x = m_AshitaCore->GetDataManager()->GetEntity()->GetLocalX(myindex); + p_MMF->Follow.position_z = m_AshitaCore->GetDataManager()->GetEntity()->GetLocalZ(myindex); + p_MMF->Follow.idle_count = 0; } else { - Following = false; - MMF_Pointer->Follow.Follow = 3; + p_MMF->Follow.zone = 0; } - m_AshitaCore->GetChatManager()->Write("MultiSend: Followme enabled."); } + else + { + p_MMF->Follow.zone = 0; + InterlockedExchange(&(p_MMF->Follow.target_process_id), 0); + } + + m_AshitaCore->GetChatManager()->Writef("MultiSend: Followme is currently %s.", (p_MMF->Follow.target_process_id == GetCurrentProcessId()) ? "enabled" : "disabled"); + return true; + } + + else if (_stricmp(arg.c_str(), "followmax") == 0) + { + if (strlen(com) < 2) return true; + com++; + com += GetArg(com, &arg); + float dist = atof(arg.c_str()); + if (dist < 1.0f) dist = 1.0f; + else if (dist > 5000.0f) dist = 5000.0f; + c_maxdist = dist; + + m_AshitaCore->GetChatManager()->Writef("MultiSend: Maximum follow distance is currently %f.", c_maxdist); + return true; + } + + else 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) + { + c_follow = true; + } 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."); + c_follow = false; } - else { - m_AshitaCore->GetChatManager()->Writef("MultiSend: Followme is currently %s.", (MMF_Pointer->Follow.FollowID == GetCurrentProcessId()) ? "enabled" : "disabled"); + c_follow = !c_follow; } - + + m_AshitaCore->GetChatManager()->Writef("MultiSend: Follow is currently %s.", c_follow ? "enabled" : "disabled"); return true; } - else if (_stricmp(arg.c_str(), "follow") == 0) + else if (_stricmp(arg.c_str(), "attemptzone") == 0) { if (strlen(com) < 2) return true; com++; @@ -133,21 +189,18 @@ bool MultiSend::HandleCommand(const char* command, int32_t type) 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."); + c_attemptzone = true; } - else if (_stricmp(arg.c_str(), "off") == 0) { - FollowEnabled = false; - m_AshitaCore->GetChatManager()->Write("MultiSend: Follow disabled."); + c_attemptzone = false; } - else { - m_AshitaCore->GetChatManager()->Writef("MultiSend: Follow is currently %s.", FollowEnabled ? "enabled" : "disabled"); + c_attemptzone = !c_attemptzone; } - + + m_AshitaCore->GetChatManager()->Writef("MultiSend: Attempted zoning currently %s.", c_attemptzone ? "enabled" : "disabled"); return true; } @@ -159,20 +212,18 @@ bool MultiSend::HandleCommand(const char* command, int32_t type) if (_stricmp(arg.c_str(), "on") == 0) { - IgnoreSelf = true; - m_AshitaCore->GetChatManager()->Write("MultiSend: Now ignoring self-published commands."); + c_ignoreself = true; } - else if (_stricmp(arg.c_str(), "off") == 0) { - IgnoreSelf = false; - m_AshitaCore->GetChatManager()->Write("MultiSend: Now accepting self-published commands."); + c_ignoreself = false; } - else { - m_AshitaCore->GetChatManager()->Writef("MultiSend: Ignore self is currently %s.", IgnoreSelf ? "enabled" : "disabled"); + c_ignoreself = !c_ignoreself; } + + m_AshitaCore->GetChatManager()->Writef("MultiSend: Ignore self is currently %s.", c_ignoreself ? "enabled" : "disabled"); return true; } @@ -184,21 +235,18 @@ bool MultiSend::HandleCommand(const char* command, int32_t type) if (_stricmp(arg.c_str(), "on") == 0) { - _Debug = true; - m_AshitaCore->GetChatManager()->Write("MultiSend: Debug prints enabled."); + c_debug = true; } - else if (_stricmp(arg.c_str(), "off") == 0) { - _Debug = false; - m_AshitaCore->GetChatManager()->Write("MultiSend: Debug prints disabled."); + c_debug = false; } - else { - m_AshitaCore->GetChatManager()->Writef("MultiSend: Debug prints currently %s.", _Debug ? "enabled" : "disabled"); + c_debug = !c_debug; } - + + m_AshitaCore->GetChatManager()->Writef("MultiSend: Debug prints currently %s.", c_debug ? "enabled" : "disabled"); return true; } @@ -210,21 +258,18 @@ bool MultiSend::HandleCommand(const char* command, int32_t type) if (_stricmp(arg.c_str(), "on") == 0) { - _SafeMode = true; - m_AshitaCore->GetChatManager()->Write("MultiSend: Safe mode enabled."); + c_safemode = true; } - else if (_stricmp(arg.c_str(), "off") == 0) { - _SafeMode = false; - m_AshitaCore->GetChatManager()->Write("MultiSend: Safe mode disabled."); + c_safemode = false; } - else { - m_AshitaCore->GetChatManager()->Writef("MultiSend: Safe mode currently %s.", _SafeMode ? "enabled" : "disabled"); + c_safemode = !c_safemode; } - + + m_AshitaCore->GetChatManager()->Writef("MultiSend: Safe mode currently %s.", c_safemode ? "enabled" : "disabled"); return true; } @@ -244,6 +289,7 @@ bool MultiSend::HandleCommand(const char* command, int32_t type) 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 attemptzone on/off - When enabled, multisend will continue running in the direction you were running when follow leader zones."); m_AshitaCore->GetChatManager()->Write("/ms debug on/off - When enabled, debug prints will be visible."); m_AshitaCore->GetChatManager()->Write("/ms safemode on/off - When enabled, '/echo' will be inserted for commands missing the leading '/' to prevent chatlog spam."); return true; diff --git a/src/MultiSend/Follow.cpp b/src/MultiSend/Follow.cpp index 121a6c9..954825e 100644 --- a/src/MultiSend/Follow.cpp +++ b/src/MultiSend/Follow.cpp @@ -13,31 +13,72 @@ bool MultiSend::Direct3DInitialize(IDirect3DDevice8* lpDevice) */ void MultiSend::Direct3DPreRender(void) { - if (FollowEnabled) + if (c_follow) { - if (Following) + if (p_MMF->Follow.target_process_id == ::GetCurrentProcessId()) return; + + if (p_MMF->Follow.target_process_id == 0) + { + if (s_last_run_state) + { + p_Follow->Autorun = 0; + s_last_run_state = false; + } + } + else if (p_MMF->Follow.zone == m_AshitaCore->GetDataManager()->GetParty()->GetMemberZone(0)) { 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)); + float my_pos_x = m_AshitaCore->GetDataManager()->GetEntity()->GetLocalX(myindex); + float my_pos_z = m_AshitaCore->GetDataManager()->GetEntity()->GetLocalZ(myindex); + s_vector_x = p_MMF->Follow.position_x - my_pos_x; + s_vector_z = p_MMF->Follow.position_z - my_pos_z; + double distance = sqrt(pow(s_vector_x, 2) + pow(s_vector_z, 2)); - if (Distance > 0.4f) + if ((distance > 0.4f) && (distance < c_maxdist)) { - StructPointer->DirX = PositionX - MyX; - StructPointer->DirY = 0; - StructPointer->DirZ = PositionZ - MyZ; - StructPointer->Autorun = 1; + p_Follow->FollowID = 0; + p_Follow->FollowIndex = 0; + p_Follow->DirX = s_vector_x; + p_Follow->DirY = 0; + p_Follow->DirZ = s_vector_z; + p_Follow->Autorun = 1; + s_last_run_state = true; } - else + else if (s_last_run_state) { - StructPointer->Autorun = 0; + p_Follow->Autorun = 0; + s_last_run_state = false; } } - else if (StopFollow) + else if (p_MMF->Follow.zone == 0) { - StructPointer->Autorun = 0; - StopFollow = false; + if ((c_attemptzone) + && (p_MMF->Follow.lastzone == m_AshitaCore->GetDataManager()->GetParty()->GetMemberZone(0)) + && (p_MMF->Follow.idle_count < 5000)) + { + p_Follow->FollowID = 0; + p_Follow->FollowIndex = 0; + p_Follow->DirX = s_vector_x; + p_Follow->DirY = 0; + p_Follow->DirZ = s_vector_z; + p_Follow->Autorun = 1; + s_last_run_state = true; + } + else if (s_last_run_state) + { + p_Follow->Autorun = 0; + s_last_run_state = false; + } + } + else if (s_last_run_state) + { + p_Follow->Autorun = 0; + s_last_run_state = false; } } + else if (s_last_run_state) + { + p_Follow->Autorun = 0; + s_last_run_state = false; + } } \ No newline at end of file diff --git a/src/MultiSend/Groups.cpp b/src/MultiSend/Groups.cpp index 0b97005..9888141 100644 --- a/src/MultiSend/Groups.cpp +++ b/src/MultiSend/Groups.cpp @@ -3,24 +3,64 @@ #include using namespace rapidxml; -bool MultiSend::MatchID(uint32_t ID) +bool MultiSend::CheckMatch(MMF_ICommand_Single command) { - if ((ID & 0xFFFF0000) == 0xFFFF0000) + if ((c_ignoreself) && (::GetCurrentProcessId() == command.sender_process_id)) return false; + + if (command.type == multisend_type::all) { return true; } - if ((ID & 0x8FFF0000) == 0x8FFF0000) + else if (command.type == multisend_type::others) + { + return (::GetCurrentProcessId() != command.param); + } + else if (command.type == multisend_type::group) + { + if (std::find(c_groups.begin(), c_groups.end(), command.param) != c_groups.end()) + { + return true; + } + return false; + } + else if (command.type == multisend_type::party) + { + for (int x = 0; x < 6; x++) + { + if ((m_AshitaCore->GetDataManager()->GetParty()->GetMemberActive(x)) + && (m_AshitaCore->GetDataManager()->GetParty()->GetMemberServerId(x) == command.param)) + { + return true; + } + } + return false; + } + else if (command.type == multisend_type::alliance) + { + for (int x = 0; x < 18; x++) + { + if ((m_AshitaCore->GetDataManager()->GetParty()->GetMemberActive(x)) + && (m_AshitaCore->GetDataManager()->GetParty()->GetMemberServerId(x) == command.param)) + { + return true; + } + } + return false; + } + else if (command.type == multisend_type::single) + { + return (::GetCurrentProcessId() == command.param); + } + else { - uint16_t GroupID = (ID & 0x0000FFFF); - return (std::find(Groups.begin(), Groups.end(), GroupID) != Groups.end()); + return false; } - return (::GetCurrentProcessId() == ID); } void MultiSend::LoadGroups() { - m_Group.Map.clear(); - Groups.clear(); + s_group.Map.clear(); + c_groups.clear(); string Path = m_AshitaCore->GetAshitaInstallPathA(); Path += "config\\MultiSend.xml"; @@ -30,37 +70,37 @@ void MultiSend::LoadGroups() Reader.seekg(0, ios::end); uint32_t Size = (uint32_t)Reader.tellg(); - m_Group.rawdata = new char[Size + 1]; + s_group.rawdata = new char[Size + 1]; Reader.seekg(0, ios::beg); - Reader.read(m_Group.rawdata, Size); + Reader.read(s_group.rawdata, Size); Reader.close(); - m_Group.rawdata[Size] = '\0'; + s_group.rawdata[Size] = '\0'; try { - m_Group.doc.parse<0>(m_Group.rawdata); + s_group.doc.parse<0>(s_group.rawdata); m_AshitaCore->GetChatManager()->Write("MultiSend: Groups loaded."); - m_Group.Loaded = true; + s_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; + s_group.doc.clear(); + s_group.Loaded = false; + delete s_group.rawdata; } } else { - if (m_Group.Loaded) + if (s_group.Loaded) { - m_Group.doc.clear(); - delete m_Group.rawdata; - m_Group.Loaded = false; + s_group.doc.clear(); + delete s_group.rawdata; + s_group.Loaded = false; } m_AshitaCore->GetChatManager()->Write("MultiSend: No groups file found."); } - if (m_Group.Loaded) + if (s_group.Loaded) { ReadXML(); MatchGroups(); @@ -69,9 +109,9 @@ void MultiSend::LoadGroups() void MultiSend::ReadXML() { - m_Group.Map.clear(); + s_group.Map.clear(); - xml_node<> *Node = m_Group.doc.first_node(); + xml_node<> *Node = s_group.doc.first_node(); if (_stricmp(Node->name(), "multisend") == 0) Node = Node->first_node(); while (Node) { @@ -83,7 +123,7 @@ void MultiSend::ReadXML() 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()))); + s_group.Map.insert(std::make_pair((uint16_t)atoi(Attr->value()), std::string(Attr2->value()))); } } } @@ -93,11 +133,11 @@ void MultiSend::ReadXML() void MultiSend::MatchGroups() { - Groups.clear(); - if (CurrentName.length() < 3) return; - if (!m_Group.Loaded) return; + c_groups.clear(); + if (s_name.length() < 3) return; + if (!s_group.Loaded) return; - xml_node<> *Node = m_Group.doc.first_node(); + xml_node<> *Node = s_group.doc.first_node(); if (_stricmp(Node->name(), "multisend") == 0) Node = Node->first_node(); while (Node) { @@ -112,9 +152,9 @@ void MultiSend::MatchGroups() 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) + if (_stricmp(s_name.c_str(), SubNode->value()) == 0) { - Groups.push_back(Index); + c_groups.push_back(Index); break; } } diff --git a/src/MultiSend/IO.cpp b/src/MultiSend/IO.cpp index af97ebf..3c84610 100644 --- a/src/MultiSend/IO.cpp +++ b/src/MultiSend/IO.cpp @@ -2,137 +2,115 @@ bool MultiSend::ReadCommand() { - if (MMF_Pointer->Command.Command[Position].Active) + if (p_MMF->Command.Command[s_position].active) { - if (MatchID(MMF_Pointer->Command.Command[Position].Targets)) + if (CheckMatch(p_MMF->Command.Command[s_position])) { - if ((!IgnoreSelf) - || (GetCurrentProcessId() != MMF_Pointer->Command.Command[Position].SendProcess)) + const char* text = new char[248]; + memcpy((void*)text, &(p_MMF->Command.Command[s_position].command), 248); + if (c_debug) { - 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); - } - if (m_AshitaCore->GetPluginManager()->GetPlugin("Shorthand")) - { - m_AshitaCore->GetChatManager()->QueueCommand(text, -1); - } - else - { - m_AshitaCore->GetChatManager()->QueueCommand(text, 0); - } - delete text; + m_AshitaCore->GetChatManager()->Writef("Sending command: %s", text); } + if (m_AshitaCore->GetPluginManager()->GetPlugin("Shorthand")) + { + m_AshitaCore->GetChatManager()->QueueCommand(text, -1); + } + else + { + m_AshitaCore->GetChatManager()->QueueCommand(text, 0); + } + delete text; } - Position++; - if (Position == 100) Position = 0; + s_position++; + if (s_position == 100) s_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) +void MultiSend::SendCommand(multisend_type type, uint32_t param, const char* Command) { char* Text = new char[248]; memset((void*)Text, 0, 248); memcpy(Text, Command, strlen(Command)); - if (_SafeMode) + if (c_safemode) SanitizeCommand(Text); SubValues(Text); - Claim(&(MMF_Pointer->Command.ProcessID), 0); + Claim(&(p_MMF->Command.ProcessID), 0); - int NextPosition = MMF_Pointer->Command.Position + 1; + int NextPosition = p_MMF->Command.Position + 1; if (NextPosition == 100) NextPosition = 0; - MMF_Pointer->Command.Command[NextPosition].Active = false; + p_MMF->Command.Command[NextPosition].active = false; - memset(&(MMF_Pointer->Command.Command[MMF_Pointer->Command.Position].Command), 0, 248); + memset(&(p_MMF->Command.Command[p_MMF->Command.Position].command), 0, 248); if (strlen(Text) > 247) { - memcpy(&(MMF_Pointer->Command.Command[MMF_Pointer->Command.Position].Command), Text, 247); + memcpy(&(p_MMF->Command.Command[p_MMF->Command.Position].command), Text, 247); } else { - memcpy(&(MMF_Pointer->Command.Command[MMF_Pointer->Command.Position].Command), Text, strlen(Text)); + memcpy(&(p_MMF->Command.Command[p_MMF->Command.Position].command), Text, strlen(Text)); } - if (_Debug) + if (c_debug) { - m_AshitaCore->GetChatManager()->Writef("Publishing position %d : %s", MMF_Pointer->Command.Position, Text); + m_AshitaCore->GetChatManager()->Writef("Publishing position %d : %s", p_MMF->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); + p_MMF->Command.Command[p_MMF->Command.Position].sender_process_id = GetCurrentProcessId(); + p_MMF->Command.Command[p_MMF->Command.Position].type = type; + p_MMF->Command.Command[p_MMF->Command.Position].param = param; + p_MMF->Command.Command[p_MMF->Command.Position].active = true; + p_MMF->Command.Position = NextPosition; + InterlockedExchange(&(p_MMF->Command.ProcessID), 0); delete Text; } void MultiSend::UpdateName(std::string Name) { - Claim(&(MMF_Pointer->Name.ProcessID), 0xFFFF0000); + Claim(&(p_MMF->Name.ProcessID), 0xFFFF0000); bool Written = false; for (int x = 0; x < 100; x++) { - if (!MMF_Pointer->Name.Names[x].Active) + if (!p_MMF->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; + memcpy(&(p_MMF->Name.Names[x].Name), Name.c_str(), strlen(Name.c_str()) + 1); + p_MMF->Name.Names[x].Process = GetCurrentProcessId(); + p_MMF->Name.Names[x].Active = 1; Written = true; } continue; } - else if (MMF_Pointer->Name.Names[x].Process == GetCurrentProcessId()) + else if (p_MMF->Name.Names[x].Process == GetCurrentProcessId()) { - memset(&(MMF_Pointer->Name.Names[x]), 0, sizeof(MMF_Name_Single)); + memset(&(p_MMF->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; + memcpy(&(p_MMF->Name.Names[x].Name), Name.c_str(), strlen(Name.c_str()) + 1); + p_MMF->Name.Names[x].Process = GetCurrentProcessId(); + p_MMF->Name.Names[x].Active = 1; Written = true; } } - else if (strcmp((const char*)&(MMF_Pointer->Name.Names[x].Name), Name.c_str()) == 0) + else if (strcmp((const char*)&(p_MMF->Name.Names[x].Name), Name.c_str()) == 0) { - memset(&(MMF_Pointer->Name.Names[x]), 0, sizeof(MMF_Name_Single)); + memset(&(p_MMF->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; + memcpy(&(p_MMF->Name.Names[x].Name), Name.c_str(), strlen(Name.c_str()) + 1); + p_MMF->Name.Names[x].Process = GetCurrentProcessId(); + p_MMF->Name.Names[x].Active = 1; Written = true; } } } - CurrentName = Name; + s_name = Name; MatchGroups(); - InterlockedExchange(&(MMF_Pointer->Name.ProcessID), 0); + InterlockedExchange(&(p_MMF->Name.ProcessID), 0); } void MultiSend::Claim(uint32_t* Target, uint32_t Mod) diff --git a/src/MultiSend/Main.cpp b/src/MultiSend/Main.cpp index d814b82..38a240f 100644 --- a/src/MultiSend/Main.cpp +++ b/src/MultiSend/Main.cpp @@ -27,27 +27,16 @@ bool MultiSend::Initialize(IAshitaCore* core, ILogManager* log, uint32_t id) LoadGroups(); DWORD Pointer = NULL; + MODULEINFO mod = { 0 }; + if (!::GetModuleInformation(::GetCurrentProcess(), ::GetModuleHandle("FFXiMain.dll"), &mod, sizeof(MODULEINFO))) + return false; - Pointers* p = (Pointers*)m_AshitaCore->GetPluginManager()->GetPlugin("Pointers"); - if (p) - { - Pointer = p->RegisterPointer("movement", "8BCFE8????FFFF8B0D????????E8????????8BE885ED750CB9", 0, 0); - } - else - { - MODULEINFO mod = { 0 }; - if (!::GetModuleInformation(::GetCurrentProcess(), ::GetModuleHandle("FFXiMain.dll"), &mod, sizeof(MODULEINFO))) - return false; - - Pointer = Ashita::Memory::FindPattern((uintptr_t)mod.lpBaseOfDll, (uintptr_t)mod.SizeOfImage, - "8BCFE8????FFFF8B0D????????E8????????8BE885ED750CB9", - 0, 0); - } - + Pointer = 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)); + p_Follow = (sFollow*)(*((DWORD*)Pointer)); //create a handle to the MMF, size matches the struct we're using for it HANDLE hMapFile = CreateFileMapping( @@ -56,7 +45,7 @@ bool MultiSend::Initialize(IAshitaCore* core, ILogManager* log, uint32_t id) PAGE_READWRITE, 0, // maximum object size (high-order DWORD) sizeof(MMF_Global), // maximum object size (low-order DWORD) - "FFXI_MultiSend"); + "FFXI_MultiSend_1_15"); bool made = (GetLastError() == 0); @@ -66,12 +55,12 @@ bool MultiSend::Initialize(IAshitaCore* core, ILogManager* log, uint32_t id) } - MMF_Pointer = (MMF_Global*)MapViewOfFile(hMapFile, // handle to map object + p_MMF = (MMF_Global*)MapViewOfFile(hMapFile, // handle to map object FILE_MAP_ALL_ACCESS, // read/write permission 0, 0, sizeof(MMF_Global)); - if (MMF_Pointer == NULL) + if (p_MMF == NULL) { CloseHandle(hMapFile); throw exception("Could not map MMF."); @@ -79,25 +68,25 @@ bool MultiSend::Initialize(IAshitaCore* core, ILogManager* log, uint32_t id) if (made) { - memset(MMF_Pointer, 0, sizeof(MMF_Global)); + memset(p_MMF, 0, sizeof(MMF_Global)); } - Position = MMF_Pointer->Command.Position; - - FollowEnabled = true; - ZoneExtra = false; - IgnoreSelf = false; - CurrentName = ""; + s_last_run_state = false; + s_position = p_MMF->Command.Position; + s_name = ""; 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; - //SafeMode enabled by Default (to avoid accidental chatlog spam): - //Allows for prepend of "/echo " to commands that are missing a leading "/". - _SafeMode = false; + //Default settings. + c_follow = true; + c_ignoreself = false; + c_attemptzone = false; + c_debug = false; + c_safemode = false; + c_maxdist = 5000.0f; this->Start(); @@ -107,9 +96,9 @@ bool MultiSend::Initialize(IAshitaCore* core, ILogManager* log, uint32_t id) void MultiSend::Release(void) { this->Stop(); - if (MMF_Pointer) + if (p_MMF) { - UnmapViewOfFile((LPCVOID)MMF_Pointer); + UnmapViewOfFile((LPCVOID)p_MMF); } if (hMapFile) { @@ -130,7 +119,7 @@ __declspec(dllexport) void __stdcall CreatePluginInfo(plugininfo_t* lpBuffer) strcpy_s(g_PluginInfo->Author, sizeof(g_PluginInfo->Author), "Thorny"); g_PluginInfo->InterfaceVersion = ASHITA_INTERFACE_VERSION; - g_PluginInfo->PluginVersion = 1.05f; + g_PluginInfo->PluginVersion = 1.15f; g_PluginInfo->Priority = 0; } diff --git a/src/MultiSend/MultiSend.h b/src/MultiSend/MultiSend.h index ad673d3..fbbc719 100644 --- a/src/MultiSend/MultiSend.h +++ b/src/MultiSend/MultiSend.h @@ -6,7 +6,7 @@ #endif #define SAFE_DELETE(p) if(p) { delete p; p = NULL; } -#include "C:\Ashita 3\Plugins\ADK\Ashita.h" +#include "C:\Program Files (x86)\Ashita 3\Plugins\ADK\Ashita.h" #include "Structs.h" #include "..\..\..\pluginheaders\Utilities.h" #include "..\..\..\pluginheaders\Pointers.h" @@ -50,28 +50,28 @@ class MultiSend : IPlugin, Ashita::Threading::AS_Thread ILogManager* m_LogManager; DWORD m_PluginId; IDirect3DDevice8* m_Direct3DDevice; - sFollow* StructPointer; - GroupData m_Group; + //References 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; - volatile bool _SafeMode; + sFollow* p_Follow; + MMF_Global* p_MMF; + + //State tracking + GroupData s_group; + std::string s_name; + uint32_t s_position; + bool s_last_run_state; + float s_vector_x; + float s_vector_z; + + //Configuration + std::list c_groups; + float c_maxdist; + volatile bool c_follow; + volatile bool c_attemptzone; + volatile bool c_ignoreself; + volatile bool c_debug; + volatile bool c_safemode; public: MultiSend(void); @@ -89,10 +89,9 @@ public: bool HandleCommand(const char* command, int32_t type); uint32_t ThreadEntry(void) override; - bool MatchID(uint32_t ID); + bool CheckMatch(MMF_ICommand_Single command); bool ReadCommand(); - void SetFollow(bool Active); - void SendCommand(uint32_t ID, const char* Command); + void SendCommand(multisend_type type, uint32_t param, const char* Command); void SanitizeCommand(char* Input); std::string SubValues(std::string Input); void SubValues(char* Input); diff --git a/src/MultiSend/MultiSend.vcxproj b/src/MultiSend/MultiSend.vcxproj index e427e45..236b888 100644 --- a/src/MultiSend/MultiSend.vcxproj +++ b/src/MultiSend/MultiSend.vcxproj @@ -21,31 +21,32 @@ {3C74E1A4-E44B-4523-85DC-9A94AC2D6457} MultiSend + 7.0 Application true - v140 + v142 MultiByte DynamicLibrary false - v140_xp + v141_xp true MultiByte Application true - v140 + v142 MultiByte DynamicLibrary false - v140_xp + v141_xp true MultiByte @@ -68,7 +69,7 @@ - ..\..\bin\ + ..\..\..\bin\ ..\..\bin\ @@ -110,7 +111,8 @@ Exports.def - copy "..\..\bin\MultiSend.dll" "C:\Ashita 3\plugins\MultiSend.dll" + copy "..\..\..\bin\MultiSend.dll" "C:\Program Files (x86)\Ashita 3\plugins\MultiSend.dll" +copy "..\..\..\bin\MultiSend.dll" "..\..\release\plugins\MultiSend.dll" @@ -140,12 +142,12 @@ - + - - - - + + + + diff --git a/src/MultiSend/MultiSend.vcxproj.filters b/src/MultiSend/MultiSend.vcxproj.filters index 10142f1..7dc401b 100644 --- a/src/MultiSend/MultiSend.vcxproj.filters +++ b/src/MultiSend/MultiSend.vcxproj.filters @@ -23,28 +23,28 @@ - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files diff --git a/src/MultiSend/Structs.h b/src/MultiSend/Structs.h index 47f8aa1..f314b80 100644 --- a/src/MultiSend/Structs.h +++ b/src/MultiSend/Structs.h @@ -3,6 +3,16 @@ #include +enum multisend_type +{ + all, //Param irrelevant + others, //Param = sender's process ID + alliance, //Param = sender's server id + party, //Param = sender's server id + group, //Param = group id + single //Param = process id of target +}; + struct MMF_Name_Single { uint32_t Process; @@ -18,10 +28,11 @@ struct MMF_Name struct MMF_ICommand_Single { - uint8_t Active; - uint32_t Targets; - uint32_t SendProcess; - uint8_t Command[248]; + uint8_t active; + multisend_type type; + uint32_t param; + uint32_t sender_process_id; + uint8_t command[248]; }; struct MMF_ICommand @@ -33,11 +44,12 @@ struct MMF_ICommand struct MMF_IFollow { - uint16_t Zone; - uint32_t FollowID; - uint32_t Follow; - int32_t PosX; - int32_t PosZ; + uint32_t target_process_id; + uint16_t lastzone; + uint16_t zone; + float position_x; + float position_z; + uint32_t idle_count; }; struct MMF_Global diff --git a/src/MultiSend/Thread.cpp b/src/MultiSend/Thread.cpp index 46b612b..9727ef3 100644 --- a/src/MultiSend/Thread.cpp +++ b/src/MultiSend/Thread.cpp @@ -4,76 +4,38 @@ uint32_t MultiSend::ThreadEntry(void) { while (!this->IsTerminated()) { - if (m_AshitaCore->GetDataManager()->GetParty()->GetMemberActive(0)) + if (p_MMF->Follow.target_process_id == GetCurrentProcessId()) { - if (Zoning == 2) Zoning = 0; - } - else if (Zoning == 1) - { - Zoning = 2; - } - - if (MMF_Pointer->Follow.Follow) - { - if (((MMF_Global*)MMF_Pointer)->Follow.FollowID == GetCurrentProcessId()) + uint16_t zone = m_AshitaCore->GetDataManager()->GetParty()->GetMemberZone(0); + uint16_t myindex = m_AshitaCore->GetDataManager()->GetParty()->GetMemberTargetIndex(0); + uint32_t renderflags = m_AshitaCore->GetDataManager()->GetEntity()->GetRenderFlags0(myindex); + bool isrendered = (((renderflags & 0x200) != 0) && ((renderflags & 0x4000) == 0)); + float my_pos_x = m_AshitaCore->GetDataManager()->GetEntity()->GetLocalX(myindex); + float my_pos_z = m_AshitaCore->GetDataManager()->GetEntity()->GetLocalZ(myindex); + if ((zone == 0) || (myindex == 0) || (!isrendered)) { - 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 + if (p_MMF->Follow.zone != 0) { - Following = false; - MMF_Pointer->Follow.Follow = 2; + p_MMF->Follow.lastzone = p_MMF->Follow.zone; } + p_MMF->Follow.zone = 0; } - else if (MMF_Pointer->Follow.Follow != 3) + else { - if (m_AshitaCore->GetDataManager()->GetParty()->GetMemberActive(0)) + if (p_MMF->Follow.zone == 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; - } + p_MMF->Follow.idle_count = 0; } + else if ((my_pos_x != p_MMF->Follow.position_x) || (my_pos_z != p_MMF->Follow.position_z)) + { + p_MMF->Follow.idle_count = 0; + } + else p_MMF->Follow.idle_count++; + + p_MMF->Follow.zone = zone; + p_MMF->Follow.position_x = my_pos_x; + p_MMF->Follow.position_z = my_pos_z; } - else - { - if (Following) StopFollow = true; - Following = false; - } - } - else - { - if (Following) StopFollow = true; - Following = false; } while (ReadCommand()) {} diff --git a/src/MultiSend/packets.cpp b/src/MultiSend/packets.cpp new file mode 100644 index 0000000..cace76c --- /dev/null +++ b/src/MultiSend/packets.cpp @@ -0,0 +1,25 @@ +#include "MultiSend.h" + + +bool MultiSend::HandleIncomingPacket(uint16_t id, uint32_t size, void* data, void* modified, bool blocked) +{ + if (id == 0x00A) + { + if (strcmp(s_name.c_str(), (const char*)data + 0x84)) + { + UpdateName(std::string((const char*)data + 0x84)); + } + } + if ((id == 0x32) || (id == 0x34)) + { + if (p_MMF->Follow.target_process_id == ::GetCurrentProcessId()) + { + if (p_MMF->Follow.idle_count < 5000) + { + p_MMF->Follow.idle_count = 5000; + } + } + } + + return false; +} \ No newline at end of file diff --git a/src/MultiSend/text_sanitizing.cpp b/src/MultiSend/text_sanitizing.cpp new file mode 100644 index 0000000..c06af60 --- /dev/null +++ b/src/MultiSend/text_sanitizing.cpp @@ -0,0 +1,87 @@ +#include "MultiSend.h" + +std::string MultiSend::SubValues(std::string 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))); + } + return Working; +} + +void MultiSend::SubValues(char* Input) +{ + std::string Working = SubValues(std::string(Input)); + const char* base = Working.c_str(); + memset(Input, 0, 248); + memcpy(Input, base, strlen(base)); +} + +void MultiSend::SanitizeCommand(char* Input) +{ + if (Input[0] != '/') + { + if (c_debug) + m_AshitaCore->GetChatManager()->Write("Detected command without leading '/'. Prepending '/echo'..."); + char* prepend = "/echo "; + size_t plen = strlen(prepend); + memmove(Input + plen, Input, strlen(Input) + 1); + memcpy(Input, prepend, strlen(prepend)); + } + else + { + if (c_debug) + m_AshitaCore->GetChatManager()->Write("No Sanitization Needed."); + } + +}