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

Improve OTB loader iteration #4795

Draft
wants to merge 22 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 7 additions & 16 deletions src/bed.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,11 @@ extern Game g_game;

BedItem::BedItem(uint16_t id) : Item(id) { internalRemoveSleeper(); }

Attr_ReadValue BedItem::readAttr(AttrTypes_t attr, PropStream& propStream)
void BedItem::readAttr(AttrTypes_t attr, OTB::iterator& first, const OTB::iterator last)
{
switch (attr) {
case ATTR_SLEEPERGUID: {
uint32_t guid;
if (!propStream.read<uint32_t>(guid)) {
return ATTR_READ_ERROR;
}
auto guid = OTB::read<uint32_t>(first, last);

if (guid != 0) {
std::string name = IOLoginData::getNameByGuid(guid);
Expand All @@ -31,23 +28,17 @@ Attr_ReadValue BedItem::readAttr(AttrTypes_t attr, PropStream& propStream)
sleeperGUID = guid;
}
}
return ATTR_READ_CONTINUE;
break;
}

case ATTR_SLEEPSTART: {
uint32_t sleep_start;
if (!propStream.read<uint32_t>(sleep_start)) {
return ATTR_READ_ERROR;
}

sleepStart = static_cast<uint64_t>(sleep_start);
return ATTR_READ_CONTINUE;
}
case ATTR_SLEEPSTART:
sleepStart = static_cast<uint64_t>(OTB::read<uint32_t>(first, last));
break;

default:
Item::readAttr(attr, first, last);
break;
}
return Item::readAttr(attr, propStream);
}

void BedItem::serializeAttr(PropWriteStream& propWriteStream) const
Expand Down
2 changes: 1 addition & 1 deletion src/bed.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class BedItem final : public Item
BedItem* getBed() override { return this; }
const BedItem* getBed() const override { return this; }

Attr_ReadValue readAttr(AttrTypes_t attr, PropStream& propStream) override;
void readAttr(AttrTypes_t attr, OTB::iterator& first, const OTB::iterator last) override;
void serializeAttr(PropWriteStream& propWriteStream) const override;

bool canRemove() const override { return !house; }
Expand Down
47 changes: 20 additions & 27 deletions src/container.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,49 +86,42 @@ void Container::addItem(Item* item)
item->setParent(this);
}

