forked from gcdsfh/PMDT
871 lines
34 KiB
C++
Executable File
871 lines
34 KiB
C++
Executable File
#define W2S(w, s) UGameplayStatics::ProjectWorldToScreen(localController, w, true, s)
|
|
|
|
// 辅助函数:检查是否应该跳过该玩家
|
|
bool ShouldSkipPlayer(ASTExtraPlayerCharacter* Player, ASTExtraPlayerController* localController, ASTExtraPlayerCharacter* localPlayer) {
|
|
float Distance = localPlayer->GetDistanceTo(Player) / 100.0f;
|
|
|
|
// 跳过条件
|
|
if (Distance > 600.0f) return true;
|
|
if (Player->PlayerKey == localController->PlayerKey) return true;
|
|
if (Player->bDead) return true;
|
|
if (Config.PlayerESP.NoBot && Player->bIsAI) return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
// 辅助函数:绘制iOS风格预警指示器
|
|
void DrawAlertIndicator(ImDrawList* draw, ASTExtraPlayerCharacter* Player,
|
|
ASTExtraPlayerCharacter* localPlayer,
|
|
ASTExtraPlayerController* localController,
|
|
ImColor borderColor, ImColor fillColor,
|
|
int screenWidth, int screenHeight) {
|
|
FVector MyPosition, EnemyPosition;
|
|
|
|
// 获取位置
|
|
ASTExtraVehicleBase* CurrentVehiclea = Player->CurrentVehicle;
|
|
if (CurrentVehiclea) {
|
|
MyPosition = CurrentVehiclea->RootComponent->RelativeLocation;
|
|
} else {
|
|
MyPosition = Player->RootComponent->RelativeLocation;
|
|
}
|
|
|
|
ASTExtraVehicleBase* CurrentVehicle = localPlayer->CurrentVehicle;
|
|
if (CurrentVehicle) {
|
|
EnemyPosition = CurrentVehicle->RootComponent->RelativeLocation;
|
|
} else {
|
|
EnemyPosition = localPlayer->RootComponent->RelativeLocation;
|
|
}
|
|
|
|
// 计算雷达位置
|
|
bool shit = false;
|
|
FVector EntityPos = WorldToRadar(localController->PlayerCameraManager->CameraCache.POV.Rotation.Yaw,
|
|
MyPosition, EnemyPosition, NULL, NULL,
|
|
Vector3(screenWidth, screenHeight, 0), shit);
|
|
|
|
// 计算角度
|
|
FVector angle = FVector();
|
|
Vector3 forward = Vector3((float)(screenWidth / 2) - EntityPos.X,
|
|
(float)(screenHeight / 2) - EntityPos.Y, 0.0f);
|
|
VectorAnglesRadar(forward, angle);
|
|
|
|
// 绘制iOS风格三角形指示器
|
|
const auto angle_yaw_rad = DEG2RAD(angle.Y + 180.f);
|
|
const auto new_point_x = (screenWidth / 2) + 55 * 4 * cosf(angle_yaw_rad);
|
|
const auto new_point_y = (screenHeight / 2) + 55 * 4 * sinf(angle_yaw_rad);
|
|
|
|
std::array<Vector3, 3> points {
|
|
Vector3(new_point_x - 12, new_point_y - 12, 0.f),
|
|
Vector3(new_point_x + 12, new_point_y, 0.f),
|
|
Vector3(new_point_x - 12, new_point_y + 12, 0.f)
|
|
};
|
|
|
|
RotateTriangle(points, angle.Y + 180.f);
|
|
|
|
// iOS风格渐变填充
|
|
draw->AddTriangleFilled(ImVec2(points.at(0).X, points.at(0).Y),
|
|
ImVec2(points.at(1).X, points.at(1).Y),
|
|
ImVec2(points.at(2).X, points.at(2).Y),
|
|
fillColor);
|
|
|
|
// 细边框
|
|
draw->AddTriangle(ImVec2(points.at(0).X, points.at(0).Y),
|
|
ImVec2(points.at(1).X, points.at(1).Y),
|
|
ImVec2(points.at(2).X, points.at(2).Y),
|
|
borderColor, 1.0f);
|
|
}
|
|
|
|
// 辅助函数:绘制iOS风格玩家方框
|
|
void DrawPlayerBox(ImDrawList* draw, ImVec2 headPos, ImVec2 rootPos, ImColor color, bool isMonster = false) {
|
|
if (isMonster) {
|
|
// 怪物方框:更大,填满怪物
|
|
float boxHeight = abs(headPos.y - rootPos.y) * 1.5f; // 怪物更高
|
|
float boxWidth = boxHeight * 0.8f; // 怪物更宽
|
|
|
|
// 调整怪物方框位置,确保居中
|
|
float centerY = headPos.y - (headPos.y - rootPos.y) / 2.0f;
|
|
ImVec2 boxTop = ImVec2(headPos.x - (boxWidth / 2), centerY - boxHeight / 2);
|
|
ImVec2 boxBottom = ImVec2(headPos.x + (boxWidth / 2), centerY + boxHeight / 2);
|
|
|
|
// 怪物使用更醒目的方框
|
|
draw->AddRectFilled(boxTop, boxBottom,
|
|
IM_COL32((int)(color.Value.x * 255), (int)(color.Value.y * 255),
|
|
(int)(color.Value.z * 255), 30),
|
|
4.0f);
|
|
draw->AddRect(boxTop, boxBottom, color, 4.0f, ImDrawFlags_RoundCornersAll, 2.5f);
|
|
} else {
|
|
// 玩家方框:iOS风格
|
|
float boxHeight = abs(headPos.y - rootPos.y);
|
|
float boxWidth = boxHeight * 0.6f;
|
|
|
|
ImVec2 boxTop = ImVec2(headPos.x - (boxWidth / 2), headPos.y);
|
|
ImVec2 boxBottom = ImVec2(headPos.x + (boxWidth / 2), rootPos.y);
|
|
|
|
// iOS风格半透明填充
|
|
draw->AddRectFilled(boxTop, boxBottom,
|
|
IM_COL32((int)(color.Value.x * 255), (int)(color.Value.y * 255),
|
|
(int)(color.Value.z * 255), 20),
|
|
4.0f);
|
|
// iOS风格细边框
|
|
draw->AddRect(boxTop, boxBottom, color, 4.0f, ImDrawFlags_RoundCornersAll, 1.5f);
|
|
}
|
|
}
|
|
|
|
// 辅助函数:绘制iOS风格血量条
|
|
void DrawHealthBar(ImDrawList* draw, ASTExtraPlayerCharacter* Player,
|
|
ImVec2 headPosSC, ASTExtraPlayerController* localController,
|
|
FVector HeadPos, bool isMonster = false) {
|
|
float PercentHP = (Player->Health / Player->HealthMax) * 100;
|
|
|
|
// 调整血条大小
|
|
float barWidth, barHeight, barX, barY;
|
|
|
|
if (isMonster) {
|
|
// 怪物血条:更大
|
|
barWidth = 80.0f;
|
|
barHeight = 8.0f;
|
|
} else {
|
|
// 玩家血条
|
|
barWidth = 60.0f;
|
|
barHeight = 6.0f;
|
|
}
|
|
|
|
barX = headPosSC.x - barWidth / 2;
|
|
barY = headPosSC.y - 25.0f; // 调整位置,为玩家信息留出空间
|
|
|
|
// iOS风格毛玻璃背景
|
|
draw->AddRectFilled(ImVec2(barX, barY),
|
|
ImVec2(barX + barWidth, barY + barHeight),
|
|
ImColor(40, 40, 40, 200), barHeight / 2);
|
|
|
|
// 计算血量颜色
|
|
ImColor healthColor;
|
|
if (!localController->LineOfSightTo(localController->PlayerCameraManager, HeadPos, true)) {
|
|
healthColor = ImColor(0, 122, 255, 220); // iOS蓝色
|
|
} else {
|
|
// 根据血量渐变
|
|
if (PercentHP > 70) healthColor = ImColor(52, 199, 89, 220); // iOS绿色
|
|
else if (PercentHP > 30) healthColor = ImColor(255, 149, 0, 220); // iOS橙色
|
|
else healthColor = ImColor(255, 59, 48, 220); // iOS红色
|
|
}
|
|
|
|
// 血量填充
|
|
float fillWidth = (barWidth * PercentHP) / 100.0f;
|
|
if (fillWidth > 0) {
|
|
draw->AddRectFilled(ImVec2(barX, barY),
|
|
ImVec2(barX + fillWidth, barY + barHeight),
|
|
healthColor, barHeight / 2);
|
|
}
|
|
|
|
// 细边框
|
|
draw->AddRect(ImVec2(barX, barY),
|
|
ImVec2(barX + barWidth, barY + barHeight),
|
|
ImColor(255, 255, 255, 80), barHeight / 2, 0, 0.8f);
|
|
}
|
|
|
|
// 辅助函数:绘制iOS风格玩家信息
|
|
void DrawPlayerInfo(ImDrawList* draw, ASTExtraPlayerCharacter* Player,
|
|
ImVec2 headPosSC, ImVec2 rootPosSC, float Distance, bool isMonster = false) {
|
|
// iOS风格字体和颜色
|
|
ImColor textColor = ImColor(255, 255, 255, 240);
|
|
ImColor shadowColor = ImColor(0, 0, 0, 180);
|
|
float fontSize = isMonster ? 18.0f : 16.0f;
|
|
|
|
// 1. 显示玩家指针(调试用)
|
|
if (世界) {
|
|
auto MySelf = getPointer(getPointer(UE4 + 0x4634ef0) + 0x0) + 0x20;
|
|
char extra[50];
|
|
sprintf(extra, "%p", MySelf);
|
|
绘制加粗文本(22, headPosSC.x, headPosSC.y + 10, textColor, shadowColor, extra);
|
|
}
|
|
|
|
// 2. 显示玩家名称和类型(带背景)
|
|
if (Config.PlayerESP.名字) {
|
|
std::string info;
|
|
|
|
if (isMonster) {
|
|
info = "年兽";
|
|
} else if (Player->bIsAI) {
|
|
info = "AI";
|
|
} else {
|
|
info = "玩家";
|
|
}
|
|
|
|
// 添加队伍ID
|
|
info = std::to_string((int)Player->TeamID) + " · " + info;
|
|
|
|
auto textSize = ImGui::CalcTextSize(info.c_str());
|
|
|
|
// iOS风格文本背景
|
|
float padding = 6.0f;
|
|
ImVec2 textPos = ImVec2(headPosSC.x - (textSize.x / 2.0f), headPosSC.y - 35.0f);
|
|
ImVec2 bgMin = ImVec2(textPos.x - padding, textPos.y - padding/2);
|
|
ImVec2 bgMax = ImVec2(textPos.x + textSize.x + padding, textPos.y + textSize.y + padding/2);
|
|
|
|
draw->AddRectFilled(bgMin, bgMax, ImColor(0, 0, 0, 160), 6.0f);
|
|
|
|
// 绘制文本
|
|
绘制加粗文本(fontSize, textPos.x, textPos.y, textColor, shadowColor, info.c_str());
|
|
}
|
|
|
|
// 3. 显示距离(带背景)
|
|
if (Config.PlayerESP.距离) {
|
|
std::string distanceStr = std::to_string((int)Distance) + "M";
|
|
|
|
auto textSize = ImGui::CalcTextSize(distanceStr.c_str());
|
|
|
|
// iOS风格文本背景
|
|
float padding = 4.0f;
|
|
ImVec2 textPos = ImVec2(rootPosSC.x - (textSize.x / 2.0f), rootPosSC.y + 5.0f);
|
|
ImVec2 bgMin = ImVec2(textPos.x - padding, textPos.y - padding/2);
|
|
ImVec2 bgMax = ImVec2(textPos.x + textSize.x + padding, textPos.y + textSize.y + padding/2);
|
|
|
|
draw->AddRectFilled(bgMin, bgMax, ImColor(0, 0, 0, 160), 4.0f);
|
|
|
|
// 绘制文本
|
|
ImColor distanceColor = isMonster ? ImColor(255, 149, 0, 240) : ImColor(0, 122, 255, 240);
|
|
绘制加粗文本(fontSize-2, textPos.x, textPos.y, distanceColor, shadowColor, distanceStr.c_str());
|
|
}
|
|
}
|
|
|
|
// 辅助函数:绘制玩家ESP(修复怪物绘制问题)
|
|
void DrawPlayerESP(ImDrawList* draw, ASTExtraPlayerCharacter* Player,
|
|
ASTExtraPlayerCharacter* localPlayer,
|
|
ASTExtraPlayerController* localController,
|
|
int screenWidth, int screenHeight) {
|
|
|
|
float Distance = localPlayer->GetDistanceTo(Player) / 100.0f;
|
|
|
|
// 特殊处理怪物(年兽)
|
|
bool isMonster = (Player->bIsAI &&
|
|
(Player->GetName().find("Monster") != std::string::npos ||
|
|
Player->GetName().find("Beast") != std::string::npos ||
|
|
Player->GetName().find("年兽") != std::string::npos));
|
|
|
|
// 1. 获取位置
|
|
FVector HeadPos, RootPos;
|
|
|
|
if (isMonster) {
|
|
// 对于怪物,使用更准确的位置计算
|
|
HeadPos = Player->K2_GetActorLocation();
|
|
HeadPos.Z += 180.0f; // 怪物高度调整
|
|
RootPos = Player->K2_GetActorLocation();
|
|
RootPos.Z -= 60.0f; // 怪物底部调整
|
|
} else {
|
|
// 正常玩家/人机
|
|
HeadPos = Player->GetBonePos("Head");
|
|
RootPos = Player->GetBonePos("Root");
|
|
}
|
|
|
|
ImVec2 headPosSC, RootPosSC;
|
|
|
|
// 检查位置是否可见
|
|
bool positionsVisible = W2S(HeadPos, (FVector2D*)&headPosSC) &&
|
|
W2S(RootPos, (FVector2D*)&RootPosSC);
|
|
|
|
if (!positionsVisible) {
|
|
// 如果不可见,尝试使用更简单的方法
|
|
FVector actorPos = Player->K2_GetActorLocation();
|
|
if (!W2S(actorPos, (FVector2D*)&headPosSC)) {
|
|
return;
|
|
}
|
|
|
|
if (isMonster) {
|
|
// 怪物:创建合适的方框高度
|
|
RootPosSC = ImVec2(headPosSC.x, headPosSC.y + 100.0f);
|
|
} else {
|
|
RootPosSC = ImVec2(headPosSC.x, headPosSC.y + 50.0f);
|
|
}
|
|
}
|
|
|
|
// 调整怪物位置:确保方框正确居中
|
|
if (isMonster) {
|
|
// 调整头部位置,使方框更准确
|
|
float boxHeight = abs(headPosSC.y - RootPosSC.y);
|
|
headPosSC.y = headPosSC.y - boxHeight * 0.2f; // 向上调整
|
|
}
|
|
|
|
// 2. 确定颜色
|
|
bool IsVisible = localController->LineOfSightTo(Player, {0, 0, 0}, true);
|
|
ImColor PlayerBoxClrCf, PlayerBoxClrCf2, SkeletonColor;
|
|
|
|
if (isMonster) {
|
|
// 怪物使用特殊颜色
|
|
PlayerBoxClrCf = ImColor(255, 149, 0, 255); // iOS橙色
|
|
PlayerBoxClrCf2 = ImColor(255, 149, 0, 80);
|
|
SkeletonColor = ImColor(255, 149, 0, 200);
|
|
} else if (IsVisible) {
|
|
if (Player->bIsAI) {
|
|
PlayerBoxClrCf = ImColor(52, 199, 89, 255); // iOS绿色
|
|
SkeletonColor = ImColor(52, 199, 89, 200);
|
|
} else {
|
|
PlayerBoxClrCf = ImColor(255, 59, 48, 255); // iOS红色
|
|
SkeletonColor = ImColor(255, 59, 48, 200);
|
|
}
|
|
PlayerBoxClrCf2 = ImColor(IM_COL32((int)(PlayerBoxClrCf.Value.x * 255), (int)(PlayerBoxClrCf.Value.y * 255), (int)(PlayerBoxClrCf.Value.z * 255), 80));
|
|
} else {
|
|
PlayerBoxClrCf = ImColor(142, 142, 147, 255); // iOS灰色
|
|
PlayerBoxClrCf2 = ImColor(142, 142, 147, 80);
|
|
SkeletonColor = ImColor(142, 142, 147, 200);
|
|
}
|
|
|
|
// 3. 绘制各种ESP元素
|
|
// 3.1 预警指示器
|
|
if (Config.PlayerESP.Alert) {
|
|
DrawAlertIndicator(draw, Player, localPlayer, localController, PlayerBoxClrCf, PlayerBoxClrCf2, screenWidth, screenHeight);
|
|
}
|
|
|
|
// 3.2 连线
|
|
if (Config.PlayerESP.Line) {
|
|
draw->AddLine(ImVec2((float)screenWidth / 2, (float)screenHeight / 8),
|
|
ImVec2(headPosSC.x, headPosSC.y - 15.0f),
|
|
PlayerBoxClrCf, 1.5f);
|
|
}
|
|
|
|
// 3.3 方框
|
|
if (Config.PlayerESP.Box) {
|
|
DrawPlayerBox(draw, headPosSC, RootPosSC, PlayerBoxClrCf, isMonster);
|
|
}
|
|
|
|
// 3.4 骨骼(仅对非怪物绘制)
|
|
if (Config.PlayerESP.Skeleton && !isMonster) {
|
|
// 获取其他骨骼位置
|
|
ImVec2 upper_rPoSC, lowerarm_rPoSC, hand_rPoSC;
|
|
ImVec2 upper_lPoSC, lowerarm_lSC, hand_lPoSC;
|
|
ImVec2 thigh_lPoSC, calf_lPoSC, foot_lPoSC;
|
|
ImVec2 thigh_rPoSC, calf_rPoSC, foot_rPoSC;
|
|
ImVec2 neck_01PoSC, pelvisPoSC;
|
|
|
|
// 检查骨骼是否可见
|
|
FVector bonePositions[] = {
|
|
Player->GetBonePos("upperarm_r"), Player->GetBonePos("lowerarm_r"),
|
|
Player->GetBonePos("hand_r"), Player->GetBonePos("upperarm_l"),
|
|
Player->GetBonePos("lowerarm_l"), Player->GetBonePos("hand_l"),
|
|
Player->GetBonePos("thigh_l"), Player->GetBonePos("calf_l"),
|
|
Player->GetBonePos("foot_l"), Player->GetBonePos("thigh_r"),
|
|
Player->GetBonePos("calf_r"), Player->GetBonePos("foot_r"),
|
|
Player->GetBonePos("neck_01"), Player->GetBonePos("pelvis")
|
|
};
|
|
|
|
if (W2S(bonePositions[0], (FVector2D*)&upper_rPoSC) &&
|
|
W2S(bonePositions[1], (FVector2D*)&lowerarm_rPoSC) &&
|
|
W2S(bonePositions[2], (FVector2D*)&hand_rPoSC) &&
|
|
W2S(bonePositions[3], (FVector2D*)&upper_lPoSC) &&
|
|
W2S(bonePositions[4], (FVector2D*)&lowerarm_lSC) &&
|
|
W2S(bonePositions[5], (FVector2D*)&hand_lPoSC) &&
|
|
W2S(bonePositions[6], (FVector2D*)&thigh_lPoSC) &&
|
|
W2S(bonePositions[7], (FVector2D*)&calf_lPoSC) &&
|
|
W2S(bonePositions[8], (FVector2D*)&foot_lPoSC) &&
|
|
W2S(bonePositions[9], (FVector2D*)&thigh_rPoSC) &&
|
|
W2S(bonePositions[10], (FVector2D*)&calf_rPoSC) &&
|
|
W2S(bonePositions[11], (FVector2D*)&foot_rPoSC) &&
|
|
W2S(bonePositions[12], (FVector2D*)&neck_01PoSC) &&
|
|
W2S(bonePositions[13], (FVector2D*)&pelvisPoSC)) {
|
|
|
|
// 绘制骨骼连线
|
|
draw->AddLine(upper_rPoSC, neck_01PoSC, SkeletonColor, 1.8f);
|
|
draw->AddLine(upper_lPoSC, neck_01PoSC, SkeletonColor, 1.8f);
|
|
draw->AddLine(upper_rPoSC, lowerarm_rPoSC, SkeletonColor, 1.8f);
|
|
draw->AddLine(lowerarm_rPoSC, hand_rPoSC, SkeletonColor, 1.8f);
|
|
draw->AddLine(upper_lPoSC, lowerarm_lSC, SkeletonColor, 1.8f);
|
|
draw->AddLine(lowerarm_lSC, hand_lPoSC, SkeletonColor, 1.8f);
|
|
draw->AddLine(thigh_rPoSC, thigh_lPoSC, SkeletonColor, 1.8f);
|
|
draw->AddLine(thigh_lPoSC, calf_lPoSC, SkeletonColor, 1.8f);
|
|
draw->AddLine(calf_lPoSC, foot_lPoSC, SkeletonColor, 1.8f);
|
|
draw->AddLine(thigh_rPoSC, calf_rPoSC, SkeletonColor, 1.8f);
|
|
draw->AddLine(calf_rPoSC, foot_rPoSC, SkeletonColor, 1.8f);
|
|
draw->AddLine(neck_01PoSC, pelvisPoSC, SkeletonColor, 1.8f);
|
|
draw->AddLine(neck_01PoSC, headPosSC, SkeletonColor, 1.8f);
|
|
}
|
|
}
|
|
|
|
// 3.5 血量条
|
|
if (Config.PlayerESP.血量) {
|
|
DrawHealthBar(draw, Player, headPosSC, localController, HeadPos, isMonster);
|
|
}
|
|
|
|
// 3.6 玩家信息
|
|
DrawPlayerInfo(draw, Player, headPosSC, RootPosSC, Distance, isMonster);
|
|
}
|
|
|
|
// 武器相关辅助函数
|
|
void ApplyWeaponDamageMultiplier(ASTExtraPlayerCharacter* localPlayer) {
|
|
auto WeaponManagerComponent = localPlayer->WeaponManagerComponent;
|
|
if (!WeaponManagerComponent) return;
|
|
|
|
auto propSlot = WeaponManagerComponent->GetCurrentUsingPropSlot();
|
|
if ((int)propSlot.GetValue() < 1 || (int)propSlot.GetValue() > 3) return;
|
|
|
|
auto CurrentWeaponReplicated = (ASTExtraShootWeapon*)WeaponManagerComponent->CurrentWeaponReplicated;
|
|
if (!CurrentWeaponReplicated) return;
|
|
|
|
auto ShootWeaponComponent = CurrentWeaponReplicated->ShootWeaponComponent;
|
|
if (!ShootWeaponComponent) return;
|
|
|
|
UShootWeaponEntity* ShootWeaponEntityComponent = ShootWeaponComponent->ShootWeaponEntityComponent;
|
|
if (!ShootWeaponEntityComponent) return;
|
|
|
|
ShootWeaponEntityComponent->BulletNumSingleShot = 50;
|
|
}
|
|
|
|
void ApplyWeaponRecoilControl(ASTExtraPlayerCharacter* localPlayer) {
|
|
auto WeaponManagerComponent = localPlayer->WeaponManagerComponent;
|
|
if (!WeaponManagerComponent) return;
|
|
|
|
auto Slot = WeaponManagerComponent->GetCurrentUsingPropSlot();
|
|
if ((int)Slot.GetValue() < 1 || (int)Slot.GetValue() > 3) return;
|
|
|
|
auto CurrentWeaponReplicated = (ASTExtraShootWeapon*)WeaponManagerComponent->CurrentWeaponReplicated;
|
|
if (!CurrentWeaponReplicated) return;
|
|
|
|
auto ShootWeaponEntityComp = CurrentWeaponReplicated->ShootWeaponEntityComp;
|
|
auto ShootWeaponEffectComp = CurrentWeaponReplicated->ShootWeaponEffectComp;
|
|
|
|
if (!ShootWeaponEntityComp || !ShootWeaponEffectComp) return;
|
|
|
|
// 重置后坐力
|
|
memset(&ShootWeaponEntityComp->RecoilInfo, 0, sizeof(FSRecoilInfo));
|
|
ShootWeaponEntityComp->AccessoriesVRecoilFactor = 0.0f;
|
|
ShootWeaponEntityComp->AccessoriesHRecoilFactor = 0.0f;
|
|
ShootWeaponEntityComp->AccessoriesRecoveryFactor = 0.0f;
|
|
|
|
// 重置偏差
|
|
memset(&ShootWeaponEntityComp->DeviationInfo, 0, sizeof(FSDeviation));
|
|
ShootWeaponEntityComp->ShotGunVerticalSpread = 0.0f;
|
|
ShootWeaponEntityComp->ShotGunHorizontalSpread = 0.0f;
|
|
ShootWeaponEntityComp->GameDeviationFactor = 0.0f;
|
|
ShootWeaponEntityComp->GameDeviationAccuracy = 0.0f;
|
|
|
|
// 重置准星
|
|
ShootWeaponEntityComp->CrossHairInitialSize = 0.0f;
|
|
ShootWeaponEntityComp->CrossHairBurstSpeed = 0.0f;
|
|
ShootWeaponEntityComp->CrossHairBurstIncreaseSpeed = 0.0f;
|
|
ShootWeaponEntityComp->RecoilKickADS = 0.0f;
|
|
|
|
// 重置相机抖动
|
|
ShootWeaponEffectComp->CameraShakeInnerRadius = 0.0f;
|
|
ShootWeaponEffectComp->CameraShakeOuterRadius = 0.0f;
|
|
ShootWeaponEffectComp->CameraShakFalloff = 0.0f;
|
|
}
|
|
|
|
void ApplyWeaponScale(ASTExtraPlayerCharacter* localPlayer) {
|
|
auto WeaponManagerComponent = localPlayer->WeaponManagerComponent;
|
|
if (!WeaponManagerComponent) return;
|
|
|
|
auto Slot = WeaponManagerComponent->GetCurrentUsingPropSlot();
|
|
if ((int)Slot.GetValue() < 1 || (int)Slot.GetValue() > 3) return;
|
|
|
|
auto CurrentWeaponReplicated = (ASTExtraShootWeapon*)WeaponManagerComponent->CurrentWeaponReplicated;
|
|
if (!CurrentWeaponReplicated) return;
|
|
|
|
CurrentWeaponReplicated->RootComponent->RelativeScale3D.Y = Gun_Size;
|
|
CurrentWeaponReplicated->RootComponent->RelativeScale3D.Z = Gun_Size;
|
|
CurrentWeaponReplicated->RootComponent->RelativeScale3D.X = Gun_Size;
|
|
}
|
|
|
|
void ApplyWeaponDamage(ASTExtraPlayerCharacter* localPlayer) {
|
|
auto WeaponManagerComponent = localPlayer->WeaponManagerComponent;
|
|
if (!WeaponManagerComponent) return;
|
|
|
|
auto Slot = WeaponManagerComponent->GetCurrentUsingPropSlot();
|
|
if ((int)Slot.GetValue() < 1 || (int)Slot.GetValue() > 3) return;
|
|
|
|
auto CurrentWeaponReplicated = (ASTExtraShootWeapon*)WeaponManagerComponent->CurrentWeaponReplicated;
|
|
if (!CurrentWeaponReplicated) return;
|
|
|
|
auto ShootWeaponEntityComp = CurrentWeaponReplicated->ShootWeaponEntityComp;
|
|
if (!ShootWeaponEntityComp) return;
|
|
|
|
ShootWeaponEntityComp->BaseImpactDamage = 伤害值 * 伤害倍率;
|
|
}
|
|
|
|
// 辅助函数:应用玩家功能
|
|
void ApplyPlayerFeatures(ASTExtraPlayerCharacter* localPlayer,
|
|
ASTExtraPlayerController* localController,
|
|
int screenWidth, int screenHeight) {
|
|
// 1. 高跳功能
|
|
if (高跳) {
|
|
UCharacterMovementComponent* CharacterMovement = localPlayer->CharacterMovement;
|
|
if (CharacterMovement) {
|
|
CharacterMovement->JumpZVelocity = 高度;
|
|
CharacterMovement->GravityScale = 2.0f;
|
|
CharacterMovement->MaxStepHeight = 999.9f;
|
|
}
|
|
}
|
|
|
|
// 2. 人物旋转功能
|
|
if (chongchongche) {
|
|
USceneComponent* MeshContainer = g_LocalPlayer->MeshContainer;
|
|
MeshContainer->RelativeRotation = {0, chongchongche1, 0};
|
|
chongchongche1 += chongchongche2;
|
|
if (chongchongche1 >= tocdoquay) chongchongche1 = 0.0f;
|
|
chongchongche1 += 50;
|
|
}
|
|
|
|
// 3. 人物缩放功能
|
|
if (人物变大) {
|
|
USceneComponent* MeshContainer = g_LocalPlayer->MeshContainer;
|
|
MeshContainer->SetWorldScale3D({巨人, 巨人, 巨人});
|
|
}
|
|
|
|
// 4. 飞天功能
|
|
if (飞天跳开) {
|
|
localPlayer->CharacterMovement->MaxAcceleration = 9999999.0f;
|
|
localPlayer->CustomTimeDilation = 0.7f;
|
|
localPlayer->EnergySpeedScale = 6.0f;
|
|
localPlayer->CharacterMovement->JumpZVelocity = 2200.0f;
|
|
localPlayer->CharacterMovement->bMaintainHorizontalGroundVelocity = true;
|
|
}
|
|
|
|
if (飞天跳关) {
|
|
localPlayer->CharacterMovement->MaxAcceleration = 10000.828f;
|
|
localPlayer->CustomTimeDilation = 1.0f;
|
|
localPlayer->EnergySpeedScale = 1.0f;
|
|
localPlayer->CharacterMovement->bMaintainHorizontalGroundVelocity = false;
|
|
localPlayer->CharacterMovement->JumpZVelocity = 500.0f;
|
|
}
|
|
|
|
// 5. 能量加速功能
|
|
if (能量加速开) {
|
|
auto GWorld = GetWorld();
|
|
if (localPlayer->Energy.EnergyCurrent >= 65) {
|
|
GWorld->PersistentLevel->WorldSettings->MinUndilatedFrameTime = 0.210f;
|
|
}
|
|
}
|
|
|
|
if (能量加速关) {
|
|
auto GWorld = GetWorld();
|
|
if (localPlayer->Energy.EnergyCurrent >= 65) {
|
|
GWorld->PersistentLevel->WorldSettings->MinUndilatedFrameTime = 0.000f;
|
|
}
|
|
}
|
|
|
|
// 6. 武器功能
|
|
if (伤害测试2) {
|
|
ApplyWeaponDamageMultiplier(localPlayer);
|
|
}
|
|
|
|
if (枪械一套) {
|
|
ApplyWeaponRecoilControl(localPlayer);
|
|
}
|
|
|
|
if (枪械变大) {
|
|
ApplyWeaponScale(localPlayer);
|
|
}
|
|
|
|
if (广角) {
|
|
localPlayer->ThirdPersonCameraComponent->SetFieldOfView(视角);
|
|
}
|
|
|
|
if (开启伤害) {
|
|
ApplyWeaponDamage(localPlayer);
|
|
}
|
|
|
|
// 7. 飞行功能
|
|
if (飞天2) {
|
|
UCharacterMovementComponent* CharacterMovement = localPlayer->CharacterMovement;
|
|
if (CharacterMovement) {
|
|
CharacterMovement->SetMovementMode(EMovementMode::MOVE_Flying, 1);
|
|
FVector NewLocation = localPlayer->K2_GetActorLocation();
|
|
NewLocation.Z += 10.0f;
|
|
CharacterMovement->GravityScale = 0.0f;
|
|
localPlayer->K2_SetActorLocation(NewLocation, 0, false, nullptr);
|
|
}
|
|
}
|
|
|
|
if (飞天1) {
|
|
UCharacterMovementComponent* CharacterMovement = localPlayer->CharacterMovement;
|
|
if (CharacterMovement) {
|
|
CharacterMovement->GravityScale = 0.f;
|
|
}
|
|
}
|
|
|
|
if (飞天关) {
|
|
UCharacterMovementComponent* CharacterMovement = g_LocalPlayer->CharacterMovement;
|
|
CharacterMovement->SetMovementMode(EMovementMode::MOVE_Walking, 1);
|
|
CharacterMovement->GravityScale = 1.0f;
|
|
}
|
|
|
|
// 8. 修复功能
|
|
if (修复着陆) {
|
|
g_LocalPlayer->STPlayerController->bCanOpenParachute = true;
|
|
g_LocalPlayer->STPlayerController->bCanCloseParachute = true;
|
|
g_LocalPlayer->STPlayerController->bLandAfterJumpPlane = true;
|
|
}
|
|
}
|
|
|
|
// 辅助函数:应用载具功能
|
|
void ApplyVehicleFeatures(ASTExtraPlayerCharacter* localPlayer,
|
|
ASTExtraPlayerController* localController) {
|
|
if (!自控初始化 || !localPlayer) return;
|
|
|
|
auto CurrentVehicle2 = localPlayer->CurrentVehicle;
|
|
if (!CurrentVehicle2) return;
|
|
|
|
auto RootComponent = static_cast<UPrimitiveComponent*>(CurrentVehicle2->K2_GetRootComponent());
|
|
if (!RootComponent) return;
|
|
|
|
// 1. 旋转控制
|
|
if (转圈) {
|
|
auto RootComponent2 = static_cast<UPrimitiveComponent*>(CurrentVehicle2->K2_GetRootComponent());
|
|
RootComponent2->SetAllPhysicsAngularVelocity({0.f, 0.f, 26.5f}, true);
|
|
}
|
|
|
|
if (转圈2) {
|
|
auto RootComponent2 = static_cast<UPrimitiveComponent*>(CurrentVehicle2->K2_GetRootComponent());
|
|
RootComponent2->SetAllPhysicsAngularVelocity({0.f, 0.f, -26.5f}, true);
|
|
}
|
|
|
|
// 2. 碰撞控制
|
|
if (无视碰撞开) {
|
|
CurrentVehicle2->SetActorEnableCollision(false);
|
|
} else {
|
|
CurrentVehicle2->SetActorEnableCollision(true);
|
|
}
|
|
|
|
// 3. 重力控制
|
|
if (无视重力开) {
|
|
auto RootComponent3 = static_cast<UPrimitiveComponent*>(CurrentVehicle2->K2_GetRootComponent());
|
|
RootComponent3->SetEnableGravity(false);
|
|
} else {
|
|
auto RootComponent3 = static_cast<UPrimitiveComponent*>(CurrentVehicle2->K2_GetRootComponent());
|
|
RootComponent3->SetEnableGravity(true);
|
|
}
|
|
|
|
// 4. 载具速度控制
|
|
float coeff = (60.0f * 60.0f) * 10.f * 0.01 * 载具速度;
|
|
float coefff = (60.0f * 60.0f) * 10.f * 0.01 * 喇叭高度;
|
|
|
|
FVector vel = {0, 0, 0};
|
|
auto yaw = localController->PlayerCameraManager->CameraCache.POV.Rotation.Yaw;
|
|
bool isMoving = false;
|
|
|
|
// 5. 不同模式的移动控制
|
|
auto CurrentVehicle = localPlayer->GetCurrentVehicle();
|
|
|
|
// 老爷模式(喇叭控制)
|
|
if (老爷模式 && CurrentVehicle->bIsUsingHorn) {
|
|
isMoving = true;
|
|
float theta = 2.f * M_PI * (yaw / 360.f);
|
|
vel.X = (coeff * cosf(theta));
|
|
vel.Y = (coeff * sinf(theta));
|
|
auto RootComponent5 = static_cast<UPrimitiveComponent*>(CurrentVehicle2->K2_GetRootComponent());
|
|
RootComponent5->SetAllPhysicsLinearVelocity(vel, false);
|
|
}
|
|
|
|
// 飞船模式(加速控制)
|
|
if (飞船模式 && CurrentVehicle->bIsBoosting) {
|
|
isMoving = true;
|
|
float theta = 2.f * M_PI * (yaw / 360.f);
|
|
vel.X = (coeff * cosf(theta));
|
|
vel.Y = (coeff * sinf(theta));
|
|
if (喇叭飞天) {
|
|
vel.Z = (coefff * sinf(theta));
|
|
}
|
|
auto RootComponent6 = static_cast<UPrimitiveComponent*>(CurrentVehicle2->K2_GetRootComponent());
|
|
RootComponent6->SetAllPhysicsLinearVelocity(vel, false);
|
|
}
|
|
|
|
// 喇叭飞天模式
|
|
if (喇叭飞天 && CurrentVehicle->bIsUsingHorn) {
|
|
isMoving = true;
|
|
vel.Z = (coefff / 4);
|
|
auto RootComponent7 = static_cast<UPrimitiveComponent*>(CurrentVehicle2->K2_GetRootComponent());
|
|
RootComponent7->SetAllPhysicsLinearVelocity(vel, false);
|
|
}
|
|
|
|
// 载具加速模式
|
|
if (载具加速 && CurrentVehicle->bIsBoosting) {
|
|
isMoving = true;
|
|
float theta = 2.f * M_PI * (yaw / 360.f);
|
|
vel.X = (coeff * cosf(theta));
|
|
vel.Y = (coeff * sinf(theta));
|
|
auto RootComponent8 = static_cast<UPrimitiveComponent*>(CurrentVehicle2->K2_GetRootComponent());
|
|
RootComponent8->SetAllPhysicsLinearVelocity(vel, false);
|
|
}
|
|
|
|
// 6. 停止移动
|
|
if (!isMoving) {
|
|
vel = {0, 0, 0};
|
|
RootComponent->SetAllPhysicsLinearVelocity(vel, true);
|
|
}
|
|
}
|
|
|
|
void DrawESP(ImDrawList* draw, int screenWidth, int screenHeight) {
|
|
if (Config.OTHER.HIDEESP) {
|
|
HIDEESP = false;
|
|
} else {
|
|
HIDEESP = true;
|
|
}
|
|
|
|
if (!HIDEESP) {
|
|
return;
|
|
}
|
|
|
|
auto Actors = getActors();
|
|
int totalEnemies = 0, totalBots = 0, totalMonsters = 0;
|
|
ASTExtraPlayerCharacter* localPlayer = nullptr;
|
|
ASTExtraPlayerController* localController = nullptr;
|
|
|
|
// 1. 查找本地控制器
|
|
for (int i = 0; i < Actors.size(); i++) {
|
|
auto Actor = Actors[i];
|
|
if (isObjectInvalid(Actor)) continue;
|
|
|
|
if (Actor->IsA(ASTExtraPlayerController::StaticClass())) {
|
|
localController = (ASTExtraPlayerController*)Actor;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!localController) return;
|
|
|
|
// 2. 查找本地玩家
|
|
for (int i = 0; i < Actors.size(); i++) {
|
|
auto Actor = Actors[i];
|
|
if (isObjectInvalid(Actor)) continue;
|
|
|
|
if (Actor->IsA(ASTExtraPlayerCharacter::StaticClass())) {
|
|
if (((ASTExtraPlayerCharacter*)Actor)->PlayerKey == localController->PlayerKey) {
|
|
localPlayer = (ASTExtraPlayerCharacter*)Actor;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!localPlayer) return;
|
|
|
|
// 3. 处理所有Actor
|
|
for (int i = 0; i < Actors.size(); i++) {
|
|
auto Actor = Actors[i];
|
|
if (isObjectInvalid(Actor)) continue;
|
|
|
|
// 3.1 处理玩家
|
|
if (Actor->IsA(ASTExtraPlayerCharacter::StaticClass())) {
|
|
auto Player = (ASTExtraPlayerCharacter*)Actor;
|
|
|
|
// 跳过条件检查
|
|
if (ShouldSkipPlayer(Player, localController, localPlayer)) {
|
|
continue;
|
|
}
|
|
|
|
// 检查是否为怪物
|
|
bool isMonster = (Player->bIsAI &&
|
|
(Player->GetName().find("Monster") != std::string::npos ||
|
|
Player->GetName().find("Beast") != std::string::npos ||
|
|
Player->GetName().find("年兽") != std::string::npos));
|
|
|
|
// 更新计数
|
|
if (isMonster) {
|
|
totalMonsters++;
|
|
} else if (Player->bIsAI) {
|
|
totalBots++;
|
|
} else {
|
|
totalEnemies++;
|
|
}
|
|
|
|
// 绘制玩家ESP
|
|
DrawPlayerESP(draw, Player, localPlayer, localController, screenWidth, screenHeight);
|
|
}
|
|
|
|
// 3.2 处理战利品箱
|
|
if (Config.PlayerESP.LootBox && Actor->IsA(APickUpListWrapperActor::StaticClass())) {
|
|
auto LootBox = (APickUpListWrapperActor*)Actor;
|
|
auto RootComponent = Actor->RootComponent;
|
|
if (!RootComponent) continue;
|
|
|
|
float Distance = LootBox->GetDistanceTo(localPlayer) / 100.f;
|
|
FVector2D lootboxPos;
|
|
|
|
if (W2S(LootBox->K2_GetActorLocation(), &lootboxPos)) {
|
|
std::string s = "物资箱 ";
|
|
s += std::to_string((int)Distance);
|
|
s += "m";
|
|
|
|
// 计算文本大小并绘制背景
|
|
auto textSize = ImGui::CalcTextSize(s.c_str());
|
|
float padding = 4.0f;
|
|
ImVec2 bgMin = ImVec2(lootboxPos.X - padding, lootboxPos.Y - padding/2);
|
|
ImVec2 bgMax = ImVec2(lootboxPos.X + textSize.x + padding, lootboxPos.Y + textSize.y + padding/2);
|
|
|
|
draw->AddRectFilled(bgMin, bgMax, ImColor(0, 0, 0, 160), 4.0f);
|
|
draw->AddText(NULL, 16.0f,
|
|
ImVec2(lootboxPos.X, lootboxPos.Y),
|
|
ImColor(255, 204, 0, 240), s.c_str());
|
|
}
|
|
}
|
|
|
|
// 3.3 处理游戏状态(剩余人数)
|
|
if (Config.PlayerESP.剩余人数 && Actor->IsA(ASTExtraGameStateBase::StaticClass())) {
|
|
auto InGame = (ASTExtraGameStateBase*)Actor;
|
|
std::string s = "剩余: " + std::to_string((int)InGame->AlivePlayerNum);
|
|
|
|
// 计算文本大小
|
|
auto textSize = ImGui::CalcTextSize(s.c_str());
|
|
float padding = 8.0f;
|
|
|
|
// iOS风格背景
|
|
ImVec2 bgMin = ImVec2(screenWidth / 2.1f - textSize.x/2 - padding, 245);
|
|
ImVec2 bgMax = ImVec2(screenWidth / 2.1f + textSize.x/2 + padding, 245 + textSize.y + padding);
|
|
|
|
draw->AddRectFilled(bgMin, bgMax, ImColor(0, 0, 0, 180), 8.0f);
|
|
draw->AddRect(bgMin, bgMax, ImColor(255, 255, 255, 80), 8.0f, 0, 1.0f);
|
|
|
|
draw->AddText(nullptr, 20.0f,
|
|
ImVec2(screenWidth / 2.1f - textSize.x/2, 250),
|
|
ImColor(255, 255, 255, 240), s.c_str());
|
|
}
|
|
}
|
|
|
|
// 4. 全局状态显示
|
|
g_LocalController = localController;
|
|
g_LocalPlayer = localPlayer;
|
|
|
|
// 4.1 显示玩家/人机/怪物数量(iOS风格)
|
|
if (人数) {
|
|
// 背景
|
|
ImVec2 bgMin = ImVec2(screenWidth / 1.73f - 220, 35);
|
|
ImVec2 bgMax = ImVec2(screenWidth / 1.73f, 85);
|
|
|
|
draw->AddRectFilled(bgMin, bgMax, ImColor(0, 0, 0, 200), 10.0f);
|
|
draw->AddRect(bgMin, bgMax, ImColor(255, 255, 255, 100), 10.0f, 0, 1.0f);
|
|
|
|
// 文本
|
|
char infoText[256];
|
|
sprintf(infoText, "玩家: %d\n人机: %d\n怪物: %d",
|
|
totalEnemies, totalBots, totalMonsters);
|
|
|
|
draw->AddText(ImVec2(screenWidth / 1.73f - 210, 40),
|
|
ImColor(255, 255, 255, 240), infoText);
|
|
}
|
|
|
|
// 4.2 应用玩家功能
|
|
ApplyPlayerFeatures(localPlayer, localController, screenWidth, screenHeight);
|
|
|
|
// 4.3 应用载具功能
|
|
ApplyVehicleFeatures(localPlayer, localController);
|
|
|
|
// 5. 绘制水印(保持原位置和内容)
|
|
if (水印) {
|
|
// 使用原水印内容和位置
|
|
std::string watermarkText = T("by.脑干\n当前内部测试版-不代表最终品质", "by.SuRanCi\nCurrent internal beta-does not represent final quality");
|
|
|
|
// 原位置:{screenWidth + 200, 650},但需要调整到可见位置
|
|
// 调整为右下角位置
|
|
ImVec2 watermarkPos = ImVec2(screenWidth - 350, screenHeight - 65);
|
|
|
|
// 计算文本大小并绘制背景
|
|
auto textSize = ImGui::CalcTextSize(watermarkText.c_str());
|
|
float padding = 6.0f;
|
|
ImVec2 bgMin = ImVec2(watermarkPos.x - padding, watermarkPos.y - padding);
|
|
ImVec2 bgMax = ImVec2(watermarkPos.x + textSize.x + padding, watermarkPos.y + textSize.y + padding);
|
|
|
|
// iOS风格背景
|
|
draw->AddRectFilled(bgMin, bgMax, ImColor(0, 0, 0, 180), 6.0f);
|
|
draw->AddRect(bgMin, bgMax, ImColor(255, 255, 255, 80), 6.0f, 0, 1.0f);
|
|
|
|
// 绘制文本
|
|
draw->AddText(watermarkPos,
|
|
ImColor(255, 59, 48, 240), // iOS红色
|
|
watermarkText.c_str());
|
|
}
|
|
} |