1
0
mirror of https://github.com/0O0o0oOoO00/Alas.git synced 2026-05-14 11:19:26 +08:00

add: auto retire

This commit is contained in:
0O0o0oOoO00
2026-01-22 19:06:27 +08:00
parent a17bc383c7
commit f8ce571512
16 changed files with 371 additions and 4 deletions

View File

@@ -1,5 +1,6 @@
#include "cracker.hpp"
#include <ranges>
#include <lua/lua.hpp>
#include <spdlog/spdlog.h>
#include <sol/as_args.hpp>
@@ -326,6 +327,14 @@ void Cracker::disable_all() {
disable_auto_once_again();
}
void Cracker::enable_auto_retire() {
ENABLE(AUTO_RETIRE);
}
void Cracker::disable_auto_retire() {
DISABLE(AUTO_RETIRE);
}
void Cracker::enable_auto_once_again() {
ENABLE(AUTO_ONCE_AGAIN);
}
@@ -742,6 +751,28 @@ void Cracker::load_lua_resources() {
m_lua_res.Ship_ENERGY_LOW = m_state["Ship"]["ENERGY_LOW"];
m_lua_res.BaseUI_closeView = m_state["BaseUI"]["closeView"];
m_lua_res.LevelMediator2_ON_RETRACKING = m_state["LevelMediator2"]["ON_RETRACKING"];
m_lua_res.PlayerProxy = m_state["PlayerProxy"];
m_lua_res.BayProxy = m_state["BayProxy"];
m_lua_res.GAME_DESTROY_SHIPS = m_state["GAME"]["DESTROY_SHIPS"];
m_lua_res.Proxy_getData = m_state["pm"]["Proxy"]["getData"];
m_lua_res.Ship_calReturnRes = m_state["Ship"]["calReturnRes"];
m_lua_res.Player_GoldMax = m_state["Player"]["GoldMax"];
m_lua_res.Player_OilMax = m_state["Player"]["OilMax"];
m_lua_res.pg_m02 = m_state["pg"]["m02"];
m_lua_res.pg_m02_sendNotification = m_state["pg"]["m02"]["sendNotification"];
m_lua_res.BayProxy_getShips = m_state["BayProxy"]["getShips"];
m_lua_res.Ship_isMaxStar = m_state["Ship"]["isMaxStar"];
m_lua_res.Ship_getGroupId = m_state["Ship"]["getGroupId"];
m_lua_res.Ship_getMaxStar = m_state["Ship"]["getMaxStar"];
m_lua_res.Ship_getStar = m_state["Ship"]["getStar"];
m_lua_res.Ship_LOCK_STATE_UNLOCK = m_state["Ship"]["LOCK_STATE_UNLOCK"];
m_lua_res.Ship_LOCK_STATE_LOCK = m_state["Ship"]["LOCK_STATE_LOCK"];
m_lua_res.Ship_GetLockState = m_state["Ship"]["GetLockState"];
m_lua_res.Ship_getRarity = m_state["Ship"]["getRarity"];
m_lua_res.Ship_getFlag = m_state["Ship"]["getFlag"];
m_lua_res.BayProxy_findShipsByGroup = m_state["BayProxy"]["findShipsByGroup"];
m_lua_res._map = m_state["_"]["map"];
m_lua_res._select = m_state["_"]["select"];
SPDLOG_INFO("Load lua functions");
m_original.GetBattleCheckResult = m_state["GetBattleCheckResult"];
@@ -963,13 +994,31 @@ void Cracker::hook_all_lua_functions() {
// skip_ship_gain_show
m_state["NewBattleResultDisplayAwardPage"]["ShowShips"] = [this](sol::this_state L, Lua::VariadicArgs args) {
CALLED(NewBattleResultDisplayAwardPage.ShowShips);
if (!IS_ENABLED(SKIP_SHIP_GAIN_SHOW)) {
auto enabled_SKIP_SHIP_GAIN_SHOW = IS_ENABLED(SKIP_SHIP_GAIN_SHOW);
auto enabled_AUTO_RETIRE = IS_ENABLED(AUTO_RETIRE);
if (!enabled_SKIP_SHIP_GAIN_SHOW && !enabled_AUTO_RETIRE) {
m_original.NewBattleResultDisplayAwardPage_ShowShips(L, args);
return;
}
Lua::Function callback = args[2];
callback(L);
if (enabled_SKIP_SHIP_GAIN_SHOW) {
Lua::Function callback = args[2];
callback(L);
}
if (enabled_AUTO_RETIRE) {
Lua::Object retire_timer = m_lua_res.Timer_New(L, [this](sol::this_state l, Lua::VariadicArgs ags) {
std::optional<Lua::Object> playerProxy = m_lua_res.getProxy(l, m_lua_res.PlayerProxy);
std::optional<Lua::Object> bayProcy = m_lua_res.getProxy(l, m_lua_res.BayProxy);
if (playerProxy.has_value() && playerProxy->get_type() != sol::type::nil && bayProcy.has_value() && bayProcy->get_type() != sol::type::nil) {
execute_retire_ship(l, ags);
}
}, 1.5, 1);
m_lua_res.Timer_Start(L, retire_timer);
}
};
m_state["BaseUI"]["emit"] = [this](sol::this_state L, Lua::VariadicArgs args) {
@@ -1576,6 +1625,171 @@ void Cracker::better_global_speedup_set_rate(double rate) {
}
}
bool Cracker::is_valid_ship(const Lua::Object& obj) {
if (obj.get_type() != sol::type::table) {
return false;
}
if (!obj.as<sol::table>().get<std::optional<int>>("configId").has_value()) {
return false;
}
return true;
}
Lua::Table Cracker::filter_ship(sol::this_state& l, Lua::VariadicArgs& args) {
Lua::Object bayProxy = m_lua_res.getProxy(l, m_lua_res.BayProxy);
auto maxStarGroup = Lua::Table(l);
auto upgradeRequirements = std::map<int, int>();
Lua::Table ships = m_lua_res.BayProxy_getShips(l, bayProxy);
ships.for_each([&](const Lua::Object& key, const Lua::Object& value) {
bool isMaxStar = m_lua_res.Ship_isMaxStar(l, value);
int groupId = m_lua_res.Ship_getGroupId(l, value);
if (isMaxStar) {
maxStarGroup[groupId] = true;
} else {
int maxStar = m_lua_res.Ship_getMaxStar(l, value);
int star = m_lua_res.Ship_getStar(l, value);
int lockState = m_lua_res.Ship_GetLockState(l, value);
auto require = maxStar - star + 1;
if (lockState == m_lua_res.Ship_LOCK_STATE_UNLOCK) {
require++;
}
upgradeRequirements[groupId] = std::min(require, upgradeRequirements.contains(groupId) ? upgradeRequirements[groupId] : 999);
}
});
auto filter = [&](sol::this_state, Lua::Object value) {
Lua::Table ship = value;
int configId = ship["configId"];
if (std::ranges::find(s_excludedShips, configId) != s_excludedShips.end()) {
return false;
}
if (configId == 100001 || configId == 100011 || configId == 100021) {
return false;
}
int lockState = m_lua_res.Ship_GetLockState(l, ship);
if (lockState == m_lua_res.Ship_LOCK_STATE_LOCK) {
return false;
}
int rarity = m_lua_res.Ship_getRarity(l, ship);
bool rarityMatched = false;
auto rarityIt = std::ranges::find(s_shipRarityId, rarity);
if (rarityIt != s_shipRarityId.end()) {
rarityMatched = true;
}
if (!rarityMatched) {
return false;
}
// Don't retire SSR and RN ships
if (rarity >= 5) {
return false;
}
for (const auto& status: s_shipStatus) {
bool forbidden = m_lua_res.Ship_getFlag(l, ship, status);
if (forbidden) {
return false;
}
}
return true;
};
Lua::Table candidate = m_lua_res._select(l, ships, filter);
/*
* According to the original Lua cheating code, it should work properly.
* But in reality it will cause duplicate addition of ship IDs.
* Don't know why.
*/
// auto final = Lua::Table(l);
// auto groupRetireNumber = std::map<int, int>();
// candidate.for_each([&](const Lua::Object& key, const Lua::Object& value) {
// if (!is_valid_ship(value)) {
// return;
// }
// int groupId = m_lua_res.Ship_getGroupId(l, value);
// if (!groupRetireNumber.contains(groupId)) {
// groupRetireNumber[groupId] = 1;
// } else {
// groupRetireNumber[groupId]++;
// }
// });
//
// for (const auto& groupId: groupRetireNumber | std::views::keys) {
// Lua::Table bayGroup = m_lua_res.BayProxy_findShipsByGroup(l, bayProxy, groupId);
// int bayGroupTotal = bayGroup.size();
// int maxToRetire = std::max(0, bayGroupTotal - 1);
//
// int hasAdded = 0;
// candidate.for_each([&](const Lua::Object& key, const Lua::Object& value) {
// if (!is_valid_ship(value)) {
// return;
// }
// Lua::Table ship = value;
// int shipGroupId = m_lua_res.Ship_getGroupId(l, ship);
// if (shipGroupId == groupId) {
// if (hasAdded < maxToRetire) {
// final.add(ship);
// hasAdded++;
// }
// }
// });
// }
// return final;
return candidate;
}
void Cracker::execute_retire_ship(sol::this_state& l, Lua::VariadicArgs& args) {
Lua::Object playerProxy = m_lua_res.getProxy(l, m_lua_res.PlayerProxy);
Lua::Object bayProxy = m_lua_res.getProxy(l, m_lua_res.BayProxy);
auto ships = filter_ship(l, args);
if (ships.empty()) {
return;
}
Lua::Object player = m_lua_res.Proxy_getData(l, playerProxy);
auto totalCoin = 0;
auto totalOil = 0;
ships.for_each([&](const Lua::Object& key, const Lua::Object& value) {
if (!is_valid_ship(value)) {
return;
}
std::tuple<int, int, Lua::Object> returnRes = m_lua_res.Ship_calReturnRes(l, value);
totalCoin += std::get<0>(returnRes);
totalOil += std::get<1>(returnRes);
});
std::optional<bool> triggeredCoinMax = m_lua_res.Player_GoldMax(l, player, totalCoin);
if (triggeredCoinMax.has_value() && triggeredCoinMax.value()) {
return;
}
std::optional<bool> triggeredOilMax = m_lua_res.Player_OilMax(l, player, totalOil);
if (triggeredOilMax.has_value() && triggeredOilMax.value()) {
return;
}
Lua::Table shipId = m_lua_res._map(l, ships, [](sol::this_state, Lua::Object value) {
int id = value.as<Lua::Table>()["id"];
return id;
});
auto params = Lua::Table(l);
params["destroyEquipment"] = true;
params["shipIds"] = shipId;
SPDLOG_INFO("Retire {} ships", shipId.size());
m_lua_res.pg_m02_sendNotification(l, m_lua_res.pg_m02, m_lua_res.GAME_DESTROY_SHIPS, params);
}
void Cracker::better_global_speedup_set_rate_with_pause(double rate) {
m_lua_state_pauser.do_when_paused([&]() {
m_state["ys"]["Battle"]["BattleConfig"]["BASIC_TIME_SCALE"] = rate;
@@ -1623,6 +1837,7 @@ Cracker::Config Cracker::get_config() {
SET_CONFIG_FLAG(INFINITE_BATTLE),
SET_CONFIG_FLAG(SKIP_AIR_STRIKE_ANIMATION),
SET_CONFIG_FLAG(AUTO_ONCE_AGAIN),
SET_CONFIG_FLAG(AUTO_RETIRE),
},
.globle_ship_properties = m_globle_ship_properties,
.global_speedup_rate = static_cast<int>(m_global_speedup_rate),
@@ -1637,6 +1852,12 @@ Cracker::Config Cracker::get_config() {
#define IS_CONFIG_ENABLED(n) config.flag.n
void Cracker::apply_config(Config& config) {
if(IS_CONFIG_ENABLED(AUTO_RETIRE)) {
enable_auto_retire();
} else {
disable_auto_retire();
}
if(IS_CONFIG_ENABLED(AUTO_ONCE_AGAIN)) {
enable_auto_once_again();
} else {
@@ -2272,3 +2493,47 @@ void Cracker::clear_hard_mode_ship_properties_limit(Lua::Table& t) {
}
}
}
std::vector<std::string> Cracker::s_shipStatus = {
"inFleet",
"inChapter",
"inWorld",
"inEvent",
"inBackyard",
"inClass",
"inTactics",
"inExercise",
"inAdmiral",
"inElite",
"inActivity",
"inGuildEvent",
"inGuildBossEvent",
};
std::vector<int> Cracker::s_excludedShips = {
900493,
900494,
900495,
9702091,
9702092,
9702093,
9702094,
};
std::vector<int> Cracker::s_shipRarityId = {
0,
2,
3,
4,
5,
6,
};
std::map<std::string_view, int> Cracker::s_shipRarityNameToId = {
{"", 0},
{"N", 2},
{"R", 3},
{"SR", 4},
{"SSR", 5},
{"RN", 6},
};

View File

@@ -119,6 +119,7 @@ public:
bool INFINITE_BATTLE = false;
bool SKIP_AIR_STRIKE_ANIMATION = false;
bool AUTO_ONCE_AGAIN = false;
bool AUTO_RETIRE = false;
} flag;
ShipProperties globle_ship_properties;
int global_speedup_rate = 1;
@@ -155,6 +156,9 @@ public:
void disable_all();
void enable_auto_retire();
void disable_auto_retire();
void enable_auto_once_again();
void disable_auto_once_again();
@@ -306,6 +310,10 @@ private:
void better_global_speedup_set_rate(double rate);
static bool is_valid_ship(const Lua::Object& obj);
Lua::Table filter_ship(sol::this_state& l, Lua::VariadicArgs& args);
void execute_retire_ship(sol::this_state& l, Lua::VariadicArgs& args);
static void modify_ship_properties(Lua::Table& properties, const ShipProperties& new_properties);
static void clear_hard_mode_ship_properties_limit(Lua::Table& t);
@@ -341,6 +349,7 @@ private:
std::atomic<bool> INFINITE_BATTLE = false;
std::atomic<bool> SKIP_AIR_STRIKE_ANIMATION = false;
std::atomic<bool> AUTO_ONCE_AGAIN = false;
std::atomic<bool> AUTO_RETIRE = false;
} m_flag;
struct {
@@ -434,6 +443,28 @@ private:
int Ship_ENERGY_LOW;
Lua::Function BaseUI_closeView;
std::string LevelMediator2_ON_RETRACKING;
Lua::Object PlayerProxy;
Lua::Object BayProxy;
std::string GAME_DESTROY_SHIPS;
Lua::Function Proxy_getData;
Lua::Function Ship_calReturnRes;
Lua::Function Player_GoldMax;
Lua::Function Player_OilMax;
Lua::Object pg_m02;
Lua::Function pg_m02_sendNotification;
Lua::Function BayProxy_getShips;
Lua::Function Ship_isMaxStar;
Lua::Function Ship_getGroupId;
Lua::Function Ship_getMaxStar;
Lua::Function Ship_getStar;
int Ship_LOCK_STATE_UNLOCK;
int Ship_LOCK_STATE_LOCK;
Lua::Function Ship_GetLockState;
Lua::Function Ship_getRarity;
Lua::Function Ship_getFlag;
Lua::Function BayProxy_findShipsByGroup;
Lua::Function _map;
Lua::Function _select;
} m_lua_res;
struct {
@@ -464,6 +495,11 @@ private:
std::atomic<bool> m_better_global_speedup_need_pause = false;
std::atomic<bool> m_skip_battle_celebrate_need_pause = false;
std::atomic<bool> m_fast_stage_move_need_pause = false;
static std::vector<std::string> s_shipStatus;
static std::vector<int> s_excludedShips;
static std::vector<int> s_shipRarityId;
static std::map<std::string_view, int> s_shipRarityNameToId;
};
#endif //CRACKER_HPP

View File

@@ -1256,6 +1256,28 @@ CrackerServer::CrackerServer() {
CRACK_OK();
});
Post("/enable_auto_retire", [](const httplib::Request& req, httplib::Response& res) {
try {
Cracker::Instance().enable_auto_retire();
} catch (std::exception& e) {
SPDLOG_ERROR("Enable auto retire failed: {}", e.what());
res.status = 500;
return;
}
CRACK_OK();
});
Post("/disable_auto_retire", [](const httplib::Request& req, httplib::Response& res) {
try {
Cracker::Instance().disable_auto_retire();
} catch (std::exception& e) {
SPDLOG_ERROR("Disable auto retire failed: {}", e.what());
res.status = 500;
return;
}
CRACK_OK();
});
Post("/init", [](const httplib::Request& req, httplib::Response& res) {
try {
Cracker::Instance();

View File

@@ -162,6 +162,7 @@ void CrackerUI::draw_menu() {
ImGui::Checkbox("章节图自动开荒", &CONFIG_FLAG(CHAPTER_AUTO_CLEAR));
ImGui::Checkbox("无限连战", &CONFIG_FLAG(INFINITE_BATTLE));
ImGui::Checkbox("自动再次前往", &CONFIG_FLAG(AUTO_ONCE_AGAIN));
ImGui::Checkbox("自动退役", &CONFIG_FLAG(AUTO_RETIRE));
ImGui::EndTable();
}

View File

@@ -233,7 +233,8 @@
"SkipStory": false,
"InfiniteBattle": false,
"SkipAirStrikeAnimation": false,
"AutoOnceAgain": false
"AutoOnceAgain": false,
"AutoRetire": false
},
"ShipProperty": {
"Method": "disable",

View File

@@ -929,6 +929,10 @@
"AutoOnceAgain": {
"type": "checkbox",
"value": false
},
"AutoRetire": {
"type": "checkbox",
"value": false
}
},
"ShipProperty": {

View File

@@ -899,6 +899,7 @@ Misc:
InfiniteBattle: false
SkipAirStrikeAnimation: false
AutoOnceAgain: false
AutoRetire: false
# ==================== Cheat ====================
PowerLimit:

View File

@@ -554,6 +554,7 @@ class GeneratedConfig:
Misc_InfiniteBattle = False
Misc_SkipAirStrikeAnimation = False
Misc_AutoOnceAgain = False
Misc_AutoRetire = False
# Group `PowerLimit`
PowerLimit_Enable = True

View File

@@ -167,6 +167,7 @@ class FullGeneratedConfig:
Hook_Misc_InfiniteBattle = None
Hook_Misc_SkipAirStrikeAnimation = None
Hook_Misc_AutoOnceAgain = None
Hook_Misc_AutoRetire = None
Hook_ShipProperty_Method = None
Hook_ShipProperty_Factor = None
Hook_ShipProperty_Armor = None

View File

@@ -3185,6 +3185,10 @@
"AutoOnceAgain": {
"name": "Misc.AutoOnceAgain.name",
"help": "Misc.AutoOnceAgain.help"
},
"AutoRetire": {
"name": "Misc.AutoRetire.name",
"help": "Misc.AutoRetire.help"
}
},
"PowerLimit": {

View File

@@ -3185,6 +3185,10 @@
"AutoOnceAgain": {
"name": "Misc.AutoOnceAgain.name",
"help": "Misc.AutoOnceAgain.help"
},
"AutoRetire": {
"name": "Misc.AutoRetire.name",
"help": "Misc.AutoRetire.help"
}
},
"PowerLimit": {

View File

@@ -3185,6 +3185,10 @@
"AutoOnceAgain": {
"name": "自动再次前往",
"help": ""
},
"AutoRetire": {
"name": "自动退役",
"help": "注意:该功能存在风险,开启前请确保船是锁上的!!!"
}
},
"PowerLimit": {

View File

@@ -3185,6 +3185,10 @@
"AutoOnceAgain": {
"name": "Misc.AutoOnceAgain.name",
"help": "Misc.AutoOnceAgain.help"
},
"AutoRetire": {
"name": "Misc.AutoRetire.name",
"help": "Misc.AutoRetire.help"
}
},
"PowerLimit": {

View File

@@ -416,6 +416,12 @@ class CrackApi:
def disable_auto_once_again(self):
self.post("disable_auto_once_again")
def enable_auto_retire(self):
self.post("enable_auto_retire")
def disable_auto_retire(self):
self.post("disable_auto_retire")
def init(self):
self.post("init")

View File

@@ -48,6 +48,7 @@ ALL_ENABLE_OPS = [
CrackOp.EnableInfiniteBattle,
CrackOp.EnableSkipAirStrikeAnimation,
CrackOp.EnableAutoOnceAgain,
CrackOp.EnableAutoRetire,
]
REMOTE_PORT = 23897
@@ -349,6 +350,11 @@ def do_crack_op(config: AzurLaneConfig, device: Device, ops: Union[Type[CrackOp.
api.enable_auto_once_again()
elif op == CrackOp.DisableAutoOnceAgain:
api.disable_auto_once_again()
elif op == CrackOp.EnableAutoRetire:
if full_config.Hook_Misc_AutoRetire:
api.enable_auto_retire()
elif op == CrackOp.DisableAutoRetire:
api.disable_auto_retire()
else:
logger.error(f"Unsupported op: {op}")
@@ -410,6 +416,7 @@ CHAPTER_CRACK_OPS = [
CrackOp.EnableInfiniteBattle,
CrackOp.EnableSkipAirStrikeAnimation,
CrackOp.EnableAutoOnceAgain,
CrackOp.EnableAutoRetire,
]

View File

@@ -196,3 +196,9 @@ class CrackOp:
class DisableAutoOnceAgain(Op):
...
class EnableAutoRetire(Op):
...
class DisableAutoRetire(Op):
...