Skip to content

Commit

Permalink
Feature: register new lua function DrawBuildSquare to show build sq…
Browse files Browse the repository at this point in the history
…uares on custom building commands
  • Loading branch information
Aurelien Lambert committed Oct 20, 2024
1 parent 19b0efc commit 2c68170
Show file tree
Hide file tree
Showing 5 changed files with 247 additions and 2 deletions.
49 changes: 49 additions & 0 deletions rts/Lua/LuaUnsyncedCtrl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ bool LuaUnsyncedCtrl::PushEntries(lua_State* L)
REGISTER_LUA_CFUNC(AddWorldUnit);

REGISTER_LUA_CFUNC(DrawUnitCommands);
REGISTER_LUA_CFUNC(DrawBuildSquare);

REGISTER_LUA_CFUNC(SetTeamColor);

Expand Down Expand Up @@ -3382,6 +3383,54 @@ int LuaUnsyncedCtrl::SetBuildFacing(lua_State* L)
}


/***
*
* @function Spring.DrawBuildSquare
* @tparam {number,...} unitArray
* @tparam {cmdSpec,...} cmdArray
* @treturn {bool,...} canBuild
*/
int LuaUnsyncedCtrl::DrawBuildSquare(lua_State* L)
{
vector<int> unitIDs;
ParseUnitArray(L, __func__, 1, unitIDs);

vector<Command> commands;
LuaUtils::ParseCommandArray(L, __func__, 2, commands);

vector<bool> canBuildVector(commands.size());

bool isQueued = !commands.empty() && (commands[0].GetOpts() & SHIFT_KEY);
vector<Command> conflicting;

for (int i=0; i<commands.size(); i++) {
Command cmd = commands[i];
if (cmd.GetID() >= 0) continue;

if (isQueued) {
conflicting.clear();
for (const int unitID: unitIDs) {
const CUnit* su = unitHandler.GetUnit(unitID);
const CCommandAI* cai = su->commandAI;
vector<Command> overlap = cai->GetOverlapQueued(cmd);
conflicting.insert(conflicting.end(), overlap.begin(), overlap.end());
}
}

canBuildVector[i] = unitDrawer->AddLuaBuildSquare(BuildInfo(cmd), conflicting);
}

lua_createtable(L, canBuildVector.size(), 0);
for (int i=0; i<canBuildVector.size(); i++) {
lua_pushboolean(L, canBuildVector[i]);
lua_rawseti(L, -2, 1 + i);
}

// TODO push canBuilds
return 1;
}


/******************************************************************************
* UI
* @section ui
Expand Down
1 change: 1 addition & 0 deletions rts/Lua/LuaUnsyncedCtrl.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class LuaUnsyncedCtrl {
static int AddWorldUnit(lua_State* L);

static int DrawUnitCommands(lua_State* L);
static int DrawBuildSquare(lua_State* L);

static int SetTeamColor(lua_State* L);

Expand Down
187 changes: 186 additions & 1 deletion rts/Rendering/Units/UnitDrawer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1183,7 +1183,6 @@ void CUnitDrawerLegacy::DrawIndividualDefAlpha(const SolidObjectDef* objectDef,
bool CUnitDrawerLegacy::ShowUnitBuildSquare(const BuildInfo& buildInfo, const std::vector<Command>& commands) const
{
RECOIL_DETAILED_TRACY_ZONE;
//TODO: make this a lua callin!
glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Expand Down Expand Up @@ -1333,6 +1332,192 @@ bool CUnitDrawerLegacy::ShowUnitBuildSquare(const BuildInfo& buildInfo, const st
return canBuild;
}

bool CUnitDrawerLegacy::AddLuaBuildSquare(const BuildInfo& buildInfo, const std::vector<Command>& commands) {
CFeature* feature = nullptr;

struct BuildCache {
uint64_t key;
int createFrame;
bool canBuild;
std::vector<float3> buildableSquares; // buildable squares
std::vector<float3> featureSquares; // occupied squares
std::vector<float3> illegalSquares; // non-buildable squares
};

static std::vector<BuildCache> buildCache;

const float3& pos = buildInfo.pos;

uint64_t hashKey = spring::LiteHash(pos);
hashKey = spring::hash_combine(spring::LiteHash(buildInfo.buildFacing), hashKey);
/*
for (const auto& cmd : commands) {
const BuildInfo bc(cmd);
spring::hash_combine(spring::LiteHash(bc), hash);
}
*/

// the chosen number here is arbitrary, feel free to fine balance.
static constexpr int CACHE_VALIDITY_PERIOD = GAME_SPEED / 5;
std::erase_if(buildCache, [](const BuildCache& bc) {
return gs->frameNum - bc.createFrame >= CACHE_VALIDITY_PERIOD;
});

