skadistats / clarity

Comically fast Dota 2, CSGO, CS2 and Deadlock replay parser written in Java.
BSD 3-Clause "New" or "Revised" License
661 stars 121 forks source link

team's vision on the mini map? #108

Closed popolikefreedom closed 7 years ago

popolikefreedom commented 8 years ago

Hi, I have a question about team's vision on mini map. Is there a entity tells the vision of a team on mini map?

spheenik commented 8 years ago

Afaik, visibility is computed client side.

There are some entities related to fog of war, CDOTAFogOfWarTempViewers, seems like there's one for each team. I've never researched what they do and how they work, though, and their data changes are much too coarse to reflect the vision.

So, to sum up, it seems that the server does vision computation as well as the client, but there's not much (if any) transmitted in the replay.

popolikefreedom commented 8 years ago

Thanks for your answer, I also found CDOTAFogOfWarTempViewers, but it's properties like X,Y, radias don't match mini map.
So, I have another question, no entity for trees in the dem files?

spheenik commented 8 years ago

There are, named CDOTA_DataRadiant, CDOTA_DataDire, CDOTA_DataSpectator.

Those contain bitfields m_bWorldTreeState.XXXX, which I assume have a bit for each tree there is on the map.

Now, the problem is to find the mapping from tree to bit, for which you have to load the map data and find the mapping. If you ever succeed in doing so, I would appreciate some code that demonstrates this, and I would like to add that functionality to clarity.

Btw: Do you know clarity-analyzer? It's a great tool to browse the data that's available.

popolikefreedom commented 8 years ago

The count of TreeState is 256, but count of trees on the map is over 3000! So the bitfields you said may not represent each tree. I used "clarity-example" and it help me a lot in parsing replays. hah

spheenik commented 8 years ago

But there's 64 bits in every entry, so you have 256*64 = 16384 bits?

popolikefreedom commented 8 years ago

I see, you are right!
Thanks for your help again, I'll try to find the mapping

f0kes commented 9 months ago
private fun onSecond(time: Int) {
        val entities = entitiesProvider.entities ?: return
        for (entity in entities.getAllByPredicate { e -> isEntityProvidingVision(e) }) {
            val team = Team.fromInt(entity.getEntityProperty<Int>("m_iTeamNum") ?: -1)
            val position = entity.getPosition() ?: continue
            val dayVision = entity.getEntityProperty<Int>("m_iDayTimeVisionRange") ?: 0
            val nightVision = entity.getEntityProperty<Int>("m_iNightTimeVisionRange") ?: 0
            val vision = if (isDayTime()) dayVision else nightVision
            val visionRange = vision.toFloat()
            val visionRangeSquared = visionRange * visionRange
            for (heroComponent in heroComponentFactory.retrieveHeroComponents()) {
                val otherTeam = heroComponent.heroModel.team
                if (team == otherTeam) continue
                val otherPosition = heroComponent.heroEntity.getPosition() ?: continue
                if (position.z < otherPosition.z) continue
                val distanceSquared = position.sqrDistance(otherPosition)
                if (distanceSquared <= visionRangeSquared) {
                    heroComponent.heroModel.seenAgo = 0
                    println(
                        "Hero ${stringTableProvider.getEntityName(heroComponent.heroEntity)},pos:${otherPosition} seen by ${
                            stringTableProvider.getEntityName(
                                entity
                            )
                        } (${position})"
                    )
                }
            }
        }
    }

    private fun isEntityProvidingVision(entity: Entity): Boolean {
        val teamInt = entity.getEntityProperty<Int>("m_iTeamNum") ?: return false
        val dayVision = entity.getEntityProperty<Int>("m_iDayTimeVisionRange") ?: return false
        val nightVision = entity.getEntityProperty<Int>("m_iNightTimeVisionRange") ?: return false
        val team = Team.fromInt(teamInt)

        return (team == Team.RADIANT || team == Team.DIRE) && (dayVision > 0 || nightVision > 0)
    }

Sorry for Kotlin, and sorry for some unknown functions, but you can get an idea. We don't know for sure how they calculate fog of war, but this estimation seems pretty good.