Browse Source

1.15 - Rewrote follow system, new features added, see documentation for usage.

master
Thorny 5 years ago
parent
commit
ed2ab118af
  1. 5
      .gitignore
  2. 31
      release/docs/MultiSend.txt
  3. BIN
      release/plugins/MultiSend.dll
  4. 160
      src/MultiSend/Commands.cpp
  5. 71
      src/MultiSend/Follow.cpp
  6. 100
      src/MultiSend/Groups.cpp
  7. 100
      src/MultiSend/IO.cpp
  8. 47
      src/MultiSend/Main.cpp
  9. 47
      src/MultiSend/MultiSend.h
  10. 24
      src/MultiSend/MultiSend.vcxproj
  11. 16
      src/MultiSend/MultiSend.vcxproj.filters
  12. 30
      src/MultiSend/Structs.h
  13. 78
      src/MultiSend/Thread.cpp
  14. 25
      src/MultiSend/packets.cpp
  15. 87
      src/MultiSend/text_sanitizing.cpp

5
.gitignore vendored

@ -1,3 +1,2 @@
*.vs/* src/.vs/
*ipch/* src/MultiSend/Release/
*src*Release/*

31
release/docs/MultiSend.txt

@ -1,13 +1,32 @@
Multisend is a replacement for servo. No synchronization is needed, just load and go. 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 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 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 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 sendothers [command] - Sends a command to all characters except for the current character.
/ms follow on/off - Enables or disables follow. Any character with follow enabled with follow the player who last activated followme. /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 ignoreself on/off - When enabled, any command that would effect the local character is not executed by the local character. /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.
/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.
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 reload - Will reload groups xml.
/ms help - Print an ingame reference. /ms help - Print an ingame reference.

BIN
release/plugins/MultiSend.dll

Binary file not shown.

160
src/MultiSend/Commands.cpp

@ -21,9 +21,8 @@ bool MultiSend::HandleCommand(const char* command, int32_t type)
if ((_stricmp(arg.c_str(), "send") == 0) if ((_stricmp(arg.c_str(), "send") == 0)
|| (_stricmp(arg.c_str(), "/mss") == 0)) || (_stricmp(arg.c_str(), "/mss") == 0))
{ {
if (strlen(com) < 2) return true; if (strlen(com) < 2) return true;
SendCommand(0xFFFF0000, com + 1); SendCommand(multisend_type::all, 0, com + 1);
return true; return true;
} }
@ -40,25 +39,49 @@ bool MultiSend::HandleCommand(const char* command, int32_t type)
arg = SubValues(arg); arg = SubValues(arg);
Claim(&(MMF_Pointer->Name.ProcessID), 0); Claim(&(p_MMF->Name.ProcessID), 0);
for (int x = 0; x < 100; x++) 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); SendCommand(multisend_type::single, p_MMF->Name.Names[x].Process, com + 1);
InterlockedExchange(&(MMF_Pointer->Name.ProcessID), 0); InterlockedExchange(&(p_MMF->Name.ProcessID), 0);
return true; return true;
} }
} }
} }
InterlockedExchange(&(MMF_Pointer->Name.ProcessID), 0); InterlockedExchange(&(p_MMF->Name.ProcessID), 0);
m_AshitaCore->GetChatManager()->Write("MultiSend: Character not found."); m_AshitaCore->GetChatManager()->Write("MultiSend: Character not found.");
return true; 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) else if ((_stricmp(arg.c_str(), "sendgroup") == 0)
|| (_stricmp(arg.c_str(), "/msg") == 0)) || (_stricmp(arg.c_str(), "/msg") == 0))
{ {
@ -70,11 +93,11 @@ bool MultiSend::HandleCommand(const char* command, int32_t type)
com++; com++;
com += GetArg(com, &arg); com += GetArg(com, &arg);
for (std::map<uint16_t, string>::iterator it = m_Group.Map.begin(); it != m_Group.Map.end(); it++) for (std::map<uint16_t, string>::iterator it = s_group.Map.begin(); it != s_group.Map.end(); it++)
{ {
if (_stricmp((*it).second.c_str(), arg.c_str()) == 0) 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; return true;
} }
} }
@ -89,43 +112,76 @@ bool MultiSend::HandleCommand(const char* command, int32_t type)
com++; com++;
com += GetArg(com, &arg); 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;
InterlockedExchange(&(MMF_Pointer->Follow.FollowID), GetCurrentProcessId()); else if (_stricmp(arg.c_str(), "off") == 0) toggle = false;
if (!Zoning)
if (toggle)
{ {
Following = false; 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); uint16_t myindex = m_AshitaCore->GetDataManager()->GetParty()->GetMemberTargetIndex(0);
uint32_t mPosX = (uint32_t)floor(m_AshitaCore->GetDataManager()->GetEntity()->GetLocalX(myindex) * 100); if ((zone != 0) && (myindex != 0))
uint32_t mPosZ = (uint32_t)floor(m_AshitaCore->GetDataManager()->GetEntity()->GetLocalZ(myindex) * 100); {
MMF_Pointer->Follow.PosX = mPosX; p_MMF->Follow.zone = zone;
MMF_Pointer->Follow.PosZ = mPosZ; p_MMF->Follow.position_x = m_AshitaCore->GetDataManager()->GetEntity()->GetLocalX(myindex);
MMF_Pointer->Follow.Follow = 1; p_MMF->Follow.position_z = m_AshitaCore->GetDataManager()->GetEntity()->GetLocalZ(myindex);
p_MMF->Follow.idle_count = 0;
}
else
{
p_MMF->Follow.zone = 0;
}
} }
else else
{ {
Following = false; p_MMF->Follow.zone = 0;
MMF_Pointer->Follow.Follow = 3; InterlockedExchange(&(p_MMF->Follow.target_process_id), 0);
} }
m_AshitaCore->GetChatManager()->Write("MultiSend: Followme enabled.");
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(), "off") == 0) else if (_stricmp(arg.c_str(), "followmax") == 0)
{ {
InterlockedExchange(&(MMF_Pointer->Follow.FollowID), 0); if (strlen(com) < 2) return true;
MMF_Pointer->Follow.Follow = 0; com++;
m_AshitaCore->GetChatManager()->Write("MultiSend: Followme disabled."); 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)
{
c_follow = false;
}
else 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; return true;
} }
else if (_stricmp(arg.c_str(), "follow") == 0) else if (_stricmp(arg.c_str(), "attemptzone") == 0)
{ {
if (strlen(com) < 2) return true; if (strlen(com) < 2) return true;
com++; com++;
@ -133,21 +189,18 @@ bool MultiSend::HandleCommand(const char* command, int32_t type)
if (_stricmp(arg.c_str(), "on") == 0) if (_stricmp(arg.c_str(), "on") == 0)
{ {
FollowEnabled = true; c_attemptzone = 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) else if (_stricmp(arg.c_str(), "off") == 0)
{ {
FollowEnabled = false; c_attemptzone = false;
m_AshitaCore->GetChatManager()->Write("MultiSend: Follow disabled.");
} }
else 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; return true;
} }
@ -159,20 +212,18 @@ bool MultiSend::HandleCommand(const char* command, int32_t type)
if (_stricmp(arg.c_str(), "on") == 0) if (_stricmp(arg.c_str(), "on") == 0)
{ {
IgnoreSelf = true; c_ignoreself = true;
m_AshitaCore->GetChatManager()->Write("MultiSend: Now ignoring self-published commands.");
} }
else if (_stricmp(arg.c_str(), "off") == 0) else if (_stricmp(arg.c_str(), "off") == 0)
{ {
IgnoreSelf = false; c_ignoreself = false;
m_AshitaCore->GetChatManager()->Write("MultiSend: Now accepting self-published commands.");
} }
else 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; return true;
} }
@ -184,21 +235,18 @@ bool MultiSend::HandleCommand(const char* command, int32_t type)
if (_stricmp(arg.c_str(), "on") == 0) if (_stricmp(arg.c_str(), "on") == 0)
{ {
_Debug = true; c_debug = true;
m_AshitaCore->GetChatManager()->Write("MultiSend: Debug prints enabled.");
} }
else if (_stricmp(arg.c_str(), "off") == 0) else if (_stricmp(arg.c_str(), "off") == 0)
{ {
_Debug = false; c_debug = false;
m_AshitaCore->GetChatManager()->Write("MultiSend: Debug prints disabled.");
} }
else 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; return true;
} }
@ -210,21 +258,18 @@ bool MultiSend::HandleCommand(const char* command, int32_t type)
if (_stricmp(arg.c_str(), "on") == 0) if (_stricmp(arg.c_str(), "on") == 0)
{ {
_SafeMode = true; c_safemode = true;
m_AshitaCore->GetChatManager()->Write("MultiSend: Safe mode enabled.");
} }
else if (_stricmp(arg.c_str(), "off") == 0) else if (_stricmp(arg.c_str(), "off") == 0)
{ {
_SafeMode = false; c_safemode = false;
m_AshitaCore->GetChatManager()->Write("MultiSend: Safe mode disabled.");
} }
else 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; 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 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 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 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 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."); 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; return true;

71
src/MultiSend/Follow.cpp

@ -13,31 +13,72 @@ bool MultiSend::Direct3DInitialize(IDirect3DDevice8* lpDevice)
*/ */
void MultiSend::Direct3DPreRender(void) 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); uint16_t myindex = m_AshitaCore->GetDataManager()->GetParty()->GetMemberTargetIndex(0);
float MyX = m_AshitaCore->GetDataManager()->GetEntity()->GetLocalX(myindex); float my_pos_x = m_AshitaCore->GetDataManager()->GetEntity()->GetLocalX(myindex);
float MyZ = m_AshitaCore->GetDataManager()->GetEntity()->GetLocalZ(myindex); float my_pos_z = m_AshitaCore->GetDataManager()->GetEntity()->GetLocalZ(myindex);
double Distance = sqrt(pow(PositionX - MyX, 2) + pow(PositionZ - MyZ, 2)); 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; p_Follow->FollowID = 0;
StructPointer->DirY = 0; p_Follow->FollowIndex = 0;
StructPointer->DirZ = PositionZ - MyZ; p_Follow->DirX = s_vector_x;
StructPointer->Autorun = 1; 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)
{
if ((c_attemptzone)
&& (p_MMF->Follow.lastzone == m_AshitaCore->GetDataManager()->GetParty()->GetMemberZone(0))
&& (p_MMF->Follow.idle_count < 5000))
{ {
StructPointer->Autorun = 0; p_Follow->FollowID = 0;
StopFollow = false; 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;
} }
} }