const float x1 = std::floor(pos.x - (buildInfo.GetXSize() * 0.5f * SQUARE_SIZE));
const float x2 = x1 + (buildInfo.GetXSize() * SQUARE_SIZE);
const float z1 = std::floor(pos.z - (buildInfo.GetZSize() * 0.5f * SQUARE_SIZE));
const float z2 = z1 + (buildInfo.GetZSize() * SQUARE_SIZE);
const float h = CGameHelper::GetBuildHeight(pos, buildInfo.def, false);

luaBuildPos.push_back(float3{x1, h, z1});
luaBuildPos.push_back(float3{x2, h, z2});

auto buildCacheItem = std::find_if(buildCache.begin(), buildCache.end(), [hashKey](const BuildCache& bc) {
return bc.key == hashKey;
});

if (buildCacheItem == buildCache.end()) {
buildCache.emplace_back();
buildCacheItem = buildCache.end()-1;

buildCacheItem->key = hashKey;
buildCacheItem->createFrame = gs->frameNum;
buildCacheItem->canBuild = CGameHelper::TestUnitBuildSquare(
buildInfo,
feature,
-1,
false,
&buildCacheItem->buildableSquares,
&buildCacheItem->featureSquares,
&buildCacheItem->illegalSquares,
&commands
);
}

bool canBuild = buildCacheItem->canBuild;
if (canBuild) {
luaBuildableSquares.insert(luaBuildableSquares.end(),
buildCacheItem->buildableSquares.begin(),
buildCacheItem->buildableSquares.end());
} else {
luaUnbuildableSquares.insert(luaUnbuildableSquares.end(),
buildCacheItem->buildableSquares.begin(),
buildCacheItem->buildableSquares.end());
}
luaFeatureSquares.insert(luaFeatureSquares.end(),
buildCacheItem->featureSquares.begin(),
buildCacheItem->featureSquares.end());
luaIllegalSquares.insert(luaIllegalSquares.end(),
buildCacheItem->illegalSquares.begin(),
buildCacheItem->illegalSquares.end());

return canBuild;
}

void CUnitDrawerLegacy::ShowLuaBuildSquare() {
if (luaBuildableSquares.empty() && luaUnbuildableSquares.empty() && luaFeatureSquares.empty() && luaIllegalSquares.empty()) {
return;
}

RECOIL_DETAILED_TRACY_ZONE;
glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_TEXTURE_2D);
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

static constexpr std::array<float, 4> buildColorT = { 0.0f, 0.9f, 0.0f, 0.7f };
static constexpr std::array<float, 4> buildColorF = { 0.9f, 0.8f, 0.0f, 0.7f };
static constexpr std::array<float, 4> featureColor = { 0.9f, 0.8f, 0.0f, 0.7f };
static constexpr std::array<float, 4> illegalColor = { 0.9f, 0.0f, 0.0f, 0.7f };

static auto& rb = RenderBuffer::GetTypedRenderBuffer<VA_TYPE_C>();
rb.AssertSubmission();

auto& sh = rb.GetShader();

sh.Enable();

const float* color = &buildColorT[0];
for (const auto& buildableSquare : luaBuildableSquares) {
rb.AddQuadLines(
{ buildableSquare , color },
{ buildableSquare + float3(SQUARE_SIZE, 0, 0 ), color },
{ buildableSquare + float3(SQUARE_SIZE, 0, SQUARE_SIZE), color },
{ buildableSquare + float3(0 , 0, SQUARE_SIZE), color }
);
}

color = &buildColorF[0];
for (const auto& unbuildableSquare : luaUnbuildableSquares) {
rb.AddQuadLines(
{ unbuildableSquare , color },
{ unbuildableSquare + float3(SQUARE_SIZE, 0, 0 ), color },
{ unbuildableSquare + float3(SQUARE_SIZE, 0, SQUARE_SIZE), color },
{ unbuildableSquare + float3(0 , 0, SQUARE_SIZE), color }
);
}

color = &featureColor[0];
for (const auto& featureSquare : luaFeatureSquares) {
rb.AddQuadLines(
{ featureSquare , color },
{ featureSquare + float3(SQUARE_SIZE, 0, 0 ), color },
{ featureSquare + float3(SQUARE_SIZE, 0, SQUARE_SIZE), color },
{ featureSquare + float3(0 , 0, SQUARE_SIZE), color }
);
}

color = &illegalColor[0];
for (const auto& illegalSquare : luaIllegalSquares) {
rb.AddQuadLines(
{ illegalSquare , color },
{ illegalSquare + float3(SQUARE_SIZE, 0, 0 ), color },
{ illegalSquare + float3(SQUARE_SIZE, 0, SQUARE_SIZE), color },
{ illegalSquare + float3(0 , 0, SQUARE_SIZE), color }
);
}
rb.Submit(GL_LINES);

