Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[10.98] Creatures on screen appears to be dashing/teleporting to next tile when walking #21

Open
GustavoContreiras opened this issue Mar 2, 2019 · 6 comments

Comments

@GustavoContreiras
Copy link

GustavoContreiras commented Mar 2, 2019

Videos

Description
There are 3 big issues on moving animations on client:

  • local player walking and idle animations
  • creatures being pushed diagonally
  • creatures on screen appears to be dashing/teleporting to next tile when walking

The first two can be fixed to work almost like real tibia 10.98, and the fixes are different things.
The third I don't know how to solve.

My guess is that creatures that aren't the local player are being drawn with wrong position or wrong speed and then when the creature reach the next tile position on server side the creature position on client side is refreshed (you can see that Troll's name and health bar teleports too, so its not a problem on skipping frames, its skipping positions) without the sprite reaching it.

I've seen that the information sent from server to client is just the oldPos and the newPos, on client the sprites are rendered using the oldPos + newPos + gettingStepDuration() + totalPixelsWalked (something like that) and I verified the getStepDuration() formula from client sources and server sources and they look almost the same thing... I'm kind of lost here

Edit:
I've counted frames and it looks like 5 frames are being used and then the creature teleports to the next tile and reset to the first frame.

To Reproduce
See monsters or players walking on screen

Expected behavior
A smooth and continuous movement without skipping positions.

Environment

  1. Latest OTClient
  2. Protocol 10.98
  3. Windows 10

Additional context

I fixed the local player walking and idle animation issue using ninjalulz's solution and fixed the pushing diagonal laggy issue (https://i.gyazo.com/412d93e4a799cdc93fd098c04001d7e2.mp4) setting the factor from getStepDuration() (in creature.cpp in client sources) to 1.

@GustavoContreiras
Copy link
Author

GustavoContreiras commented Mar 3, 2019

I think I found the bug.

creature.cpp:

I changed the return value of this function to 80% of the original value.
The factor is commented to solve the pushing diagonal laggy issue.
This line interval = std::ceil(interval / (50 * 1.f)) * 50; uses 50 cause I use TFS 1.3.

int Creature::getStepDuration(bool ignoreDiagonal, Otc::Direction dir)
{
    int speed = m_speed;
    if(speed < 1)
        return 0;

    if(g_game.getFeature(Otc::GameNewSpeedLaw))
        speed *= 2;

    int groundSpeed = 0;
    Position tilePos;

    if(dir == Otc::InvalidDirection)
        tilePos = m_lastStepToPosition;
    else
        tilePos = m_position.translatedToDirection(dir);

    if(!tilePos.isValid())
        tilePos = m_position;
    const TilePtr& tile = g_map.getTile(tilePos);
    if(tile) {
        groundSpeed = tile->getGroundSpeed();
        if(groundSpeed == 0)
            groundSpeed = 150;
    }

    int interval = 1000;
    if(groundSpeed > 0 && speed > 0)
        interval = 1000 * groundSpeed;

    if(g_game.getFeature(Otc::GameNewSpeedLaw) && hasSpeedFormula()) {
        int formulatedSpeed = 1;
        if(speed > -m_speedFormula[Otc::SpeedFormulaB]) {
            formulatedSpeed = std::max<int>(1, (int)floor((m_speedFormula[Otc::SpeedFormulaA] * log((speed / 2)
                 + m_speedFormula[Otc::SpeedFormulaB]) + m_speedFormula[Otc::SpeedFormulaC]) + 0.5));
        }
        interval = std::floor(interval / (double)formulatedSpeed);
    }
    else
        interval /= speed;

    if(g_game.getClientVersion() >= 900)
		interval = std::ceil(interval / (50 * 1.f)) * 50;

    //float factor = 3;
    //if(g_game.getClientVersion() <= 810)
    //    factor = 2;

    //interval = std::max<int>(interval, g_game.getServerBeat());

    //if(!ignoreDiagonal && (m_lastStepDirection == Otc::NorthWest || m_lastStepDirection == Otc::NorthEast ||
    //   m_lastStepDirection == Otc::SouthWest || m_lastStepDirection == Otc::SouthEast))
    //    interval *= factor;

	if (this->isLocalPlayer()) {
		return interval;
	}

    return (int)interval*0.8f;
}

My updateWalkAnimation function based on ninjalulz fix for walking and idle animations

void Creature::updateWalkAnimation(int totalPixelsWalked)
{
    // update outfit animation
    if(m_outfit.getCategory() != ThingCategoryCreature)
        return;

    int footAnimPhases = getAnimationPhases() - 1; //returns 8
    float footDelay = getStepDuration(true) / footAnimPhases; //varies with the g round

    // since mount is a different outfit we need to get the mount animation phases
    if(m_outfit.getMount() != 0) {
        ThingType *type = g_things.rawGetThingType(m_outfit.getMount(), m_outfit.getCategory());
        footAnimPhases = type->getAnimationPhases() - 1;
		footDelay = getStepDuration(true) / footAnimPhases;
    }

	if (totalPixelsWalked >= 32 && !m_walkFinishAnimEvent) {
		m_footStep = 0;

		auto self = static_self_cast<Creature>();
		m_walkFinishAnimEvent = g_dispatcher.scheduleEvent([self] {
			if (!self->m_walking || self->m_walkTimer.ticksElapsed() >= self->getStepDuration(true)) {
				self->m_walkAnimationPhase = 0;
			}
			self->m_walkFinishAnimEvent = nullptr;
		}, std::min<int>(footDelay, 200));
	}

	if (footAnimPhases == 0) {
		m_walkAnimationPhase = 0;
	}
    else if(m_footStepDrawn && m_footTimer.ticksElapsed() >= footDelay && totalPixelsWalked < 32) {
        m_footStep++;
		m_walkAnimationPhase = (m_footStep % footAnimPhases);
        m_footStepDrawn = false;
        m_footTimer.restart();
    }
	else if(m_walkAnimationPhase == 0 && totalPixelsWalked < 32) {
		m_walkAnimationPhase = (m_footStep % footAnimPhases);
    }
}

Videos
https://streamable.com/2gq1h
https://streamable.com/j679m

Conclusion
Client creature speed values are treated different from server creature speed values or the getStepDuration is wrong on client or server sources.

@dudantas
Copy link

@GustavoContreiras I tested, and it was perfect! Thank you very much, brother, for sharing the content. For more people like you! Thanks!!!

@nekiro
Copy link
Member

nekiro commented Apr 28, 2020

Hey, nice that you found a fix, is that related to #45?
If not, can you please submit pull request with your fixes so we can review them?

@GustavoContreiras
Copy link
Author

Hey, nice that you found a fix, is that related to #45?
If not, can you please submit pull request with your fixes so we can review them?

I think it's related.
I'm not coding for OTClient has more then 1 year.. you're free to make the commit with my fix

@vfjpl
Copy link

vfjpl commented Apr 30, 2020

for me it's a little suspicious that we always getStepDuration(true) ignore diagonal when we calculate animation speed.

Anyway I don't think that updateWalkAnimation is related to the non smooth diagonal movement. At least it shouldn't. After all it only decides which part of the sprite to show, not where on the screen it should be. If position update is somehow related to animation frames, then something else is wrong.

int footAnimPhases = getAnimationPhases() - 1; //returns 8
That's not true. It can return 1, any even number between 2 and 8 maybe more. And also 0 for some broken things.

@vfjpl
Copy link

vfjpl commented May 19, 2020

@nekiro #50

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants