Blizzard / s2client-api

StarCraft II Client - C++ library supported on Windows, Linux and Mac designed for building scripted bots and research using the SC2API.
MIT License
1.66k stars 281 forks source link

[Help] Can't build on vespene geyser #257

Closed thehatb0y closed 6 years ago

thehatb0y commented 6 years ago

Hello i'm trying to build refinery on vespene but i've no idea why it's not working, if some one could help i would appreciate.

Here's a function wich give a exact position of Vespene Geyser .

            if (CountUnitType(UNIT_TYPEID::TERRAN_REFINERY) == 0) {
                Point3D Location;
                Location.x = 19.5;
                Location.y = 122.5;
                Location.z = 12;
                return Location;
            }

And Here's a function wich ask to build the Refinery

        Actions()->UnitCommand(unit_to_build, ABILITY_ID::BUILD_REFINERY, Gas());

But some how the svc can't find the way to build giving the alert " Can't place, locaton invalid "

alkurbatov commented 6 years ago

Hi @azshalasa Try to pass a pointer to a geiser unit instead of a 3d point.

thehatb0y commented 6 years ago

Tx for reply @alkurbatov ! i'm not sure if i understood what to do... You mean a pointer to Point3D ?

Even functions like that are not working properly

    const Unit* FindNearestVespenelPatch(const Point3D& start) {
        Units units = Observation()->GetUnits(Unit::Alliance::Neutral);
        float distance = std::numeric_limits<float>::max();
        const Unit* target = nullptr;
        for (const auto& u : units) {
            if (u->unit_type == UNIT_TYPEID::NEUTRAL_VESPENEGEYSER) {
                std::cout << u->pos.x << std::endl;
                std::cout << u->pos.y << std::endl;
                float d = DistanceSquared3D(u->pos, start);
                if (d < distance) {
                    distance = d;
                    target = u;
                }
            }
        }

        return target;
    }

    const Unit* FindNearestCC(const Point2D& start) {
        Units units = Observation()->GetUnits(Unit::Alliance::Neutral);
        float distance = std::numeric_limits<float>::max();
        const Unit* target = nullptr;
        for (const auto& u : units) {
            if (u->unit_type == UNIT_TYPEID::TERRAN_COMMANDCENTER) {
                float d = DistanceSquared2D(u->pos, start);
                if (d < distance) {
                    distance = d;
                    target = u;
                }
            }
        }
        return target;
    }

With the functions above(FindNearest stuff), SCV are acting like crazy, looking for far mining places and wrong gaiser... So FindNearest Stuff are not working and neither my specific functions wich tells exact where to build. invalid_path2

I've got a similar function to build Depos wich are working 100%

            if (CountUnitType(UNIT_TYPEID::TERRAN_SUPPLYDEPOT) > 1) {
                if (CountUnitType(UNIT_TYPEID::TERRAN_SUPPLYDEPOT) > 1 && CountUnitType(UNIT_TYPEID::TERRAN_SUPPLYDEPOT) <= 8) {
                    Point3D Location;
                    Location.x = (float)138.0 + (float)(CountUnitType(UNIT_TYPEID::TERRAN_SUPPLYDEPOT) * 2);
                    Location.y = 32.0;
                    Location.z = 12;
                    return Location;
                }
                if (CountUnitType(UNIT_TYPEID::TERRAN_SUPPLYDEPOT) > 8 && CountUnitType(UNIT_TYPEID::TERRAN_SUPPLYDEPOT) <= 14) {
                    Point3D Location;
                    Location.x = (float)124.0 + (float)(CountUnitType(UNIT_TYPEID::TERRAN_SUPPLYDEPOT) * 2);
                    Location.y = 30.0;
                    Location.z = 12;
                    return Location;
                }
                if (CountUnitType(UNIT_TYPEID::TERRAN_SUPPLYDEPOT) > 14 && CountUnitType(UNIT_TYPEID::TERRAN_SUPPLYDEPOT) <= 16) {
                    Point3D Location;
                    Location.x = (float)112.0 + (float)(CountUnitType(UNIT_TYPEID::TERRAN_SUPPLYDEPOT) * 2);
                    Location.y = 28.0;
                    Location.z = 12;
                    return Location;
                }
            }

sem titulo

alkurbatov commented 6 years ago

Take a look at examples from the API's sources (bool TerranMultiplayerBot::BuildRefinery() ): https://github.com/Blizzard/s2client-api/blob/master/examples/common/bot_examples.cc

Usually, you should find the nearest mineral or vesper geyser (these are neutral units on the map), use the unit found as a target for the 'build' command instead of a point.