100
src/MultiSend/Groups.cpp

@ -3,24 +3,64 @@
#include <iostream> #include <iostream>
using namespace rapidxml; 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;
}
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 true;
} }
if ((ID & 0x8FFF0000) == 0x8FFF0000) }
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 false;
return (std::find(Groups.begin(), Groups.end(), GroupID) != Groups.end());
} }
return (::GetCurrentProcessId() == ID);
} }
void MultiSend::LoadGroups() void MultiSend::LoadGroups()
{ {
m_Group.Map.clear(); s_group.Map.clear();
Groups.clear(); c_groups.clear();
string Path = m_AshitaCore->GetAshitaInstallPathA(); string Path = m_AshitaCore->GetAshitaInstallPathA();
Path += "config\\MultiSend.xml"; Path += "config\\MultiSend.xml";
@ -30,37 +70,37 @@ void MultiSend::LoadGroups()
Reader.seekg(0, ios::end); Reader.seekg(0, ios::end);
uint32_t Size = (uint32_t)Reader.tellg(); 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.seekg(0, ios::beg);
Reader.read(m_Group.rawdata, Size); Reader.read(s_group.rawdata, Size);
Reader.close(); Reader.close();
m_Group.rawdata[Size] = '\0'; s_group.rawdata[Size] = '\0';
try 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_AshitaCore->GetChatManager()->Write("MultiSend: Groups loaded.");
m_Group.Loaded = true; s_group.Loaded = true;
} }
catch (...) catch (...)
{ {
m_AshitaCore->GetChatManager()->Write("MultiSend: Groups failed to parse."); m_AshitaCore->GetChatManager()->Write("MultiSend: Groups failed to parse.");
m_Group.doc.clear(); s_group.doc.clear();
m_Group.Loaded = false; s_group.Loaded = false;
delete m_Group.rawdata; delete s_group.rawdata;
} }
} }
else else
{ {
if (m_Group.Loaded) if (s_group.Loaded)
{ {
m_Group.doc.clear(); s_group.doc.clear();
delete m_Group.rawdata; delete s_group.rawdata;
m_Group.Loaded = false; s_group.Loaded = false;
} }
m_AshitaCore->GetChatManager()->Write("MultiSend: No groups file found."); m_AshitaCore->GetChatManager()->Write("MultiSend: No groups file found.");
} }
if (m_Group.Loaded) if (s_group.Loaded)
{ {
ReadXML(); ReadXML();
MatchGroups(); MatchGroups();
@ -69,9 +109,9 @@ void MultiSend::LoadGroups()
void MultiSend::ReadXML() 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(); if (_stricmp(Node->name(), "multisend") == 0) Node = Node->first_node();
while (Node) while (Node)
{ {
@ -83,7 +123,7 @@ void MultiSend::ReadXML()
xml_attribute<> *Attr2 = Node->first_attribute("name"); xml_attribute<> *Attr2 = Node->first_attribute("name");
if (Attr2) 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() void MultiSend::MatchGroups()
{ {
Groups.clear(); c_groups.clear();
if (CurrentName.length() < 3) return; if (s_name.length() < 3) return;
if (!m_Group.Loaded) 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(); if (_stricmp(Node->name(), "multisend") == 0) Node = Node->first_node();
while (Node) while (Node)
{ {
@ -112,9 +152,9 @@ void MultiSend::MatchGroups()
uint16_t Index = (uint16_t)atoi(Attr->value()); uint16_t Index = (uint16_t)atoi(Attr->value());
for (xml_node<> *SubNode = Node->first_node("char"); SubNode != NULL; SubNode = SubNode->next_sibling("char")) 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; break;
} }
} }

100
src/MultiSend/IO.cpp

@ -2,17 +2,13 @@
bool MultiSend::ReadCommand() 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]; const char* text = new char[248];
memset((void*)text, 0, 248); memcpy((void*)text, &(p_MMF->Command.Command[s_position].command), 248);
memcpy((void*)text, &(MMF_Pointer->Command.Command[Position].Command), 248); if (c_debug)
if (_Debug)
{ {
m_AshitaCore->GetChatManager()->Writef("Sending command: %s", text); m_AshitaCore->GetChatManager()->Writef("Sending command: %s", text);
} }
@ -26,113 +22,95 @@ bool MultiSend::ReadCommand()
} }
delete text; delete text;
} }
} s_position++;
Position++; if (s_position == 100) s_position = 0;
if (Position == 100) Position = 0;
return true; return true;
} }
return false; return false;
} }
void MultiSend::SetFollow(bool Active) void MultiSend::SendCommand(multisend_type type, uint32_t param, const char* Command)
{
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]; char* Text = new char[248];
memset((void*)Text, 0, 248); memset((void*)Text, 0, 248);
memcpy(Text, Command, strlen(Command)); memcpy(Text, Command, strlen(Command));
if (_SafeMode) if (c_safemode)
SanitizeCommand(Text); SanitizeCommand(Text);
SubValues(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; 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) 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 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(); p_MMF->Command.Command[p_MMF->Command.Position].sender_process_id = GetCurrentProcessId();
MMF_Pointer->Command.Command[MMF_Pointer->Command.Position].Targets = ID; p_MMF->Command.Command[p_MMF->Command.Position].type = type;
MMF_Pointer->Command.Command[MMF_Pointer->Command.Position].Active = true; p_MMF->Command.Command[p_MMF->Command.Position].param = param;
MMF_Pointer->Command.Position = NextPosition; p_MMF->Command.Command[p_MMF->Command.Position].active = true;
InterlockedExchange(&(MMF_Pointer->Command.ProcessID), 0); p_MMF->Command.Position = NextPosition;
InterlockedExchange(&(p_MMF->Command.ProcessID), 0);
delete Text; delete Text;
} }
void MultiSend::UpdateName(std::string Name) void MultiSend::UpdateName(std::string Name)
{ {
Claim(&(MMF_Pointer->Name.ProcessID), 0xFFFF0000); Claim(&(p_MMF->Name.ProcessID), 0xFFFF0000);
bool Written = false; bool Written = false;
for (int x = 0; x < 100; x++) for (int x = 0; x < 100; x++)
{ {
if (!MMF_Pointer->Name.Names[x].Active) if (!p_MMF->Name.Names[x].Active)
{ {
if (!Written) if (!Written)
{ {
memcpy(&(MMF_Pointer->Name.Names[x].Name), Name.c_str(), strlen(Name.c_str()) + 1); memcpy(&(p_MMF->Name.Names[x].Name), Name.c_str(), strlen(Name.c_str()) + 1);
MMF_Pointer->Name.Names[x].Process = GetCurrentProcessId(); p_MMF->Name.Names[x].Process = GetCurrentProcessId();
MMF_Pointer->Name.Names[x].Active = 1; p_MMF->Name.Names[x].Active = 1;
Written = true; Written = true;
} }
continue; 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) if (!Written)
{ {
memcpy(&(MMF_Pointer->Name.Names[x].Name), Name.c_str(), strlen(Name.c_str()) + 1); memcpy(&(p_MMF->Name.Names[x].Name), Name.c_str(), strlen(Name.c_str()) + 1);
MMF_Pointer->Name.Names[x].Process = GetCurrentProcessId(); p_MMF->Name.Names[x].Process = GetCurrentProcessId();
MMF_Pointer->Name.Names[x].Active = 1; p_MMF->Name.Names[x].Active = 1;
Written = true; 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) if (!Written)
{ {
memcpy(&(MMF_Pointer->Name.Names[x].Name), Name.c_str(), strlen(Name.c_str()) + 1); memcpy(&(p_MMF->Name.Names[x].Name), Name.c_str(), strlen(Name.c_str()) + 1);
MMF_Pointer->Name.Names[x].Process = GetCurrentProcessId(); p_MMF->Name.Names[x].Process = GetCurrentProcessId();
MMF_Pointer->Name.Names[x].Active = 1; p_MMF->Name.Names[x].Active = 1;
Written = true; Written = true;
} }
} }
} }
CurrentName = Name; s_name = Name;
MatchGroups(); MatchGroups();
InterlockedExchange(&(MMF_Pointer->Name.ProcessID), 0); InterlockedExchange(&(p_MMF->Name.ProcessID), 0);
} }
void MultiSend::Claim(uint32_t* Target, uint32_t Mod) void MultiSend::Claim(uint32_t* Target, uint32_t Mod)