for (int i=0; i<luaBuildPos.size(); i+=2) {
float3 pos1 = luaBuildPos[i];
float3 pos2 = luaBuildPos[i+1];
float x1 = pos1.x, x2 = pos2.x;
float z1 = pos1.z, z2 = pos2.z;
float h = pos1.y;

if (h < 0.0f) {
constexpr uint8_t s[] = { 0, 0, 255, 128 }; // start color
constexpr uint8_t e[] = { 0, 128, 255, 255 }; // end color

rb.AddVertex({ float3(x1, h, z1), s }); rb.AddVertex({ float3(x1, 0.f, z1), e });
rb.AddVertex({ float3(x1, h, z2), s }); rb.AddVertex({ float3(x1, 0.f, z2), e });
rb.AddVertex({ float3(x2, h, z2), s }); rb.AddVertex({ float3(x2, 0.f, z2), e });
rb.AddVertex({ float3(x2, h, z1), s }); rb.AddVertex({ float3(x2, 0.f, z1), e });
rb.Submit(GL_LINES);

rb.AddVertex({ float3(x1, 0.0f, z1), e });
rb.AddVertex({ float3(x1, 0.0f, z2), e });
rb.AddVertex({ float3(x2, 0.0f, z2), e });
rb.AddVertex({ float3(x2, 0.0f, z1), e });
rb.Submit(GL_LINE_LOOP);
}
}

sh.Disable();


glEnable(GL_DEPTH_TEST);
//glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
// glDisable(GL_BLEND);

luaBuildableSquares.clear();
luaUnbuildableSquares.clear();
luaFeatureSquares.clear();
luaIllegalSquares.clear();
luaBuildPos.clear();
}

void CUnitDrawerLegacy::DrawBuildIcons(const std::vector<CCursorIcons::BuildIcon>& buildIcons) const
{
RECOIL_DETAILED_TRACY_ZONE;
Expand Down
11 changes: 10 additions & 1 deletion rts/Rendering/Units/UnitDrawer.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ class CUnitDrawer : public CModelDrawerBase<CUnitDrawerData, CUnitDrawer>
bool ShowUnitBuildSquare(const BuildInfo& buildInfo) const { return ShowUnitBuildSquare(buildInfo, std::vector<Command>()); }
virtual bool ShowUnitBuildSquare(const BuildInfo& buildInfo, const std::vector<Command>& commands) const = 0;

virtual bool AddLuaBuildSquare(const BuildInfo& buildInfo, const std::vector<Command>& commands) = 0;
virtual void ShowLuaBuildSquare() = 0;

virtual void DrawBuildIcons(const std::vector<CCursorIcons::BuildIcon>& buildIcons) const = 0;
protected:
static bool ShouldDrawOpaqueUnit(CUnit* u, uint8_t thisPassMask);
Expand Down Expand Up @@ -144,6 +147,8 @@ class CUnitDrawerLegacy : public CUnitDrawerBase {
void DrawIndividualDefAlpha(const SolidObjectDef* objectDef, int teamID, bool rawState, bool toScreen = false) const override;

bool ShowUnitBuildSquare(const BuildInfo& buildInfo, const std::vector<Command>& commands) const override;
bool AddLuaBuildSquare(const BuildInfo& buildInfo, const std::vector<Command>& commands) override;
void ShowLuaBuildSquare() override;
void DrawBuildIcons(const std::vector<CCursorIcons::BuildIcon>& buildIcons) const override;

void DrawUnitMiniMapIcons() const override;
Expand Down Expand Up @@ -185,7 +190,11 @@ class CUnitDrawerLegacy : public CUnitDrawerBase {
void PopIndividualOpaqueState(const S3DModel* model, int teamID, bool deferredPass) const;
void PopIndividualAlphaState(const S3DModel* model, int teamID, bool deferredPass) const;
protected:

std::vector<float3> luaBuildableSquares;
std::vector<float3> luaUnbuildableSquares;
std::vector<float3> luaFeatureSquares;
std::vector<float3> luaIllegalSquares;
std::vector<float3> luaBuildPos;
};

class CUnitDrawerFFP final : public CUnitDrawerLegacy {};
Expand Down
1 change: 1 addition & 0 deletions rts/Rendering/WorldDrawer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,7 @@ void CWorldDrawer::DrawMiscObjects() const

mouse->DrawSelectionBox();
guihandler->DrawMapStuff(false);
unitDrawer->ShowLuaBuildSquare();

if (globalRendering->drawMapMarks && !game->hideInterface) {
inMapDrawerView->Draw();
Expand Down

0 comments on commit 2c68170

Please sign in to comment.