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 e8dd582..561286c 100644 Binary files a/release/plugins/MultiSend.dll and b/release/plugins/MultiSend.dll differ diff --git a/src/MultiSend/Commands.cpp b/src/MultiSend/Commands.cpp index 36122a0..1cb4a14 100644 --- a/src/MultiSend/Commands.cpp +++ b/src/MultiSend/Commands.cpp @@ -21,9 +21,8 @@ bool MultiSend::HandleCommand(const char* command, int32_t type) if ((_stricmp(arg.c_str(), "send") == 0) || (_stricmp(arg.c_str(), "/mss") == 0)) { - if (strlen(com) < 2) return true; - SendCommand(0xFFFF0000, com + 1); + SendCommand(multisend_type::all, 0, com + 1); return true; } @@ -40,25 +39,49 @@ bool MultiSend::HandleCommand(const char* command, int32_t type) arg = SubValues(arg); - Claim(&(MMF_Pointer->Name.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."); + } + +}