--- a/rts/Game/WebbarBrowser.h +++ b/rts/Game/WebbarBrowser.h @@ -45,6 +45,7 @@ #include "WebbarShields.h" #include "WebbarCloak.h" #include "WebbarWorkAudio.h" +#include "WebbarEconomy.h" static bool WebbarSupports(const UnitDef* def) { @@ -82,7 +83,7 @@ if (!catalogSent) { catalogSent = true; if (std::getenv("WEBBAR_NETWORK") != nullptr) { static WebbarNetworkResult result; } - MAIN_THREAD_EM_ASM({ if (Module['webbarProtocol']) Module['webbarProtocol'](8, 511 /* restore | shields | cloak | resurrection | native work effects | area resurrection | manual launch | capture | smart trajectory */); }); + MAIN_THREAD_EM_ASM({ if (Module['webbarProtocol']) Module['webbarProtocol'](8, 1023 /* restore | shields | cloak | resurrection | native work effects | area resurrection | manual launch | capture | smart trajectory | energy conversion */); }); MAIN_THREAD_EM_ASM({ if (Module['webbarIdentity']) Module['webbarIdentity']($0, $1, $2, $3); }, gu->myPlayerNum, gu->myTeam, gu->myAllyTeam, int(gu->spectating)); @@ -130,6 +131,7 @@ Module['webbarCommandDescriptions'](units, $2); }, words.data(), words.size(), gs->frameNum); } + PublishWebbarEnergyConversion(); const CTeam* team = teamHandler.Team(gu->myTeam); const float economy[] = {team->res.metal, team->resStorage.metal, team->resPrevIncome.metal, team->resPrevExpense.metal, team->resPrevPull.metal, team->res.energy, team->resStorage.energy, team->resPrevIncome.energy, team->resPrevExpense.energy, team->resPrevPull.energy}; @@ -208,6 +210,8 @@ std::vector ids; if (order.count > 64 || gu->spectating || !playerHandler.IsValidPlayer(gu->myPlayerNum)) { status = 1; + } else if (order.kind == 1010) { + status = SetWebbarEnergyReserve(order.count, order.target, order.options); } else if (order.kind == 1000) { clientNet->Send(CBaseNetProtocol::Get().SendPause(gu->myPlayerNum, order.target != 0)); } else { --- /dev/null +++ b/rts/Game/WebbarEconomy.h @@ -0,0 +1,50 @@ +/* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */ +#pragma once + +#include "Lua/LuaHandle.h" +#include "Lua/LuaRulesParams.h" + +// Codex-assisted local interface to pinned BAR's original energy conversion +// gadget. Read only our team; its synced gadget remains the sole state writer. +static uint32_t ReadWebbarEnergyConversion(float (&values)[4]) +{ + std::fill(std::begin(values), std::end(values), 0.0f); + if (gu->spectating || !teamHandler.IsValidTeam(gu->myTeam)) return 0; + const CTeam* team = teamHandler.Team(gu->myTeam); + const char* names[] = {"mmLevel", "mmCapacity", "mmUse", "mmAvgEffi"}; + uint32_t mask = 0; + for (size_t i = 0; i < 4; ++i) { + const auto it = team->modParams.find(names[i]); + if (it == team->modParams.end() || !(it->second.los & LuaRulesParams::RULESPARAMLOS_PRIVATE_MASK)) continue; + const float* value = std::get_if(&it->second.value); + if (value == nullptr || !std::isfinite(*value) || *value < 0.0f || (i == 0 && *value > 1.0f)) continue; + values[i] = *value; + mask |= 1u << i; + } + return mask; +} + +static void PublishWebbarEnergyConversion() +{ + float values[4]; + const uint32_t mask = ReadWebbarEnergyConversion(values); + if (gu->spectating || !teamHandler.IsValidTeam(gu->myTeam)) return; + MAIN_THREAD_EM_ASM({ + if (Module['webbarEnergyConversion']) Module['webbarEnergyConversion']($0, $1, $2, Array.from(HEAPF32.subarray($3 >> 2, ($3 >> 2) + 4))); + }, gs->frameNum, gu->myTeam, mask, values); +} + +static int SetWebbarEnergyReserve(uint32_t count, uint32_t percent, uint32_t options) +{ + // Match gui_top_bar's ordinary slider limits, not the gadget's wider API. + if (count != 0 || options != 0 || percent < 12 || percent > 88) return 6; + float values[4]; + if (!(ReadWebbarEnergyConversion(values) & 1u)) return 8; + const std::string level = std::to_string(percent); + std::vector message = {137}; + message.insert(message.end(), level.begin(), level.end()); + // Same network path as Spring.SendLuaRulesMsg. The original RecvLuaMsg + // resolves the sender's team and rejects spectators; no team selector exists. + clientNet->Send(CBaseNetProtocol::Get().SendLuaMsg(gu->myPlayerNum, LUA_HANDLE_ORDER_RULES, 0, message)); + return 0; +}