diff --git a/Sdk/Include/AI/Public/Components/DodgeBehavior.cpp b/Sdk/Include/AI/Public/Components/DodgeBehavior.cpp deleted file mode 100644 index b3a7e28..0000000 --- a/Sdk/Include/AI/Public/Components/DodgeBehavior.cpp +++ /dev/null @@ -1,179 +0,0 @@ -#include "AI/Public/Behaviors/DodgeBehavior.h" -#include "AI/Public/Components/Senses.h" -#include "AI/Public/Components/MoveEnactor.h" -#include "AI/Public/Components/PhysicsView.h" -#include "GameObject/Public/Core.h" -#include "Navigation/Public/Core.h" -#include "projectile.h" - -namespace AI -{ - using namespace beehive; - using namespace ECS; - using namespace GameObj; - using namespace Nav; - - // TODO: Parameterize - const float DodgeStartTime = 5.0f; - const float DodgeSafeRadius = 10.0f; - - static bool DodgeTargetValid(const std::optional& target) - { - return target && !target->Projectile.expired(); - } - - static float GetTimeToImpact(const P3D& avoidLocation, const PhysicsView& projectilePhysics) - { - float timeToImpact = avoidLocation.Distance3D(projectilePhysics.Location) / projectilePhysics.Velocity.Length(); - return timeToImpact; - } - - static void AbortDodge(DodgeBehaviorState& state, BehaviorTreeContext& context) - { - state.DodgeTarget = std::nullopt; - context.ResetResumeIndex(); - } - - static std::optional ChooseDodgeTarget(Entity* entity, Senses& senses, const PhysicsView& objectPhysics) - { - Object* aiObject = entity->GetComponent().GetObj(); - - std::sort(senses.KnownEnemyProjectiles.begin(), senses.KnownEnemyProjectiles.end(), [&objectPhysics](const auto& e1, const auto& e2) - { - const PhysicsView& entity1Physics = e1->GetComponent(); - const PhysicsView& entity2Physics = e2->GetComponent(); - - return entity1Physics.Location.DistanceSquared3D(objectPhysics.Location) < entity2Physics.Location.DistanceSquared3D(objectPhysics.Location); - }); - - for (const auto& projectile : senses.KnownEnemyProjectiles) - { - Object* projectileObject = projectile->GetComponent().GetObj(); - const PhysicsView& projectilePhysics = projectile->GetComponent(); - ObjSpecProjectile* spec = ObjSpecProjectile::Cast(projectileObject); - - if (!spec->ground_collision) - { - TRACE_BEHAVIOR("Projectile is not expected to collide with ground"); - continue; - } - - const PROJ_Def* def = PROJ_DefGet(spec->projectile_index); - - float speed = projectileObject->velocity.Length(); - float timeToImpact = GetTimeToImpact(spec->ground_collision_position, projectilePhysics); - if (timeToImpact > DodgeStartTime) - { - TRACE_BEHAVIOR("Projectile time to impact of {0} is above threshold", timeToImpact); - continue; - } - - P3D aiProjectedLocation = aiObject->location + (aiObject->velocity * timeToImpact); - if (aiProjectedLocation.DistanceSquared3D(spec->ground_collision_position) < Squared(def->fardist)) - { - return DodgeTarget{ projectile, def->fardist, spec->ground_collision_position }; - } - } - - return std::nullopt; - } - - bool DodgeBehavior::ShouldStartDodge(Entity* entity, Object* object, BehaviorTreeContext& context) - { - if (!entity->HasComponent()) - return false; - - if (!World->navMesh) - return false; - - auto& state = entity->GetComponent(); - if (!DodgeTargetValid(state.DodgeTarget)) - { - // Make sure invalid targets have been cleared out - state.DodgeTarget = std::nullopt; - } - else - { - // Already have dodge in progress - return false; - } - - auto [senses, physicsView] = entity->GetComponent(); - - state.DodgeTarget = ChooseDodgeTarget(entity, senses, physicsView); - if (!state.DodgeTarget) - { - // No nearby threats - return false; - } - - float angleToCenter = dirfcalcp3d(&state.DodgeTarget->AvoidLocation, &physicsView.Location); - - float sa, ca; - calc_sincosd(dirfadjust(angleToCenter), &sa, &ca); - P3D wantLoc = state.DodgeTarget->AvoidLocation; - wantLoc.x += (state.DodgeTarget->ImpactRadius + DodgeSafeRadius) * ca; - wantLoc.y += (state.DodgeTarget->ImpactRadius + DodgeSafeRadius) * sa; - - MoveGoalParams params; - params.Speed = MoveGoalSpeed::Fast; - std::shared_ptr path = PathUtil::GetPath(entity, World->navMesh.get(), physicsView.Location, wantLoc, ¶ms); - if (!path) - { - TRACE_BEHAVIOR("Couldn't path away from projectile"); - return false; - } - - TRACE_BEHAVIOR("Dodging to location {0} {1} {2}, est. impact time {3}", - wantLoc.x, - wantLoc.y, - wantLoc.z, - GetTimeToImpact(state.DodgeTarget->AvoidLocation, state.DodgeTarget->Projectile.lock()->GetComponent())); - - PathUtil::SetPath(entity, path); - - context.SetChainingEnabled(false); - return true; - } - - Status DodgeBehavior::MoveToDodgeLocation(Entity* entity, Object* object, BehaviorTreeContext& context) - { - auto& state = entity->GetComponent(); - const auto& moveEnactor = entity->GetComponent(); - - if (!DodgeTargetValid(state.DodgeTarget) - || !moveEnactor.Path) - { - TRACE_BEHAVIOR("Dodge target no longer valid; canceling"); - AbortDodge(state, context); - return Status::SUCCESS; - } - - const auto& aiPhysics = entity->GetComponent(); - - float distanceFromImpactSq = state.DodgeTarget->AvoidLocation.DistanceSquared3D(aiPhysics.Location); - if (distanceFromImpactSq > Squared(state.DodgeTarget->ImpactRadius + DodgeSafeRadius)) - { - // Got far enough away somehow, we can reset - TRACE_BEHAVIOR("AI is {0} units away from impact location with still active dodge behavior; canceling", sqrt(distanceFromImpactSq)); - AbortDodge(state, context); - return Status::SUCCESS; - } - - return Status::RUNNING; - } - - InnerBehaviorTree DodgeBehavior::Build(ECS::Entity* entity) - { - assert(entity); - - DodgeBehaviorState& state = entity->AddComponent(); - - return BehaviorTreeBuilder() - .sequence() - .leaf(CreateLeaf(entity, ShouldStartDodge)) - .leaf(CreateLeaf(entity, MoveToDodgeLocation)) - .end() - .build(); - } -} \ No newline at end of file diff --git a/Sdk/Include/Core/Public/EventListenerResult.h b/Sdk/Include/Core/Public/EventListenerResult.h new file mode 100644 index 0000000..99749d3 --- /dev/null +++ b/Sdk/Include/Core/Public/EventListenerResult.h @@ -0,0 +1,7 @@ +#pragma once + +enum class EventListenerResult +{ + Continue, + Cancel +}; \ No newline at end of file diff --git a/Sdk/Include/Core/Public/IEventSource.h b/Sdk/Include/Core/Public/IEventSource.h index a30ea7c..f2b9dc6 100644 --- a/Sdk/Include/Core/Public/IEventSource.h +++ b/Sdk/Include/Core/Public/IEventSource.h @@ -3,11 +3,13 @@ #include #include +#include "EventListenerResult.h" + template struct IEventSource { virtual ~IEventSource() = default; - virtual GUID Listen(TEventType event, std::function function) noexcept = 0; + virtual GUID Listen(TEventType event, std::function function) noexcept = 0; virtual void Unlisten(TEventType event, GUID uuid) noexcept = 0; }; \ No newline at end of file diff --git a/Sdk/Include/Core/Public/ITextLookupService.h b/Sdk/Include/Core/Public/ITextLookupService.h index 47b40b2..bae036c 100644 --- a/Sdk/Include/Core/Public/ITextLookupService.h +++ b/Sdk/Include/Core/Public/ITextLookupService.h @@ -7,9 +7,6 @@ enum class NetPlayerState; enum class GameTeam; -// {770DEBD3-165D-4340-829D-5262F473FBE3} -inline const GUID IID_ITextLookupService = { 0x770debd3, 0x165d, 0x4340, 0x82, 0x9d, 0x52, 0x62, 0xf4, 0x73, 0xfb, 0xe3 }; - /// /// Service providing localization of text placeholders and friendly-name mappings of common enums. /// diff --git a/Sdk/Include/Network/Public/GameServerEvents.h b/Sdk/Include/Network/Public/GameServerEvents.h index 823d62f..557a9f0 100644 --- a/Sdk/Include/Network/Public/GameServerEvents.h +++ b/Sdk/Include/Network/Public/GameServerEvents.h @@ -46,6 +46,7 @@ struct ChatMessageEvent : GameServerEvent tstring_view message{}; PlayerIndex senderIndex{}; + ChatFlag flags{}; }; struct WorldLoadedEvent : GameServerEvent diff --git a/Sdk/Include/Network/Public/IGameServer.h b/Sdk/Include/Network/Public/IGameServer.h index fc6fe73..27d7a08 100644 --- a/Sdk/Include/Network/Public/IGameServer.h +++ b/Sdk/Include/Network/Public/IGameServer.h @@ -8,9 +8,6 @@ #include "GameServerEvents.h" #include "NetCommon.h" -// {B2D67EE7-8063-488F-B3B9-E7DA675CB752} -inline const GUID IID_IGameServer = { 0xb2d67ee7, 0x8063, 0x488f, 0xb3, 0xb9, 0xe7, 0xda, 0x67, 0x5c, 0xb7, 0x52 }; - /// /// Defines an API for communicating with the game server. /// @@ -31,15 +28,24 @@ DEFINE_SERVICE_MULTI("{B2D67EE7-8063-488F-B3B9-E7DA675CB752}", IGameServer, IEve /// Bans the player at the specified index. /// /// The player index. - /// virtual void BanPlayer(int index) = 0; + /// + /// Removes the IP address from the ban list. + /// + /// The IP address. + virtual void UnbanPlayer(const IPAddress & ipAddress) = 0; + + /// + /// Gets the IP addresses that are currently banned. + /// + virtual const std::vector GetBans() const = 0; + /// /// Kicks the player at the specified index. /// /// The player index. /// The reason for kicking the player. - /// virtual void KickPlayer(int index, KickReason reason) = 0; /// @@ -72,6 +78,4 @@ DEFINE_SERVICE_MULTI("{B2D67EE7-8063-488F-B3B9-E7DA675CB752}", IGameServer, IEve /// /// The game details. virtual void ChangeGameDetails(const NetGameDetails& gameDetails) = 0; -}; - -struct DECLSPEC_UUID("{B2D67EE7-8063-488F-B3B9-E7DA675CB752}") IGameServer; \ No newline at end of file +}; \ No newline at end of file diff --git a/Sdk/Include/Network/Public/IGiantsApiClient.h b/Sdk/Include/Network/Public/IGiantsApiClient.h index 37c1bef..235d526 100644 --- a/Sdk/Include/Network/Public/IGiantsApiClient.h +++ b/Sdk/Include/Network/Public/IGiantsApiClient.h @@ -7,9 +7,6 @@ typedef std::future> ServerInfoFuture; -// {EE129A81-0A86-49C4-8D23-A771A7350952} -inline const GUID IID_IGiantsApiClient = { 0xee129a81, 0xa86, 0x49c4, 0x8d, 0x23, 0xa7, 0x71, 0xa7, 0x35, 0x9, 0x52 }; - DEFINE_SERVICE("{EE129A81-0A86-49C4-8D23-A771A7350952}", IGiantsApiClient) { virtual ~IGiantsApiClient() = default; @@ -17,6 +14,4 @@ DEFINE_SERVICE("{EE129A81-0A86-49C4-8D23-A771A7350952}", IGiantsApiClient) virtual void DeleteServerInformationAsync(tstring_view gameName, int hostPort) = 0; virtual ServerInfoFuture GetServerInformationAsync() = 0; virtual void PostServerInformationAsync(const nlohmann::json& requestBody) = 0; -}; - -struct DECLSPEC_UUID("{EE129A81-0A86-49C4-8D23-A771A7350952}") IGiantsApiClient; \ No newline at end of file +}; \ No newline at end of file diff --git a/Sdk/Include/Network/Public/IPAddress.h b/Sdk/Include/Network/Public/IPAddress.h new file mode 100644 index 0000000..90158d3 --- /dev/null +++ b/Sdk/Include/Network/Public/IPAddress.h @@ -0,0 +1,82 @@ +#pragma once + +#include + +class IPAddress +{ +public: + int operator[](int index) const + { + if (index < countof(m_octets) && index > 0) + { + return m_octets[index]; + } + + throw std::invalid_argument("Invalid octet index."); + } + + bool operator==(const IPAddress& right) const + { + return (m_octets[0] == right.m_octets[0] && + m_octets[1] == right.m_octets[1] && + m_octets[2] == right.m_octets[2] && + m_octets[3] == right.m_octets[3]); + } + + bool operator!= (const IPAddress& right) const + { + return !operator==(right); + } + + bool operator<(const IPAddress& right) const + { + return ToInt() < right.ToInt(); + } + + bool operator>(const IPAddress& right) const + { + return right.operator<(*this); + } + + static IPAddress FromString(const tstring_view str) + { + IPAddress ipAddress; + + char octetBuff[4]{}; + std::string tmp(str); + std::istringstream iss(tmp); + + int octetsRead = 0; + while (true) + { + iss.getline(octetBuff, sizeof(octetBuff), '.'); + + if (iss.gcount() <= 0) + break; + + int octet = atoi(octetBuff); + if (octet > 255 || octet < 0) + { + throw std::invalid_argument(fmt::format("Octet '{0}' is invalid.", octet)); + } + + ipAddress.m_octets[octetsRead] = octet; + octetsRead++; + } + + return ipAddress; + } + + std::string ToString() const + { + return fmt::sprintf("%d.%d.%d.%d", m_octets[0], m_octets[1], m_octets[2], m_octets[3]); + } + + uint ToInt() const + { + return ((m_octets[0] << 24) + (m_octets[1] << 16) + (m_octets[2] << 8) + m_octets[3]); + } + +protected: + int m_octets[4]{}; +}; diff --git a/Sdk/Include/Network/Public/NetCommon.h b/Sdk/Include/Network/Public/NetCommon.h index 921e656..a7bdb40 100644 --- a/Sdk/Include/Network/Public/NetCommon.h +++ b/Sdk/Include/Network/Public/NetCommon.h @@ -2,6 +2,8 @@ #include +#include "IPAddress.h" + typedef int PlayerIndex; typedef int PlayerTeamIndex; @@ -81,13 +83,14 @@ enum class GameTeam struct PlayerInfo { PlayerIndex index = 0; - std::string name; + tstring name; float score = 0; float deaths = 0; int ping = 0; PlayerTeamIndex team = 0; bool host = false; NetPlayerState state = NetPlayerState::None; + IPAddress ipAddress; }; struct NetGameSettings @@ -105,6 +108,7 @@ struct NetGameSettings bool vimpsDisabled = false; bool weaponAvailabilityModified = false; int worldId = 0; + tstring sessionName; }; struct NetGameDetails @@ -112,7 +116,7 @@ struct NetGameDetails // User-adjustable settings for the current game. NetGameSettings settings; - std::string worldName; - std::string teamTypeName; - std::string gameTypeName; + tstring worldName; + tstring teamTypeName; + tstring gameTypeName; }; \ No newline at end of file diff --git a/ServerConsoleExample/ServerDialog.cpp b/ServerConsoleExample/ServerDialog.cpp index 45e5cb1..d1e7bf1 100644 --- a/ServerConsoleExample/ServerDialog.cpp +++ b/ServerConsoleExample/ServerDialog.cpp @@ -28,6 +28,7 @@ ServerDialog::~ServerDialog() pGameServer->Unlisten(GameServerEventType::PlayerConnected, m_playerConnectedEventHandle); pGameServer->Unlisten(GameServerEventType::PlayerDisconnected, m_playerDisconnectedEventHandle); pGameServer->Unlisten(GameServerEventType::ChatMessage, m_playerChatMessageHandle); + pGameServer->Unlisten(GameServerEventType::WorldLoaded, m_worldLoadedHandle); } catch (...) {