Skip to content

Commit

Permalink
fix: incorrectly aligned looktypes for 32x32 idle sprites when using …
Browse files Browse the repository at this point in the history
…protobuf

Fix improperly positioned special looktypes that are 32x32 in idle, while 64x64 while walking.

Fix #914
Fix #828
Fix #961
Fix #966
  • Loading branch information
nekiro authored Jan 6, 2025
1 parent 98ef399 commit 52694e8
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 98 deletions.
107 changes: 11 additions & 96 deletions src/client/thingtype.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -285,9 +285,6 @@ void ThingType::unserializeAppearance(const uint16_t clientId, const ThingCatego
m_animationPhases = 0;
int totalSpritesCount = 0;

std::vector<Size> sizes;
std::vector<int> total_sprites;

for (const auto& framegroup : appearance.frame_group()) {
const int frameGroupType = framegroup.fixed_frame_group();
const auto& spriteInfo = framegroup.sprite_info();
Expand All @@ -305,7 +302,6 @@ void ThingType::unserializeAppearance(const uint16_t clientId, const ThingCatego

if (const auto& sheet = g_spriteAppearances.getSheetBySpriteId(spriteInfo.sprite_id(0), false)) {
m_size = sheet->getSpriteSize() / g_gameConfig.getSpriteSize();
sizes.emplace_back(m_size);
}

// animations
Expand All @@ -320,7 +316,6 @@ void ThingType::unserializeAppearance(const uint16_t clientId, const ThingCatego
}

const int totalSprites = m_layers * m_numPatternX * m_numPatternY * m_numPatternZ * std::max<int>(1, spritesPhases.size());
total_sprites.push_back(totalSprites);

if (totalSpritesCount + totalSprites > 4096)
throw Exception("a thing type has more than 4096 sprites");
Expand All @@ -333,42 +328,7 @@ void ThingType::unserializeAppearance(const uint16_t clientId, const ThingCatego
totalSpritesCount += totalSprites;
}

if (sizes.size() > 1) {
// correction for some sprites
for (const auto& s : sizes) {
m_size.setWidth(std::max<int>(m_size.width(), s.width()));
m_size.setHeight(std::max<int>(m_size.height(), s.height()));
}
const size_t expectedSize = m_size.area() * m_layers * m_numPatternX * m_numPatternY * m_numPatternZ * m_animationPhases;
if (expectedSize != m_spritesIndex.size()) {
const std::vector sprites(std::move(m_spritesIndex));
m_spritesIndex.clear();
m_spritesIndex.reserve(expectedSize);
for (size_t i = 0, idx = 0; i < sizes.size(); ++i) {
const int totalSprites = total_sprites[i];
if (m_size == sizes[i]) {
for (int j = 0; j < totalSprites; ++j) {
m_spritesIndex.push_back(sprites[idx++]);
}
continue;
}
const size_t patterns = (totalSprites / sizes[i].area());
for (size_t p = 0; p < patterns; ++p) {
for (int x = 0; x < m_size.width(); ++x) {
for (int y = 0; y < m_size.height(); ++y) {
if (x < sizes[i].width() && y < sizes[i].height()) {
m_spritesIndex.push_back(sprites[idx++]);
continue;
}
m_spritesIndex.push_back(0);
}
}
}
}
}
}

prepareTextureLoad(sizes, total_sprites);
m_textureData.resize(m_animationPhases);
}

void ThingType::unserialize(const uint16_t clientId, const ThingCategory category, const FileStreamPtr& fin)
Expand Down Expand Up @@ -517,9 +477,6 @@ void ThingType::unserialize(const uint16_t clientId, const ThingCategory categor
m_animationPhases = 0;
int totalSpritesCount = 0;

std::vector<Size> sizes;
std::vector<int> total_sprites;

for (int i = 0; i < groupCount; ++i) {
uint8_t frameGroupType = FrameGroupDefault;
if (hasFrameGroups)
Expand All @@ -528,7 +485,6 @@ void ThingType::unserialize(const uint16_t clientId, const ThingCategory categor
const uint8_t width = fin->getU8();
const uint8_t height = fin->getU8();
m_size = { width, height };
sizes.emplace_back(m_size);
if (width > 1 || height > 1) {
m_realSize = fin->getU8();
}
Expand All @@ -555,55 +511,12 @@ void ThingType::unserialize(const uint16_t clientId, const ThingCategory categor
}

const int totalSprites = m_size.area() * m_layers * m_numPatternX * m_numPatternY * m_numPatternZ * groupAnimationsPhases;
total_sprites.push_back(totalSprites);

if (totalSpritesCount + totalSprites > 4096)
throw Exception("a thing type has more than 4096 sprites");

m_spritesIndex.resize(totalSpritesCount + totalSprites);
for (int j = totalSpritesCount; j < (totalSpritesCount + totalSprites); ++j)
m_spritesIndex[j] = g_game.getFeature(Otc::GameSpritesU32) ? fin->getU32() : fin->getU16();

totalSpritesCount += totalSprites;
}

prepareTextureLoad(sizes, total_sprites);
}

void ThingType::prepareTextureLoad(const std::vector<Size>& sizes, const std::vector<int>& total_sprites) {
if (sizes.size() > 1) {
// correction for some sprites
for (const auto& s : sizes) {
m_size.setWidth(std::max<int>(m_size.width(), s.width()));
m_size.setHeight(std::max<int>(m_size.height(), s.height()));
}
const size_t expectedSize = m_size.area() * m_layers * m_numPatternX * m_numPatternY * m_numPatternZ * m_animationPhases;
if (expectedSize != m_spritesIndex.size()) {
const std::vector sprites(std::move(m_spritesIndex));
m_spritesIndex.clear();
m_spritesIndex.reserve(expectedSize);
for (size_t i = 0, idx = 0; i < sizes.size(); ++i) {
const int totalSprites = total_sprites[i];
if (m_size == sizes[i]) {
for (int j = 0; j < totalSprites; ++j) {
m_spritesIndex.push_back(sprites[idx++]);
}
continue;
}
const size_t patterns = (totalSprites / sizes[i].area());
for (size_t p = 0; p < patterns; ++p) {
for (int x = 0; x < m_size.width(); ++x) {
for (int y = 0; y < m_size.height(); ++y) {
if (x < sizes[i].width() && y < sizes[i].height()) {
m_spritesIndex.push_back(sprites[idx++]);
continue;
}
m_spritesIndex.push_back(0);
}
}
}
}
}
}

m_textureData.resize(m_animationPhases);
Expand Down Expand Up @@ -752,20 +665,22 @@ void ThingType::loadTexture(const int animationPhase)
if (protobufSupported) {
const uint32_t spriteIndex = getSpriteIndex(-1, -1, spriteMask ? 1 : l, x, y, z, animationPhase);
const auto& spriteImage = g_sprites.getSpriteImage(m_spritesIndex[spriteIndex]);
if (!spriteImage) {
continue;
}

// verifies that the first block in the lower right corner is transparent.
if (spriteImage->hasTransparentPixel()) {
if (!spriteImage || spriteImage->hasTransparentPixel()) {
fullImage->setTransparentPixel(true);
}

if (spriteMask) {
spriteImage->overwriteMask(maskColors[(l - 1)]);
}
if (spriteImage) {
if (spriteMask) {
spriteImage->overwriteMask(maskColors[(l - 1)]);
}

fullImage->blit(framePos, spriteImage);
auto spriteSize = spriteImage->getSize() / g_gameConfig.getSpriteSize();

const Point& spritePos = Point(m_size.width() - spriteSize.width(), m_size.height() - spriteSize.height()) * g_gameConfig.getSpriteSize();
fullImage->blit(framePos + spritePos, spriteImage);
}
} else {
for (int h = 0; h < m_size.height(); ++h) {
for (int w = 0; w < m_size.width(); ++w) {
Expand Down
2 changes: 0 additions & 2 deletions src/client/thingtype.h
Original file line number Diff line number Diff line change
Expand Up @@ -476,8 +476,6 @@ class ThingType final : public LuaObject
std::vector<Pos> pos;
};

void prepareTextureLoad(const std::vector<Size>& sizes, const std::vector<int>& total_sprites);

uint32_t getSpriteIndex(int w, int h, int l, int x, int y, int z, int a) const;
uint32_t getTextureIndex(int l, int x, int y, int z) const;

Expand Down

0 comments on commit 52694e8

Please sign in to comment.