Attr_ReadValue Container::readAttr(AttrTypes_t attr, PropStream& propStream)
void Container::readAttr(AttrTypes_t attr, OTB::iterator& first, const OTB::iterator last)
{
if (attr == ATTR_CONTAINER_ITEMS) {
if (!propStream.read<uint32_t>(serializationCount)) {
return ATTR_READ_ERROR;
}
return ATTR_READ_END;
switch (attr) {
case ATTR_CONTAINER_ITEMS:
serializationCount = OTB::read<uint32_t>(first, last);
break;

default:
Item::readAttr(attr, first, last);
break;
}
return Item::readAttr(attr, propStream);
}

bool Container::unserializeItemNode(OTB::Loader& loader, const OTB::Node& node, PropStream& propStream)
void Container::unserializeItemNode(OTB::iterator& first, const OTB::iterator last, const OTB::Node& node)
{
bool ret = Item::unserializeItemNode(loader, node, propStream);
if (!ret) {
return false;
}
Item::unserializeItemNode(first, last, node);

for (auto& itemNode : node.children) {
for (const auto& itemNode : node.children) {
// load container items
if (itemNode.type != OTBM_ITEM) {
// unknown type
return false;
if (itemNode.type != tfs::io::map::OTBM_ITEM) [[unlikely]] {
throw std::invalid_argument("Invalid node type");
}

PropStream itemPropStream;
if (!loader.getProps(itemNode, itemPropStream)) {
return false;
}
auto first = itemNode.propsBegin;
auto id = OTB::read<uint16_t>(first, itemNode.propsEnd);

Item* item = Item::CreateItem(itemPropStream);
if (!item) {
return false;
auto item = Item::CreateItem(Item::getPersistentId(id));
if (!item) [[unlikely]] {
throw std::invalid_argument("Invalid item id");
}

if (!item->unserializeItemNode(loader, itemNode, itemPropStream)) {
return false;
}
item->unserializeItemNode(first, itemNode.propsEnd, itemNode);

addItem(item);
updateItemWeight(item->getWeight());
}
return true;
}

void Container::updateItemWeight(int32_t diff)
Expand Down
8 changes: 4 additions & 4 deletions src/container.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ class Container : public Item, public Cylinder

bool hasParent() const override;

Attr_ReadValue readAttr(AttrTypes_t attr, PropStream& propStream) override;
bool unserializeItemNode(OTB::Loader& loader, const OTB::Node& node, PropStream& propStream) override;
void readAttr(AttrTypes_t attr, OTB::iterator& first, OTB::iterator const last) override;
void unserializeItemNode(OTB::iterator& first, OTB::iterator const last, const OTB::Node& node) override;

size_t size() const { return itemlist.size(); }
bool empty() const { return itemlist.empty(); }
Expand Down Expand Up @@ -115,13 +115,14 @@ class Container : public Item, public Cylinder
void internalAddThing(uint32_t index, Thing* thing) override final;
void startDecaying() override final;

uint32_t serializationCount = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this become public method due to the namespace. loadContainer function.


protected:
ItemDeque itemlist;

private:
uint32_t maxSize;
uint32_t totalWeight = 0;
uint32_t serializationCount = 0;
uint32_t ammoCount = 0;

bool unlocked;
Expand All @@ -135,7 +136,6 @@ class Container : public Item, public Cylinder
void updateItemWeight(int32_t diff);

friend class ContainerIterator;
friend class IOMapSerialize;
};

#endif // FS_CONTAINER_H
16 changes: 9 additions & 7 deletions src/depotlocker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,17 @@

DepotLocker::DepotLocker(uint16_t type) : Container(type), depotId(0) {}

Attr_ReadValue DepotLocker::readAttr(AttrTypes_t attr, PropStream& propStream)
void DepotLocker::readAttr(AttrTypes_t attr, OTB::iterator& first, const OTB::iterator last)
{
if (attr == ATTR_DEPOT_ID) {
if (!propStream.read<uint16_t>(depotId)) {
return ATTR_READ_ERROR;
}
return ATTR_READ_CONTINUE;
switch (attr) {
case ATTR_DEPOT_ID:
depotId = OTB::read<uint16_t>(first, last);
break;

default:
Item::readAttr(attr, first, last);
break;
}
return Item::readAttr(attr, propStream);
}

ReturnValue DepotLocker::queryAdd(int32_t, const Thing&, uint32_t, uint32_t, Creature*) const
Expand Down
2 changes: 1 addition & 1 deletion src/depotlocker.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class DepotLocker final : public Container
void removeInbox(Inbox* inbox);

// serialization
Attr_ReadValue readAttr(AttrTypes_t attr, PropStream& propStream) override;
void readAttr(AttrTypes_t attr, OTB::iterator& first, const OTB::iterator last) override;

uint16_t getDepotId() const { return depotId; }
void setDepotId(uint16_t depotId) { this->depotId = depotId; }
Expand Down
108 changes: 37 additions & 71 deletions src/fileloader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,105 +5,71 @@

#include "fileloader.h"

#include <stack>

namespace OTB {

constexpr Identifier wildcard = {{'\0', '\0', '\0', '\0'}};
namespace {

Loader::Loader(const std::string& fileName, const Identifier& acceptedIdentifier) : fileContents(fileName)
{
constexpr auto minimalSize = sizeof(Identifier) + sizeof(Node::START) + sizeof(Node::type) + sizeof(Node::END);
if (fileContents.size() <= minimalSize) {
throw InvalidOTBFormat{};
}

Identifier fileIdentifier;
std::copy(fileContents.begin(), fileContents.begin() + fileIdentifier.size(), fileIdentifier.begin());
if (fileIdentifier != acceptedIdentifier && fileIdentifier != wildcard) {
throw InvalidOTBFormat{};
}
}
const auto wildcard = std::string_view{"\0\0\0\0", 4};

using NodeStack = std::stack<Node*, std::vector<Node*>>;
static Node& getCurrentNode(const NodeStack& nodeStack)
auto checkIdentifier(iterator it, std::string_view acceptedIdentifier)
{
if (nodeStack.empty()) {
throw InvalidOTBFormat{};
}
return *nodeStack.top();
auto identifier = std::string_view(it, 4);
return identifier == acceptedIdentifier || identifier == wildcard;
}

const Node& Loader::parseTree()
Node parseTree(iterator& first, const iterator last)
{
auto it = fileContents.begin() + sizeof(Identifier);
if (static_cast<uint8_t>(*it) != Node::START) {
throw InvalidOTBFormat{};
}
root.type = *(++it);
root.propsBegin = ++it;
NodeStack parseStack;
parseStack.push(&root);
auto node = Node{.propsBegin = first + 1, .propsEnd = last, .type = *first};

for (; it != fileContents.end(); ++it) {
switch (static_cast<uint8_t>(*it)) {
for (; first != last; ++first) {
switch (*first) {
case Node::START: {
auto& currentNode = getCurrentNode(parseStack);
if (currentNode.children.empty()) {
currentNode.propsEnd = it;
if (node.children.empty()) {
node.propsEnd = first;
}
currentNode.children.emplace_back();
auto& child = currentNode.children.back();
if (++it == fileContents.end()) {
throw InvalidOTBFormat{};

if (++first == last) [[unlikely]] {
throw std::invalid_argument("File overflow on start node.");
}
child.type = *it;
child.propsBegin = it + sizeof(Node::type);
parseStack.push(&child);

node.children.emplace_back(parseTree(first, last));
break;
}
case Node::END: {
auto& currentNode = getCurrentNode(parseStack);
if (currentNode.children.empty()) {
currentNode.propsEnd = it;
if (node.children.empty()) {
node.propsEnd = first;
}
parseStack.pop();
break;

return node;
}
case Node::ESCAPE: {
if (++it == fileContents.end()) {
throw InvalidOTBFormat{};
if (++first == last) [[unlikely]] {
throw std::invalid_argument("File overflow on escape node.");
}
break;
}
default: {
break;
}
}
}
if (!parseStack.empty()) {
throw InvalidOTBFormat{};
}

return root;
throw std::invalid_argument("File underflow.");
}

bool Loader::getProps(const Node& node, PropStream& props)
} // namespace

Loader load(std::string_view filename, std::string_view acceptedIdentifier)
{
auto size = std::distance(node.propsBegin, node.propsEnd);
if (size == 0) {
return false;
MappedFile file{filename.data()};

if (!checkIdentifier(file.begin(), acceptedIdentifier)) {
throw std::invalid_argument("Invalid magic header.");
}
propBuffer.resize(size);
bool lastEscaped = false;

auto escapedPropEnd =
std::copy_if(node.propsBegin, node.propsEnd, propBuffer.begin(), [&lastEscaped](const char& byte) {
lastEscaped = byte == static_cast<char>(Node::ESCAPE) && !lastEscaped;
return !lastEscaped;
});
props.init(&propBuffer[0], std::distance(propBuffer.begin(), escapedPropEnd));
return true;

auto first = file.begin() + 4;
if (*first != Node::START) {
throw std::invalid_argument("Invalid first byte.");
}

return {std::move(file), parseTree(++first, file.end())};
}

} // namespace OTB
Loading
Loading