Skip to content

Commit

Permalink
Merge branch 'main' into dudantas/clean-code-from-lua-script-interface
Browse files Browse the repository at this point in the history
  • Loading branch information
dudantas committed Nov 1, 2024
2 parents 4e98420 + 0ac47c1 commit 88964f2
Show file tree
Hide file tree
Showing 22 changed files with 449 additions and 335 deletions.
74 changes: 74 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Contributing to Canary

Thank you for your interest in contributing to Canary! This document provides guidelines for contributing to the project to ensure a smooth and effective collaboration.

## Code of Conduct

This project adheres to the [Contributor Covenant Code of Conduct](https://github.com/opentibiabr/canary/blob/main/CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at email: [email protected] or discord: https://discord.com/invite/gvTj5sh9Mp

## Project Roadmap

- The Canary project is part of a larger ecosystem within the Open Tibia BR organization, which includes various projects focused on enhancing and innovating within OT server development. You can follow our shared roadmap, encompassing projects like Canary, OTServBR, and OTServBR-Global, among others, in the projects section on GitHub: [Open Tibia BR - Project Roadmap](https://github.com/orgs/opentibiabr/projects).

- This roadmap aims to ensure alignment of initiatives and prioritize the development of improvements and new features that benefit the community. Community participation is crucial, and we encourage contributors to review the roadmap before proposing major changes, to ensure these align with the strategic direction of our projects.


## Getting Started

### Issues

- **Bug Reports**: If you encounter any bugs or issues while using Canary, please submit them via our [bug report template](https://github.com/opentibiabr/canary/blob/main/.github/ISSUE_TEMPLATE/bug.yaml).
- **Feature Requests**: If you have any ideas for features or enhancements, you can submit them through our [feature request template](https://github.com/opentibiabr/canary/blob/main/.github/ISSUE_TEMPLATE/request.yaml).

Please provide as much relevant information as possible, including logs, screenshots, or other details to help the team understand the problem or your request.

### Pull Requests

To contribute code to the project, please follow these guidelines:

1. **Fork the Repository**: Fork the Canary repository and create your own branch to make changes.
2. **Follow the Style Guides**: The project uses **Clang Format** for C++ and **Lua Format** for Lua scripts. It is important that your code follows these styles. We use GitHub Actions (GHA) for formatting checks, so make sure to format your code properly before submitting.
3. **No Complex Lua Scripts**: Contributions involving Lua scripts should focus on simple and efficient implementations. Performance-heavy features should be implemented in C++, and contributions that introduce overly complex Lua scripts may be rejected in favor of a C++ implementation.
4. **Database Standards**: We use an advanced key/value system for data storage called "KV System." We do not accept new tables in the MySQL database. All persistent data must be integrated using the KV system, which includes a protobuf-based abstraction for performance and integration. Please refer to the [KV System README](https://github.com/opentibiabr/canary/blob/main/src/kv/README.md) for more information.
5. **PR Guidelines**: Use our [Pull Request Template](https://github.com/opentibiabr/canary/blob/main/.github/PULL_REQUEST_TEMPLATE.md) when submitting a pull request. Ensure your PR:
- Follows the project coding standards.
- Contains relevant descriptions and details about the changes.
- Respects project maintainers' decisions. Some contributions may not be merged immediately or might be rejected due to internal project priorities.
6. **Do Not Use Legacy Storage System**: Pull requests that introduce new features using the legacy storage system will not be accepted. Contributors must adopt the "KV System" to ensure compatibility with our modern approach.

## Development Standards

### Code Quality
- Follow modern C++20+ standards when contributing to the codebase.
- Ensure that your code is well-documented. Comments should be in English, and special attention should be given to areas that are hard to understand.

### Formatting and Style
- **C++**: Code must be formatted with **Clang Format** according to the project's style configuration.
- **Lua**: Scripts must follow the formatting provided by **Lua Format**.

We recommend using the provided GitHub Actions to validate the formatting before submitting any pull requests.

## Communication

Please use a respectful and welcoming tone when communicating with others. We aim to foster a positive and friendly community, so be mindful of others' perspectives and experiences.

If you need to reach out to project maintainers for any assistance or inquiries, feel free to contact us at [email protected].

## Review Process

- Pull requests will be reviewed by the project maintainers. Please be patient, as it may take some time to get feedback.
- Contributors must be prepared for their PRs to be modified or even rejected. Reasons for this include internal priorities, a need for better performance, or violations of contribution guidelines.

## Best Practices
- Respect the project standards and guidelines.
- Make small, focused pull requests, as it makes the review process easier.
- Write tests where possible to ensure that your changes do not introduce new issues.
- Provide clear descriptions in your commits and pull requests.
- Ensure that new features are properly integrated with existing systems.

## Advanced Contribution
- **Complex Systems**: For features that impact performance or require deeper integrations, discuss them with the maintainers before implementation.
- **KV System Usage**: All persistent data should leverage the KV system. It allows for efficient data mapping, storing complex structures seamlessly. Learn more about the KV system [here](https://github.com/opentibiabr/canary/blob/main/src/kv/README.md).

Thank you for your contributions and for helping make Canary better!

13 changes: 13 additions & 0 deletions data/scripts/actions/items/mystery_box.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
local mysteryBox = Action()

function mysteryBox.onUse(player, item, fromPosition, target, toPosition, isHotkey)
local items = { 25361, 25360 }
local randomItem = items[math.random(#items)]
player:addItem(randomItem, 1)
player:getPosition():sendMagicEffect(CONST_ME_MAGIC_BLUE)
item:remove(1)
return true
end

mysteryBox:id(26186)
mysteryBox:register()
83 changes: 44 additions & 39 deletions src/account/account.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "account/account.hpp"

#include "account/account_repository_db.hpp"
#include "account/account_info.hpp"
#include "security/argon.hpp"
#include "utils/tools.hpp"
#include "enums/account_coins.hpp"
Expand All @@ -34,113 +35,116 @@ Account::Account(std::string descriptor) :
m_account->accountType = ACCOUNT_TYPE_NORMAL;
}

uint8_t Account::load() {
AccountErrors_t Account::load() {
using enum AccountErrors_t;
if (m_account->id != 0 && g_accountRepository().loadByID(m_account->id, m_account)) {
m_accLoaded = true;
return enumToValue(AccountErrors_t::Ok);
return Ok;
}

if (!m_descriptor.empty() && g_accountRepository().loadByEmailOrName(getProtocolCompat(), m_descriptor, m_account)) {
m_accLoaded = true;
return enumToValue(AccountErrors_t::Ok);
return Ok;
}

if (!m_descriptor.empty() && g_accountRepository().loadBySession(m_descriptor, m_account)) {
m_accLoaded = true;
return enumToValue(AccountErrors_t::Ok);
return Ok;
}

updatePremiumTime();
return enumToValue(AccountErrors_t::LoadingAccount);
return LoadingAccount;
}

uint8_t Account::reload() {
AccountErrors_t Account::reload() {
if (!m_accLoaded) {
return enumToValue(AccountErrors_t::NotInitialized);
return AccountErrors_t::NotInitialized;
}

return load();
}

uint8_t Account::save() {
AccountErrors_t Account::save() const {
using enum AccountErrors_t;
if (!m_accLoaded) {
return enumToValue(AccountErrors_t::NotInitialized);
return NotInitialized;
}

if (!g_accountRepository().save(m_account)) {
return enumToValue(AccountErrors_t::Storage);
return Storage;
}

return enumToValue(AccountErrors_t::Ok);
return Ok;
}

std::tuple<uint32_t, uint8_t> Account::getCoins(const uint8_t &type) const {
std::tuple<uint32_t, AccountErrors_t> Account::getCoins(CoinType type) const {
using enum AccountErrors_t;
if (!m_accLoaded) {
return { 0, enumToValue(AccountErrors_t::NotInitialized) };
return { 0, NotInitialized };
}

uint32_t coins = 0;
if (!g_accountRepository().getCoins(m_account->id, type, coins)) {
return { 0, enumToValue(AccountErrors_t::Storage) };
return { 0, Storage };
}

return { coins, enumToValue(AccountErrors_t::Ok) };
return { coins, Ok };
}

uint8_t Account::addCoins(const uint8_t &type, const uint32_t &amount, const std::string &detail) {
AccountErrors_t Account::addCoins(CoinType type, const uint32_t &amount, const std::string &detail) {
using enum AccountErrors_t;
if (!m_accLoaded) {
return enumToValue(AccountErrors_t::NotInitialized);
return NotInitialized;
}

if (amount == 0) {
return enumToValue(AccountErrors_t::Ok);
return Ok;
}

auto [coins, result] = getCoins(type);

if (AccountErrors_t::Ok != enumFromValue<AccountErrors_t>(result)) {
if (Ok != result) {
return result;
}

if (!g_accountRepository().setCoins(m_account->id, type, coins + amount)) {
return enumToValue(AccountErrors_t::Storage);
return Storage;
}

registerCoinTransaction(enumToValue(CoinTransactionType::Add), type, amount, detail);
registerCoinTransaction(CoinTransactionType::Add, type, amount, detail);

return enumToValue(AccountErrors_t::Ok);
return Ok;
}

uint8_t Account::removeCoins(const uint8_t &type, const uint32_t &amount, const std::string &detail) {
AccountErrors_t Account::removeCoins(CoinType type, const uint32_t &amount, const std::string &detail) {
using enum AccountErrors_t;
if (!m_accLoaded) {
return enumToValue(AccountErrors_t::NotInitialized);
return NotInitialized;
}

if (amount == 0) {
return enumToValue(AccountErrors_t::Ok);
return Ok;
}

auto [coins, result] = getCoins(type);

if (AccountErrors_t::Ok != enumFromValue<AccountErrors_t>(result)) {
if (Ok != result) {
return result;
}

if (coins < amount) {
g_logger().info("Account doesn't have enough coins! current[{}], remove:[{}]", coins, amount);
return enumToValue(AccountErrors_t::RemoveCoins);
return RemoveCoins;
}

if (!g_accountRepository().setCoins(m_account->id, type, coins - amount)) {
return enumToValue(AccountErrors_t::Storage);
return Storage;
}

registerCoinTransaction(enumToValue(CoinTransactionType::Remove), type, amount, detail);
registerCoinTransaction(CoinTransactionType::Remove, type, amount, detail);

return enumToValue(AccountErrors_t::Ok);
return Ok;
}

void Account::registerCoinTransaction(const uint8_t &transactionType, const uint8_t &type, const uint32_t &amount, const std::string &detail) {
void Account::registerCoinTransaction(CoinTransactionType transactionType, CoinType type, const uint32_t &amount, const std::string &detail) {
if (!m_accLoaded) {
return;
}
Expand Down Expand Up @@ -208,12 +212,12 @@ void Account::setPremiumDays(const int32_t &days) {
return m_account->premiumDaysPurchased;
}

uint8_t Account::setAccountType(const uint8_t &accountType) {
AccountErrors_t Account::setAccountType(AccountType accountType) {
m_account->accountType = accountType;
return enumToValue(AccountErrors_t::Ok);
return AccountErrors_t::Ok;
}

[[nodiscard]] uint8_t Account::getAccountType() const {
[[nodiscard]] AccountType Account::getAccountType() const {
return m_account->accountType;
}

Expand All @@ -240,14 +244,15 @@ void Account::updatePremiumTime() {
return;
}

if (AccountErrors_t::Ok != enumFromValue<AccountErrors_t>(save())) {
if (AccountErrors_t::Ok != save()) {
g_logger().error("Failed to update account premium time: [{}]", getDescriptor());
}
}

std::tuple<phmap::flat_hash_map<std::string, uint64_t>, uint8_t>
std::tuple<phmap::flat_hash_map<std::string, uint64_t>, AccountErrors_t>
Account::getAccountPlayers() const {
auto valueToReturn = enumToValue(m_accLoaded ? AccountErrors_t::Ok : AccountErrors_t::NotInitialized);
using enum AccountErrors_t;
auto valueToReturn = m_accLoaded ? Ok : NotInitialized;
return { m_account->players, valueToReturn };
}

Expand Down
25 changes: 15 additions & 10 deletions src/account/account.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@

struct AccountInfo;

enum class CoinType : uint8_t;
enum class CoinTransactionType : uint8_t;
enum class AccountErrors_t : uint8_t;
enum AccountType : uint8_t;

class Account {
public:
explicit Account(const uint32_t &id);
Expand All @@ -26,7 +31,7 @@ class Account {
* @return uint32_t Number of coins
* @return AccountErrors_t AccountErrors_t::Ok(0) Success, otherwise Fail.
*/
[[nodiscard]] std::tuple<uint32_t, uint8_t> getCoins(const uint8_t &type) const;
[[nodiscard]] std::tuple<uint32_t, AccountErrors_t> getCoins(CoinType type) const;

/**
* @brief Add coins to the account.
Expand All @@ -35,7 +40,7 @@ class Account {
* @param amount Amount of coins to be added
* @return AccountErrors_t AccountErrors_t::Ok(0) Success, otherwise Fail.
*/
uint8_t addCoins(const uint8_t &type, const uint32_t &amount, const std::string &detail = "ADD Coins");
AccountErrors_t addCoins(CoinType type, const uint32_t &amount, const std::string &detail = "ADD Coins");

/**
* @brief Removes coins from the account.
Expand All @@ -44,7 +49,7 @@ class Account {
* @param amount Amount of coins to be removed
* @return AccountErrors_t AccountErrors_t::Ok(0) Success, otherwise Fail.
*/
uint8_t removeCoins(const uint8_t &type, const uint32_t &amount, const std::string &detail = "REMOVE Coins");
AccountErrors_t removeCoins(CoinType type, const uint32_t &amount, const std::string &detail = "REMOVE Coins");

/**
* @brief Registers a coin transaction.
Expand All @@ -53,7 +58,7 @@ class Account {
* @param amount Amount of coins to be added
* @param detail Detail of the transaction
*/
void registerCoinTransaction(const uint8_t &transactionType, const uint8_t &type, const uint32_t &amount, const std::string &detail);
void registerCoinTransaction(CoinTransactionType transactionType, CoinType type, const uint32_t &amount, const std::string &detail);

/***************************************************************************
* Account Load/Save
Expand All @@ -64,22 +69,22 @@ class Account {
*
* @return AccountErrors_t AccountErrors_t::Ok(0) Success, otherwise Fail.
*/
uint8_t save();
AccountErrors_t save() const;

/**
* @brief Load Account Information.
*
* @return AccountErrors_t AccountErrors_t::Ok(0) Success, otherwise Fail.
*/
uint8_t load();
AccountErrors_t load();

/**
* @brief Re-Load Account Information to get update information(mainly the
* players list).
*
* @return AccountErrors_t AccountErrors_t::Ok(0) Success, otherwise Fail.
*/
uint8_t reload();
AccountErrors_t reload();

/***************************************************************************
* Setters and Getters
Expand Down Expand Up @@ -107,12 +112,12 @@ class Account {

[[nodiscard]] time_t getPremiumLastDay() const;

uint8_t setAccountType(const uint8_t &accountType);
[[nodiscard]] uint8_t getAccountType() const;
AccountErrors_t setAccountType(AccountType accountType);
[[nodiscard]] AccountType getAccountType() const;

void updatePremiumTime();

std::tuple<phmap::flat_hash_map<std::string, uint64_t>, uint8_t> getAccountPlayers() const;
std::tuple<phmap::flat_hash_map<std::string, uint64_t>, AccountErrors_t> getAccountPlayers() const;

// Old protocol compat
void setProtocolCompat(bool toggle);
Expand Down
4 changes: 3 additions & 1 deletion src/account/account_info.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@
#include <cstdint>
#endif

#include "enums/account_type.hpp"

struct AccountInfo {
~AccountInfo() = default;

uint32_t id = 0;
uint32_t premiumRemainingDays = 0;
time_t premiumLastDay = 0;
uint8_t accountType = 0;
AccountType accountType = ACCOUNT_TYPE_NONE;
phmap::flat_hash_map<std::string, uint64_t> players;
bool oldProtocol = false;
time_t sessionExpires = 0;
Expand Down
Loading

0 comments on commit 88964f2

Please sign in to comment.