Skip to content
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
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ add_library(alicia-libserver STATIC
src/libserver/network/http/WebSocket.cpp
src/libserver/registry/CharacterRegistry.cpp
src/libserver/registry/CourseRegistry.cpp
src/libserver/registry/BreedingRegistry.cpp
src/libserver/registry/HorseRegistry.cpp
src/libserver/registry/ItemRegistry.cpp
src/libserver/registry/MagicRegistry.cpp
Expand Down Expand Up @@ -109,6 +110,8 @@ add_executable(alicia-server
src/server/messenger/MessengerDirector.cpp
src/server/race/RaceInstance.cpp
src/server/race/RaceNetworkHandler.cpp
src/server/ranch/BreedingMarket.cpp
src/server/ranch/Genetics.cpp
src/server/ranch/RanchDirector.cpp
src/server/room/Room.cpp
src/server/system/ChatSystem.cpp
Expand Down
53 changes: 49 additions & 4 deletions include/libserver/data/DataDefinitions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,19 @@ struct Character

struct Horse
{
//! A horse type.
enum class Type
{
//! An adult horse.
Adult,
//! A horse foal.
Foal,
//! An adult horse which is registered in the breeding market.
Stallion,
//! An adult horse which is rented.
Rent
};

dao::Field<Uid> uid{InvalidUid};
dao::Field<Tid> tid{InvalidTid};
dao::Field<std::string> name{};
Expand Down Expand Up @@ -406,6 +419,17 @@ struct Horse
dao::Field<uint32_t> grade{0u};
dao::Field<uint32_t> growthPoints{0u};

//! A count of how many times the horse was bred.
dao::Field<uint32_t> breedingCount{0u};
//! A count of successful consecutive breeds.
dao::Field<uint32_t> breedingCombo{0u};

dao::Field<Type> type{Type::Adult};
dao::Field<Clock::time_point> dateOfBirth{};

dao::Field<uint32_t> tendency{0u};
dao::Field<uint32_t> spirit{0u};

struct Potential
{
dao::Field<uint32_t> type{0u};
Expand All @@ -416,7 +440,6 @@ struct Horse
dao::Field<uint32_t> luckState{0u};
dao::Field<uint32_t> fatigue{0u};
dao::Field<uint32_t> emblemUid{0u};
dao::Field<Clock::time_point> dateOfBirth{};

struct MountCondition
{
Expand All @@ -436,8 +459,6 @@ struct Horse
dao::Field<uint32_t> stopAmendsPoint{};
} mountCondition{};

dao::Field<uint32_t> tendency{0u};

struct MountInfo
{
dao::Field<uint32_t> boostsInARow{};
Expand All @@ -458,6 +479,19 @@ struct Horse
dao::Field<uint32_t> cumulativePrize{};
dao::Field<uint32_t> biggestPrize{};
} mountInfo{};

struct Ancestors
{
Uid father{InvalidUid};
Uid mother{InvalidUid};
} ancestors{};

//! A value in an interval of <1, 9>.
//! Basically a weighted score of number of ancestors that share the same coat as the horse.
//! Ancestors of the first generation add two points to the lineage,
//! ancestors of the second generation add one point to the lineage
//! while the horse itself adds 1.
dao::Field<uint32_t> lineage{1u};
};

struct Housing
Expand Down Expand Up @@ -515,7 +549,7 @@ struct Quest
dao::Field<Status> isCompleted{Status::InProgress};
dao::Field<uint32_t> progress{};
};

struct Mail
{
//! Mail type.
Expand Down Expand Up @@ -550,6 +584,17 @@ struct Mail
dao::Field<std::string> body{};
};

struct Stallion
{
dao::Field<Uid> uid{InvalidUid};
dao::Field<Uid> horseUid{InvalidUid}; // The horse being registered as stallion
dao::Field<Uid> ownerUid{InvalidUid}; // Owner of the stallion
dao::Field<uint32_t> breedingCharge{}; // Price in carrots to breed with this stallion
dao::Field<uint32_t> timesMated{0u}; // Times bred during current registration
dao::Field<Clock::time_point> registeredAt{};
dao::Field<Clock::time_point> expiresAt{};
};

} // namespace data

} // namespace server
Expand Down
11 changes: 11 additions & 0 deletions include/libserver/data/DataDirector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
namespace server
{

// Forward declaration
class FileDataSource;

class DataDirector
{
public:
Expand All @@ -46,6 +49,7 @@ class DataDirector
using DailyQuestGroupStorage = DataStorage<data::Uid, data::DailyQuestGroup>;
using MailStorage = DataStorage<data::Uid, data::Mail>;
using QuestStorage = DataStorage<data::Uid, data::Quest>;
using StallionStorage = DataStorage<data::Uid, data::Stallion>;

//! Default constructor.
explicit DataDirector(const std::filesystem::path& basePath);
Expand Down Expand Up @@ -136,6 +140,11 @@ class DataDirector
[[nodiscard]] Record<data::Quest> CreateQuest() noexcept;
[[nodiscard]] QuestStorage& GetQuestCache();

[[nodiscard]] Record<data::Stallion> GetStallion(data::Uid stallionUid) noexcept;
[[nodiscard]] Record<data::Stallion> CreateStallion() noexcept;
[[nodiscard]] StallionStorage& GetStallionCache();
[[nodiscard]] std::vector<data::Uid> ListRegisteredStallions();

[[nodiscard]] DataSource& GetDataSource() noexcept;

private:
Expand Down Expand Up @@ -193,6 +202,8 @@ class DataDirector
MailStorage _mailStorage;
//! A quest storage.
QuestStorage _questStorage;
//! A stallion storage.
StallionStorage _stallionStorage;
};

} // namespace server
Expand Down
18 changes: 18 additions & 0 deletions include/libserver/data/DataSource.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,24 @@ class DataSource
//! Deletes the quest from the data source.
//! @param uid UID of the quest.
virtual void DeleteQuest(data::Uid uid) = 0;