47
src/MultiSend/Main.cpp

@ -27,14 +27,6 @@ bool MultiSend::Initialize(IAshitaCore* core, ILogManager* log, uint32_t id)
LoadGroups(); LoadGroups();
DWORD Pointer = NULL; DWORD Pointer = NULL;
Pointers* p = (Pointers*)m_AshitaCore->GetPluginManager()->GetPlugin("Pointers");
if (p)
{
Pointer = p->RegisterPointer("movement", "8BCFE8????FFFF8B0D????????E8????????8BE885ED750CB9", 0, 0);
}
else
{
MODULEINFO mod = { 0 }; MODULEINFO mod = { 0 };
if (!::GetModuleInformation(::GetCurrentProcess(), ::GetModuleHandle("FFXiMain.dll"), &mod, sizeof(MODULEINFO))) if (!::GetModuleInformation(::GetCurrentProcess(), ::GetModuleHandle("FFXiMain.dll"), &mod, sizeof(MODULEINFO)))
return false; return false;
@ -42,12 +34,9 @@ bool MultiSend::Initialize(IAshitaCore* core, ILogManager* log, uint32_t id)
Pointer = Ashita::Memory::FindPattern((uintptr_t)mod.lpBaseOfDll, (uintptr_t)mod.SizeOfImage, Pointer = Ashita::Memory::FindPattern((uintptr_t)mod.lpBaseOfDll, (uintptr_t)mod.SizeOfImage,
"8BCFE8????FFFF8B0D????????E8????????8BE885ED750CB9", "8BCFE8????FFFF8B0D????????E8????????8BE885ED750CB9",
0, 0); 0, 0);
}
if (Pointer == NULL) return false; if (Pointer == NULL) return false;
Pointer += 25; 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 //create a handle to the MMF, size matches the struct we're using for it
HANDLE hMapFile = CreateFileMapping( HANDLE hMapFile = CreateFileMapping(
@ -56,7 +45,7 @@ bool MultiSend::Initialize(IAshitaCore* core, ILogManager* log, uint32_t id)
PAGE_READWRITE, PAGE_READWRITE,
0, // maximum object size (high-order DWORD) 0, // maximum object size (high-order DWORD)
sizeof(MMF_Global), // maximum object size (low-order DWORD) sizeof(MMF_Global), // maximum object size (low-order DWORD)
"FFXI_MultiSend"); "FFXI_MultiSend_1_15");
bool made = (GetLastError() == 0); 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 FILE_MAP_ALL_ACCESS, // read/write permission
0, 0,
0, 0,
sizeof(MMF_Global)); sizeof(MMF_Global));
if (MMF_Pointer == NULL) if (p_MMF == NULL)
{ {
CloseHandle(hMapFile); CloseHandle(hMapFile);
throw exception("Could not map MMF."); throw exception("Could not map MMF.");
@ -79,25 +68,25 @@ bool MultiSend::Initialize(IAshitaCore* core, ILogManager* log, uint32_t id)
if (made) 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)) if (m_AshitaCore->GetDataManager()->GetParty()->GetMemberActive(0))
{ {
uint16_t myindex = m_AshitaCore->GetDataManager()->GetParty()->GetMemberTargetIndex(0); uint16_t myindex = m_AshitaCore->GetDataManager()->GetParty()->GetMemberTargetIndex(0);
UpdateName(std::string(m_AshitaCore->GetDataManager()->GetEntity()->GetName(myindex))); UpdateName(std::string(m_AshitaCore->GetDataManager()->GetEntity()->GetName(myindex)));
} }
_Debug = false; //Default settings.
//SafeMode enabled by Default (to avoid accidental chatlog spam): c_follow = true;
//Allows for prepend of "/echo " to commands that are missing a leading "/". c_ignoreself = false;
_SafeMode = false; c_attemptzone = false;
c_debug = false;
c_safemode = false;
c_maxdist = 5000.0f;
this->Start(); this->Start();
@ -107,9 +96,9 @@ bool MultiSend::Initialize(IAshitaCore* core, ILogManager* log, uint32_t id)
void MultiSend::Release(void) void MultiSend::Release(void)
{ {
this->Stop(); this->Stop();
if (MMF_Pointer) if (p_MMF)
{ {
UnmapViewOfFile((LPCVOID)MMF_Pointer); UnmapViewOfFile((LPCVOID)p_MMF);
} }
if (hMapFile) if (hMapFile)
{ {
@ -130,7 +119,7 @@ __declspec(dllexport) void __stdcall CreatePluginInfo(plugininfo_t* lpBuffer)
strcpy_s(g_PluginInfo->Author, sizeof(g_PluginInfo->Author), "Thorny"); strcpy_s(g_PluginInfo->Author, sizeof(g_PluginInfo->Author), "Thorny");
g_PluginInfo->InterfaceVersion = ASHITA_INTERFACE_VERSION; g_PluginInfo->InterfaceVersion = ASHITA_INTERFACE_VERSION;
g_PluginInfo->PluginVersion = 1.05f; g_PluginInfo->PluginVersion = 1.15f;
g_PluginInfo->Priority = 0; g_PluginInfo->Priority = 0;
} }

47
src/MultiSend/MultiSend.h

@ -6,7 +6,7 @@
#endif #endif
#define SAFE_DELETE(p) if(p) { delete p; p = NULL; } #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 "Structs.h"
#include "..\..\..\pluginheaders\Utilities.h" #include "..\..\..\pluginheaders\Utilities.h"
#include "..\..\..\pluginheaders\Pointers.h" #include "..\..\..\pluginheaders\Pointers.h"
@ -50,28 +50,28 @@ class MultiSend : IPlugin, Ashita::Threading::AS_Thread
ILogManager* m_LogManager; ILogManager* m_LogManager;
DWORD m_PluginId; DWORD m_PluginId;
IDirect3DDevice8* m_Direct3DDevice; IDirect3DDevice8* m_Direct3DDevice;
sFollow* StructPointer;
GroupData m_Group;
//References
HANDLE hMapFile; HANDLE hMapFile;
MMF_Global* MMF_Pointer; sFollow* p_Follow;
MMF_Global* p_MMF;
uint32_t Position;
volatile bool ZoneExtra; //State tracking
volatile bool Following; GroupData s_group;
volatile float PositionX; std::string s_name;
volatile float PositionZ; uint32_t s_position;
std::list<uint16_t> Groups; bool s_last_run_state;
float s_vector_x;
std::string CurrentName; float s_vector_z;
uint32_t Zoning; //0 = not zoning, 1 = waiting to zone, 2 = zoned and waiting to finish //Configuration
volatile bool FollowEnabled; std::list<uint16_t> c_groups;
volatile bool StopFollow; float c_maxdist;
volatile bool IgnoreSelf; volatile bool c_follow;
volatile bool c_attemptzone;
volatile bool _Debug; volatile bool c_ignoreself;
volatile bool _SafeMode; volatile bool c_debug;
volatile bool c_safemode;
public: public:
MultiSend(void); MultiSend(void);
@ -89,10 +89,9 @@ public:
bool HandleCommand(const char* command, int32_t type); bool HandleCommand(const char* command, int32_t type);
uint32_t ThreadEntry(void) override; uint32_t ThreadEntry(void) override;
bool MatchID(uint32_t ID); bool CheckMatch(MMF_ICommand_Single command);
bool ReadCommand(); bool ReadCommand();
void SetFollow(bool Active); void SendCommand(multisend_type type, uint32_t param, const char* Command);
void SendCommand(uint32_t ID, const char* Command);
void SanitizeCommand(char* Input); void SanitizeCommand(char* Input);
std::string SubValues(std::string Input); std::string SubValues(std::string Input);
void SubValues(char* Input); void SubValues(char* Input);

24
src/MultiSend/MultiSend.vcxproj

@ -21,31 +21,32 @@
<PropertyGroup Label="Globals"> <PropertyGroup Label="Globals">
<ProjectGuid>{3C74E1A4-E44B-4523-85DC-9A94AC2D6457}</ProjectGuid> <ProjectGuid>{3C74E1A4-E44B-4523-85DC-9A94AC2D6457}</ProjectGuid>
<RootNamespace>MultiSend</RootNamespace> <RootNamespace>MultiSend</RootNamespace>
<WindowsTargetPlatformVersion>7.0</WindowsTargetPlatformVersion>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>MultiByte</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140_xp</PlatformToolset> <PlatformToolset>v141_xp</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>MultiByte</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>MultiByte</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140_xp</PlatformToolset> <PlatformToolset>v141_xp</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>MultiByte</CharacterSet>
</PropertyGroup> </PropertyGroup>
@ -68,7 +69,7 @@
</ImportGroup> </ImportGroup>
<PropertyGroup Label="UserMacros" /> <PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>..\..\bin\</OutDir> <OutDir>..\..\..\bin\</OutDir>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>..\..\bin\</OutDir> <OutDir>..\..\bin\</OutDir>
@ -110,7 +111,8 @@
<ModuleDefinitionFile>Exports.def</ModuleDefinitionFile> <ModuleDefinitionFile>Exports.def</ModuleDefinitionFile>
</Link> </Link>
<PostBuildEvent> <PostBuildEvent>
<Command>copy "..\..\bin\MultiSend.dll" "C:\Ashita 3\plugins\MultiSend.dll"</Command> <Command>copy "..\..\..\bin\MultiSend.dll" "C:\Program Files (x86)\Ashita 3\plugins\MultiSend.dll"
copy "..\..\..\bin\MultiSend.dll" "..\..\release\plugins\MultiSend.dll"</Command>
</PostBuildEvent> </PostBuildEvent>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@ -140,12 +142,12 @@
<ItemGroup> <ItemGroup>
<ClCompile Include="Commands.cpp" /> <ClCompile Include="Commands.cpp" />
<ClCompile Include="Follow.cpp" /> <ClCompile Include="Follow.cpp" />
<ClCompile Include="Groups.cpp" /> <ClCompile Include="groups.cpp" />
<ClCompile Include="IO.cpp" /> <ClCompile Include="IO.cpp" />
<ClCompile Include="Main.cpp" /> <ClCompile Include="main.cpp" />
<ClCompile Include="Name.cpp" /> <ClCompile Include="packets.cpp" />
<ClCompile Include="Substitute.cpp" /> <ClCompile Include="text_sanitizing.cpp" />
<ClCompile Include="Thread.cpp" /> <ClCompile Include="thread.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="Exports.def" /> <None Include="Exports.def" />

16
src/MultiSend/MultiSend.vcxproj.filters

@ -23,28 +23,28 @@
</ClInclude> </ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="Main.cpp"> <ClCompile Include="IO.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Thread.cpp"> <ClCompile Include="Commands.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="IO.cpp"> <ClCompile Include="Follow.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Groups.cpp"> <ClCompile Include="packets.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Name.cpp"> <ClCompile Include="text_sanitizing.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Commands.cpp"> <ClCompile Include="thread.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Follow.cpp"> <ClCompile Include="main.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Substitute.cpp"> <ClCompile Include="groups.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
</ItemGroup> </ItemGroup>

30
src/MultiSend/Structs.h

@ -3,6 +3,16 @@
#include <stdint.h> #include <stdint.h>
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 struct MMF_Name_Single
{ {
uint32_t Process; uint32_t Process;
@ -18,10 +28,11 @@ struct MMF_Name
struct MMF_ICommand_Single struct MMF_ICommand_Single
{ {
uint8_t Active; uint8_t active;
uint32_t Targets; multisend_type type;
uint32_t SendProcess; uint32_t param;
uint8_t Command[248]; uint32_t sender_process_id;
uint8_t command[248];
}; };
struct MMF_ICommand struct MMF_ICommand
@ -33,11 +44,12 @@ struct MMF_ICommand
struct MMF_IFollow struct MMF_IFollow
{ {
uint16_t Zone; uint32_t target_process_id;
uint32_t FollowID; uint16_t lastzone;
uint32_t Follow; uint16_t zone;
int32_t PosX; float position_x;
int32_t PosZ; float position_z;
uint32_t idle_count;
}; };
struct MMF_Global struct MMF_Global

78
src/MultiSend/Thread.cpp

@ -4,76 +4,38 @@ uint32_t MultiSend::ThreadEntry(void)
{ {
while (!this->IsTerminated()) while (!this->IsTerminated())
{ {
if (m_AshitaCore->GetDataManager()->GetParty()->GetMemberActive(0)) if (p_MMF->Follow.target_process_id == GetCurrentProcessId())
{ {
if (Zoning == 2) Zoning = 0; uint16_t zone = m_AshitaCore->GetDataManager()->GetParty()->GetMemberZone(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); uint16_t myindex = m_AshitaCore->GetDataManager()->GetParty()->GetMemberTargetIndex(0);
int32_t mPosX = (int32_t)floor(m_AshitaCore->GetDataManager()->GetEntity()->GetLocalX(myindex) * 100); uint32_t renderflags = m_AshitaCore->GetDataManager()->GetEntity()->GetRenderFlags0(myindex);
int32_t mPosZ = (int32_t)floor(m_AshitaCore->GetDataManager()->GetEntity()->GetLocalZ(myindex) * 100); bool isrendered = (((renderflags & 0x200) != 0) && ((renderflags & 0x4000) == 0));
MMF_Pointer->Follow.PosX = mPosX; float my_pos_x = m_AshitaCore->GetDataManager()->GetEntity()->GetLocalX(myindex);
MMF_Pointer->Follow.PosZ = mPosZ; float my_pos_z = m_AshitaCore->GetDataManager()->GetEntity()->GetLocalZ(myindex);
MMF_Pointer->Follow.Follow = 1; if ((zone == 0) || (myindex == 0) || (!isrendered))
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) if (p_MMF->Follow.zone != 0)
{ {
Following = false; p_MMF->Follow.lastzone = p_MMF->Follow.zone;
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;
} }
p_MMF->Follow.zone = 0;
} }
else else
{ {
ZoneExtra = false; if (p_MMF->Follow.zone == 0)
PositionX = (float)MMF_Pointer->Follow.PosX / 100.0f; {
PositionZ = (float)MMF_Pointer->Follow.PosZ / 100.0f; p_MMF->Follow.idle_count = 0;
Following = true;
}
}
} }
else else if ((my_pos_x != p_MMF->Follow.position_x) || (my_pos_z != p_MMF->Follow.position_z))
{ {
if (Following) StopFollow = true; p_MMF->Follow.idle_count = 0;
Following = false;
} }
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;
} }
while (ReadCommand()) {} while (ReadCommand()) {}

25
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;
}

87
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.");
}
}
Loading…
Cancel
Save