Another example: https://github.com/alkurbatov/suvorov-bot/blob/master/src/blueprints/Refinery.cpp

alkurbatov commented 6 years ago

Ah, suddenly I've remembered. I've used the example from the API (with location point) and it failed to build a refinery. Then I've switched to another solution, you can see it in my bot's sources.

So the following advice should help:

Usually, you should find the nearest mineral or vesper geyser (these are neutral units on the map), use the unit found as a target for the 'build' command instead of a point.

thehatb0y commented 6 years ago

@alkurbatov Thanks alot! I think i can solve the problem but i'll ask to keep this issue open util i check that, prob todady at night i'll back to code again.

thehatb0y commented 6 years ago

Actually nearest mineral or nearest vespene are pointing SCVs to the wrong way. When some SCV finish something and get iddle he's sent to findnearestminerals and mine there, but for some reason he's getting wrong mineral and gaiser, and i already tryed to push them to CC before getting iddle, no sucess.

That's explain why my pointers are not working properly ~~maybe. iddle ~

Here's a iddle function:

        case UNIT_TYPEID::TERRAN_SCV: {
            const Unit* cc_target = FindNearestCC(unit->pos);
            const Unit* mineral_target = FindNearestMineralPatch(unit->pos);
            if (!mineral_target) {
                break;
            }
            Actions()->UnitCommand(unit, ABILITY_ID::SMART, cc_target);
            Actions()->UnitCommand(unit, ABILITY_ID::SMART, mineral_target);
            break;
        }

Heres Nearest Vespene

const Unit FindNearestVespenelPatch(const Point3D& start) { Units units = Observation()->GetUnits(Unit::Alliance::Neutral); float distance = std::numeric_limits::max(); const Unit target = nullptr; for (const auto& u : units) { if (u->unit_type == UNIT_TYPEID::NEUTRAL_VESPENEGEYSER) { std::cout << u->pos.x << std::endl; std::cout << u->pos.y << std::endl; float d = DistanceSquared3D(u->pos, start); if (d < distance) { distance = d; target = u; } } }

Heres Nearest Minerals

    const Unit* FindNearestMineralPatch(const Point2D& start) {
        Units units = Observation()->GetUnits(Unit::Alliance::Neutral);
        float distance = std::numeric_limits<float>::max();
        const Unit* target = nullptr;
        for (const auto& u : units) {
            if (u->unit_type == UNIT_TYPEID::NEUTRAL_MINERALFIELD) {
                float d = DistanceSquared2D(u->pos, start);
                if (d < distance) {
                    distance = d;
                    target = u;
                }
            }
        }
        return target;
    }

whyyy

Archiatrus commented 6 years ago

Minerals: There are two flaws in your code. First: why are you looking for a mineral that is closest to the unit position and not cc_target->pos? You don't want the closest mineral to the worker, you want the closest mineral that belongs to the closest cc to the worker. Second: if you issue two commands in the same frame without queuing, the second overrides the first. So the move command to the cc will never be used. Anyway, you don't need to queue. Just look for the right closest mineral.

Gas: You could also here use a cc position rather than a worker position as start. You just need to make sure that the gas positions are not already occupied for the cc.

(Sry I'm at my phone so no nice formating.)

Archiatrus commented 6 years ago

One thing I forgot to mention: keep in mind that there are different types if mineral/gas. On some maps your functions won't find minerals/gas because you are only looking for one specific type. See type enums for the others.

alkurbatov commented 6 years ago

By the way, is there any simple approach to identify that the gas positions are not already occupied (i.e. without additional memory and comparison of refineries with vespene points)?

thehatb0y commented 6 years ago

@Archiatrus Minerals:

There are two flaws in your code. First: why are you looking for a mineral that is closest to the unit.....

R: I was trying to send SCV to CC before start to find for nearest minerals, to check if SCV would try some distant mine. Already fixed that.

One thing I forgot to mention: keep in mind that there are different types if mineral/gas. On some maps your functions won't find minerals/gas because you are only looking for one specific type. See type enums for the others.

R: That post was the key to solve the problem, since Geyser on plataform are named NEUTRAL_SPACEPLATFORMGEYSER instead of NEUTRAL_VESPENEGEYSER, just like the minerals.

So the problem is solved, but i'll ask to keep that issue open just a little more, i'll close by my self when i feel confident.

thehatb0y commented 6 years ago

Ok, thx to @alkurbatov and @Archiatrus all problems are fixed and i'll close the issue. If somebody are facing some problem related just feel free to inbox me any time.