//! Creates the stallion in the data source.
//! @param stallion Stallion to create.
virtual void CreateStallion(data::Stallion& stallion) = 0;
//! Retrieves the stallion from the data source.
//! @param uid UID of the stallion.
//! @param stallion Stallion to retrieve.
virtual void RetrieveStallion(data::Uid uid, data::Stallion& stallion) = 0;
//! Stores the stallion on the data source.
//! @param uid UID of the stallion.
//! @param stallion Stallion to store.
virtual void StoreStallion(data::Uid uid, const data::Stallion& stallion) = 0;
//! Deletes the stallion from the data source.
//! @param uid UID of the stallion.
virtual void DeleteStallion(data::Uid uid) = 0;
//! Lists all registered stallion UIDs from the data source.
//! @returns Vector of stallion UIDs.
virtual std::vector<data::Uid> ListRegisteredStallions() = 0;
};

} // namespace server
Expand Down
11 changes: 11 additions & 0 deletions include/libserver/data/file/FileDataSource.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,13 @@ class FileDataSource
void RetrieveQuest(data::Uid uid, data::Quest& quest) override;
void StoreQuest(data::Uid uid, const data::Quest& quest) override;
void DeleteQuest(data::Uid uid) override;

void CreateStallion(data::Stallion& stallion) override;
void RetrieveStallion(data::Uid uid, data::Stallion& stallion) override;
void StoreStallion(data::Uid uid, const data::Stallion& stallion) override;
void DeleteStallion(data::Uid uid) override;
std::vector<data::Uid> ListRegisteredStallions() override;

private:
//! A root data path.
std::filesystem::path _dataPath;
Expand Down Expand Up @@ -141,6 +148,8 @@ class FileDataSource
std::filesystem::path _mailDataPath;
//! A path to the quest data files.
std::filesystem::path _questDataPath;
//! A path to the stallion data files.
std::filesystem::path _stallionDataPath;

//! A path to meta-data file.
std::filesystem::path _metaFilePath;
Expand Down Expand Up @@ -170,6 +179,8 @@ class FileDataSource
std::atomic_uint32_t _mailSequentialId = 0;
//! Sequential UID for quests.
std::atomic_uint32_t _questSequentialId = 0;
//! Sequential UID for stallions.
std::atomic_uint32_t _stallionSequentialUid = 0;
};

} // namespace server
Expand Down
3 changes: 2 additions & 1 deletion include/libserver/data/helper/ProtocolHelper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ void BuildProtocolHorse(

void BuildProtocolHorseParts(
Horse::Parts& protocolHorseParts,
const data::Horse::Parts& parts);
const data::Horse::Parts& parts,
bool isFoal = false);

void BuildProtocolHorseAppearance(
Horse::Appearance& protocolHorseAppearance,
Expand Down
99 changes: 99 additions & 0 deletions include/libserver/network/command/CommandDeferrer.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/**
* Alicia Server - dedicated server software
* Copyright (C) 2026 Story Of Alicia
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
**/

#ifndef ALICIA_SERVER_COMMANDDEFERRER_HPP
#define ALICIA_SERVER_COMMANDDEFERRER_HPP

#include "libserver/network/NetworkDefinitions.hpp"

#include <functional>
#include <list>

namespace server
{

//! Class providing command deferring capability.
template <typename C>
class CommandDeferrer
{
public:
using Handler = std::function<void(network::ClientId, const C&)>;

//! Default constructor.
explicit CommandDeferrer(Handler handler) noexcept
: _handler(handler)
{
_command = _commands.cend();
}

//! Default destructor
~CommandDeferrer() = default;

CommandDeferrer(const CommandDeferrer&) = delete;
CommandDeferrer& operator=(const CommandDeferrer&) = delete;

CommandDeferrer(CommandDeferrer&&) = delete;
CommandDeferrer& operator=(CommandDeferrer&&) = delete;

void Tick()
{
// If there's no commands skip.
if (_commands.empty())
return;

// If at the end of the commands list
// loop back to the beginning.
if (_command == _commands.cend())
_command = _commands.cbegin();

try
{
// Call the handler.
_handler(_command->clientId, _command->command);
_command = _commands.erase(_command);
}
catch (const std::exception& x)
{
_command = _commands.erase(_command);
throw x;
}
}

void Defer(const network::ClientId clientId, C command) noexcept
{
_commands.emplace_back(CommandContext{
.clientId = clientId,
.command = std::move(command)});
}

private:
struct CommandContext
{
network::ClientId clientId;
C command;
};

Handler _handler;
std::list<CommandContext> _commands;
decltype(_commands)::const_iterator _command;
};

} // namespace server

#endif // ALICIA_SERVER_COMMANDDEFERRER_HPP
28 changes: 18 additions & 10 deletions include/libserver/network/command/CommandServer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ concept WritableCommandStruct = WritableStruct<T> and requires
class CommandServer final
{
public:
//! Command server event handler interface.
class EventHandlerInterface
{
public:
Expand All @@ -80,24 +81,34 @@ class CommandServer final
virtual void HandleClientDisconnected(ClientId clientId) = 0;
};

//! Default constructor;
explicit CommandServer(
EventHandlerInterface& events);
~CommandServer();
//! Constructor.
//! @param eventHandlerInterface Instance of event handler.
CommandServer(
EventHandlerInterface& eventHandlerInterface);

//! Begins the server.
//! Default destructor.
~CommandServer() = default;

CommandServer(const CommandServer&) = delete;
CommandServer& operator=(const CommandServer&) = delete;

CommandServer(CommandServer&&) = delete;
CommandServer& operator=(CommandServer&&) = delete;

//! Begins the command server.
//! @param address Address.
//! @param port Port.
void BeginHost(const asio::ip::address& address, uint16_t port);

//! Ends the server.
//! Ends the command server.
void EndHost();

asio::ip::address_v4 GetClientAddress(ClientId);
void DisconnectClient(ClientId clientId);

void SetCode(ClientId client, protocol::XorCode code);

//! Registers a command handler.
//! @param commandId ID of the command to register the handler for.
//! @param handler Handler of the command.
template <ReadableCommandStruct C>
void RegisterCommandHandler(
Expand All @@ -113,7 +124,6 @@ class CommandServer final

//! Queues a command for sending.
//! @param clientId ID of the client to send the command to.
//! @param commandId ID of the command.
//! @param supplier Supplier of the command.
template <WritableStruct C>
void QueueCommand(
Expand All @@ -125,8 +135,6 @@ class CommandServer final
});
}

void SetCode(ClientId client, protocol::XorCode code);

private:
class NetworkEventHandler
: public network::EventHandlerInterface
Expand Down
Loading
Loading