Skip to content

Commit

Permalink
Merge pull request #4 from Wild-W/develop
Browse files Browse the repository at this point in the history
v1.3
  • Loading branch information
Wild-W authored Aug 2, 2024
2 parents c16d250 + 13cf623 commit cc200f9
Show file tree
Hide file tree
Showing 24 changed files with 823 additions and 188 deletions.
197 changes: 197 additions & 0 deletions AI.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
#include "AI.h"
#include "Runtime.h"
#include "EventSystems.h"
#include "Data.h"
#include <functional>
#include <string>

namespace AI::CongressSupport {
// TODO: Find a way to optimize target choosers. Currently they are ran for every player (even minor civs), every turn, and for both types of outcomes.
// This is a problem with the game's base code, and could prove problematic for performance if we hook these functions by calling lua code.

static bool HandleTargetChooser(Types::Class* congressSupport, Player::Instance* player, OutcomeType outcomeType,
const std::string& name, const std::string& decisionKey, Types::TargetChooser baseChooser, void* modifierAnalysis, unsigned int fieldOffset)
{
using namespace EventSystems;
using namespace Data;

if (DoesProcessorExist(name)) {
auto variantMap = LuaVariantMap();
variantMap.emplace("OutcomeType", LuaVariant(outcomeType));
variantMap.emplace("PlayerId", LuaVariant(*(int*)((uintptr_t)player + 0xd8)));
variantMap.emplace(decisionKey, LuaVariant(*(int*)((uintptr_t)modifierAnalysis + fieldOffset)));

std::cout << "Calling Target Chooser: " << name << "!\n";

if (CallCustomProcessor(name, variantMap)) {
int decisionType = std::get<int>(variantMap.at(decisionKey));
std::cout << "Decision type: " << decisionType << '\n';
if (decisionType == -1) {
return false;
}

*(int*)((uintptr_t)modifierAnalysis + fieldOffset) = decisionType;
return true;
}
}

return baseChooser(congressSupport, player, outcomeType, modifierAnalysis);
}

Types::TargetChooser orig_District;
Types::TargetChooser base_District;
bool District(Types::Class* congressSupport, Player::Instance* player, OutcomeType outcomeType, void* modifierAnalysis) {
return HandleTargetChooser(congressSupport, player, outcomeType,
"DistrictTargetChooser", "DistrictIndex", base_District, modifierAnalysis, 0x1c);
}

Types::TargetChooser orig_UnitPromotionClass;
Types::TargetChooser base_UnitPromotionClass;
bool UnitPromotionClass(Types::Class* congressSupport, Player::Instance* player, OutcomeType outcomeType, void* modifierAnalysis) {
return HandleTargetChooser(congressSupport, player, outcomeType,
"UnitPromotionClassTargetChooser", "UnitPromotionClassIndex", base_UnitPromotionClass, modifierAnalysis, 0x58);
}

Types::TargetChooser orig_UnitBuildYield;
Types::TargetChooser base_UnitBuildYield;
bool UnitBuildYield(Types::Class* congressSupport, Player::Instance* player, OutcomeType outcomeType, void* modifierAnalysis) {
return HandleTargetChooser(congressSupport, player, outcomeType,
"UnitBuildYieldTargetChooser", "YieldIndex", base_UnitBuildYield, modifierAnalysis, 0x64);
}

Types::TargetChooser orig_TradingPartners;
Types::TargetChooser base_TradingPartners;
bool TradingPartners(Types::Class* congressSupport, Player::Instance* player, OutcomeType outcomeType, void* modifierAnalysis) {
return HandleTargetChooser(congressSupport, player, outcomeType,
"TradingPartnersTargetChooser", "TargetPlayerId", base_TradingPartners, modifierAnalysis, 0x40);
}

Types::TargetChooser orig_PlayerOrDiploLeader;
Types::TargetChooser base_PlayerOrDiploLeader;
bool PlayerOrDiploLeader(Types::Class* congressSupport, Player::Instance* player, OutcomeType outcomeType, void* modifierAnalysis) {
return HandleTargetChooser(congressSupport, player, outcomeType,
"PlayerOrDiploLeaderTargetChooser", "TargetPlayerId", base_PlayerOrDiploLeader, modifierAnalysis, 0x40);
}

// Unused normally
Types::TargetChooser orig_GreatPersonClass;
Types::TargetChooser base_GreatPersonClass;
bool GreatPersonClass(Types::Class* congressSupport, Player::Instance* player, OutcomeType outcomeType, void* modifierAnalysis) {
return HandleTargetChooser(congressSupport, player, outcomeType,
"GreatPersonClassTargetChooser", "GreatPersonClassIndex", base_GreatPersonClass, modifierAnalysis, 0x6c);
}

Types::TargetChooser orig_GreatPersonPatronage;
Types::TargetChooser base_GreatPersonPatronage;
bool GreatPersonPatronage(Types::Class* congressSupport, Player::Instance* player, OutcomeType outcomeType, void* modifierAnalysis) {
return HandleTargetChooser(congressSupport, player, outcomeType,
"GreatPersonPatronageTargetChooser", "GreatPersonClassIndex", base_GreatPersonClass, modifierAnalysis, 0x6c);
}

Types::TargetChooser orig_SpyOperation;
Types::TargetChooser base_SpyOperation;
bool SpyOperation(Types::Class* congressSupport, Player::Instance* player, OutcomeType outcomeType, void* modifierAnalysis) {
return HandleTargetChooser(congressSupport, player, outcomeType,
"SpyOperationTargetChooser", "UnitOperationIndex", base_SpyOperation, modifierAnalysis, 0x54);
}

Types::TargetChooser orig_MostCommonLuxury;
Types::TargetChooser base_MostCommonLuxury;
bool MostCommonLuxury(Types::Class* congressSupport, Player::Instance* player, OutcomeType outcomeType, void* modifierAnalysis) {
return HandleTargetChooser(congressSupport, player, outcomeType,
"MostCommonLuxuryTargetChooser", "ResourceIndex", base_MostCommonLuxury, modifierAnalysis, 0x4c);
}

Types::TargetChooser orig_MinorCivBonus;
Types::TargetChooser base_MinorCivBonus;
bool MinorCivBonus(Types::Class* congressSupport, Player::Instance* player, OutcomeType outcomeType, void* modifierAnalysis) {
return HandleTargetChooser(congressSupport, player, outcomeType,
"MinorCivBonusTargetChooser", "MinorCivBonusIndex", base_MinorCivBonus, modifierAnalysis, 0x3c);
}

Types::TargetChooser orig_GrievancesType;
Types::TargetChooser base_GrievancesType;
bool GrievancesType(Types::Class* congressSupport, Player::Instance* player, OutcomeType outcomeType, void* modifierAnalysis) {
return HandleTargetChooser(congressSupport, player, outcomeType,
"GrievancesTypeTargetChooser", "TargetPlayerId", base_GrievancesType, modifierAnalysis, 0x40);
}

int RegisterOutcomeTypes(hks::lua_State* L) {
hks::createtable(L, 0, 2);

hks::pushinteger(L, OutcomeType::A);
hks::setfield(L, -2, "A");
hks::pushinteger(L, OutcomeType::B);
hks::setfield(L, -2, "B");

hks::setfield(L, hks::LUA_GLOBAL, "OutcomeTypes");
return 0;
}

void Create() {
using namespace Runtime;

orig_District = GetGameCoreGlobalAt<Types::TargetChooser>(DISTRICT_OFFSET);
CreateHook(orig_District, &District, &base_District);

orig_UnitPromotionClass = GetGameCoreGlobalAt<Types::TargetChooser>(UNIT_PROMOTION_CLASS_OFFSET);
CreateHook(orig_UnitPromotionClass, &UnitPromotionClass, &base_UnitPromotionClass);

orig_UnitBuildYield = GetGameCoreGlobalAt<Types::TargetChooser>(UNIT_BUILD_YIELD_OFFSET);
CreateHook(orig_UnitBuildYield, &UnitBuildYield, &base_UnitBuildYield);

orig_TradingPartners = GetGameCoreGlobalAt<Types::TargetChooser>(TRADING_PARTNERS_OFFSET);
CreateHook(orig_TradingPartners, &TradingPartners, &base_TradingPartners);

orig_PlayerOrDiploLeader = GetGameCoreGlobalAt<Types::TargetChooser>(PLAYER_OR_DIPLO_LEADER_OFFSET);
CreateHook(orig_PlayerOrDiploLeader, &PlayerOrDiploLeader, &base_PlayerOrDiploLeader);

orig_GreatPersonClass = GetGameCoreGlobalAt<Types::TargetChooser>(GREAT_PERSON_CLASS_OFFSET);
CreateHook(orig_GreatPersonClass, &GreatPersonClass, &base_GreatPersonClass);

orig_GreatPersonPatronage = GetGameCoreGlobalAt<Types::TargetChooser>(GREAT_PERSON_PATRONAGE_OFFSET);
CreateHook(orig_GreatPersonPatronage, &GreatPersonPatronage, &base_GreatPersonPatronage);

orig_SpyOperation = GetGameCoreGlobalAt<Types::TargetChooser>(SPY_OPERATION_OFFSET);
CreateHook(orig_SpyOperation, &SpyOperation, &base_SpyOperation);

orig_MostCommonLuxury = GetGameCoreGlobalAt<Types::TargetChooser>(MOST_COMMON_LUXURY_OFFSET);
CreateHook(orig_MostCommonLuxury, &MostCommonLuxury, &base_MostCommonLuxury);

orig_MinorCivBonus = GetGameCoreGlobalAt<Types::TargetChooser>(MINOR_CIV_BONUS_OFFSET);
CreateHook(orig_MinorCivBonus, &MinorCivBonus, &base_MinorCivBonus);

orig_GrievancesType = GetGameCoreGlobalAt<Types::TargetChooser>(GRIEVANCES_TYPE_OFFSET);
CreateHook(orig_GrievancesType, &GrievancesType, &base_GrievancesType);
}
}

namespace AI::Espionage {
Types::GetAIEspionage GetAIEspionage;
Types::GetMostUsedSpyMission GetMostUsedSpyMission;

static int lGetMostUsedSpyMission(hks::lua_State* L) {
Player::Instance* player = Player::GetPlayerInstance(L);

hks::pushinteger(L, GetMostUsedSpyMission(GetAIEspionage(player)));
return 1;
}

int RegisterAIEspionageManager(hks::lua_State* L) {
std::cout << "Registering AIEspionageManager!\n";

hks::createtable(L, 0, 1);

PushLuaMethod(L, lGetMostUsedSpyMission, "lGetMostUsedSpyMission", -2, "GetMostUsedSpyMission");

hks::setfield(L, hks::LUA_GLOBAL, "AIEspionageManager");
return 0;
}

void Create() {
using namespace Runtime;

GetAIEspionage = GetGameCoreGlobalAt<Types::GetAIEspionage>(GET_AI_ESPIONAGE_OFFSET);
GetMostUsedSpyMission = GetGameCoreGlobalAt<Types::GetMostUsedSpyMission>(GET_MOST_USED_SPY_MISSION_OFFSET);
}
}
74 changes: 74 additions & 0 deletions AI.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#pragma once
#include "Player.h"
#include "HavokScript.h"

namespace AI {
namespace CongressSupport {
enum OutcomeType {
// For
A = 1,
// Against
B = 2
};

namespace Types {
typedef class Class;
typedef bool(__thiscall* TargetChooser)(Types::Class* congressSupport, Player::Instance* player, OutcomeType outcomeType, void* modifierAnalysis);
}

constexpr uintptr_t DISTRICT_OFFSET = 0x44e4f0;
extern bool District(Types::Class* congressSupport, Player::Instance* player, OutcomeType outcomeType, void* modifierAnalysis);

constexpr uintptr_t UNIT_PROMOTION_CLASS_OFFSET = 0x453ca0;
extern bool UnitPromotionClass(Types::Class* congressSupport, Player::Instance* player, OutcomeType outcomeType, void* modifierAnalysis);

constexpr uintptr_t UNIT_BUILD_YIELD_OFFSET = 0x4539f0;
extern bool UnitBuildYield(Types::Class* congressSupport, Player::Instance* player, OutcomeType outcomeType, void* modifierAnalysis);

constexpr uintptr_t TRADING_PARTNERS_OFFSET = 0x453850;
extern bool TradingPartners(Types::Class* congressSupport, Player::Instance* player, OutcomeType outcomeType, void* modifierAnalysis);

constexpr uintptr_t PLAYER_OR_DIPLO_LEADER_OFFSET = 0x452ce0;
extern bool PlayerOrDiploLeader(Types::Class* congressSupport, Player::Instance* player, OutcomeType outcomeType, void* modifierAnalysis);

constexpr uintptr_t GREAT_PERSON_CLASS_OFFSET = 0x44f4c0;
extern bool GreatPersonClass(Types::Class* congressSupport, Player::Instance* player, OutcomeType outcomeType, void* modifierAnalysis);

constexpr uintptr_t GREAT_PERSON_PATRONAGE_OFFSET = 0x44f570;
extern bool GreatPersonPatronage(Types::Class* congressSupport, Player::Instance* player, OutcomeType outcomeType, void* modifierAnalysis);

constexpr uintptr_t SPY_OPERATION_OFFSET = 0x453820;
extern bool SpyOperation(Types::Class* congressSupport, Player::Instance* player, OutcomeType outcomeType, void* modifierAnalysis);

constexpr uintptr_t MOST_COMMON_LUXURY_OFFSET = 0x452500;
extern bool MostCommonLuxury(Types::Class* congressSupport, Player::Instance* player, OutcomeType outcomeType, void* modifierAnalysis);

constexpr uintptr_t MINOR_CIV_BONUS_OFFSET = 0x452080;
extern bool MinorCivBonus(Types::Class* congressSupport, Player::Instance* player, OutcomeType outcomeType, void* modifierAnalysis);

constexpr uintptr_t GRIEVANCES_TYPE_OFFSET = 0x44fd20;
extern bool GrievancesType(Types::Class* congressSupport, Player::Instance* player, OutcomeType outcomeType, void* modifierAnalysis);

extern int RegisterOutcomeTypes(hks::lua_State* L);

extern void Create();
};
}

namespace AI::Espionage {
typedef class AIEspionage;
namespace Types {
typedef AIEspionage*(__thiscall* GetAIEspionage)(Player::Instance*);
typedef int(__thiscall* GetMostUsedSpyMission)(AIEspionage*);
}

constexpr uintptr_t GET_AI_ESPIONAGE_OFFSET = 0x2f7ee0;
extern Types::GetAIEspionage GetAIEspionage;

constexpr uintptr_t GET_MOST_USED_SPY_MISSION_OFFSET = 0x45ec60;
extern Types::GetMostUsedSpyMission GetMostUsedSpyMission;

extern int RegisterAIEspionageManager(hks::lua_State* L);

extern void Create();
}
47 changes: 16 additions & 31 deletions CivilizationVI_CommunityExtension.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
<ProjectGuid>{42f0ba07-c262-48e4-9df2-d3a93377e99c}</ProjectGuid>
<RootNamespace>CivilizationVICommunityExtension</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<VcpkgTriplet Condition="'$(Platform)'=='x64'">x64-windows-static</VcpkgTriplet>
<VcpkgTriplet Condition="'$(Platform)'=='x64'">x64-windows-static</VcpkgTriplet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
Expand Down Expand Up @@ -173,10 +173,11 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;ASMJIT_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;ASMJIT_STATIC;ASMJIT_NO_AARCH64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>
</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
Expand Down Expand Up @@ -216,17 +217,7 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="asmjit\arm\a64assembler.cpp" />
<ClCompile Include="asmjit\arm\a64builder.cpp" />
<ClCompile Include="asmjit\arm\a64compiler.cpp" />
<ClCompile Include="asmjit\arm\a64emithelper.cpp" />
<ClCompile Include="asmjit\arm\a64formatter.cpp" />
<ClCompile Include="asmjit\arm\a64func.cpp" />
<ClCompile Include="asmjit\arm\a64instapi.cpp" />
<ClCompile Include="asmjit\arm\a64instdb.cpp" />
<ClCompile Include="asmjit\arm\a64operand.cpp" />
<ClCompile Include="asmjit\arm\a64rapass.cpp" />
<ClCompile Include="asmjit\arm\armformatter.cpp" />
<ClCompile Include="AI.cpp" />
<ClCompile Include="asmjit\core\archtraits.cpp" />
<ClCompile Include="asmjit\core\assembler.cpp" />
<ClCompile Include="asmjit\core\builder.cpp" />
Expand Down Expand Up @@ -278,42 +269,30 @@
<ClCompile Include="City.cpp" />
<ClCompile Include="CityTradeManager.cpp" />
<ClCompile Include="CultureManager.cpp" />
<ClCompile Include="Data.cpp" />
<ClCompile Include="EconomicManager.cpp" />
<ClCompile Include="EmergencyManager.cpp" />
<ClCompile Include="EventSystems.cpp" />
<ClCompile Include="Game.cpp" />
<ClCompile Include="GameDiplomacy.cpp" />
<ClCompile Include="GovernorManager.cpp" />
<ClCompile Include="HavokScript.cpp" />
<ClCompile Include="MemoryManipulation.cpp" />
<ClCompile Include="Main.cpp" />
<ClCompile Include="NationalParks.cpp" />
<ClCompile Include="Player.cpp" />
<ClCompile Include="PlayerCities.cpp" />
<ClCompile Include="PlayerGovernors.cpp" />
<ClCompile Include="PlayerInfluence.cpp" />
<ClCompile Include="Plot.cpp" />
<ClCompile Include="Runtime.cpp" />
<ClCompile Include="Unit.cpp" />
<ClCompile Include="UnitManager.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="AI.h" />
<ClInclude Include="asmjit\a64.h" />
<ClInclude Include="asmjit\arm.h" />
<ClInclude Include="asmjit\arm\a64archtraits_p.h" />
<ClInclude Include="asmjit\arm\a64assembler.h" />
<ClInclude Include="asmjit\arm\a64builder.h" />
<ClInclude Include="asmjit\arm\a64compiler.h" />
<ClInclude Include="asmjit\arm\a64emithelper_p.h" />
<ClInclude Include="asmjit\arm\a64emitter.h" />
<ClInclude Include="asmjit\arm\a64formatter_p.h" />
<ClInclude Include="asmjit\arm\a64func_p.h" />
<ClInclude Include="asmjit\arm\a64globals.h" />
<ClInclude Include="asmjit\arm\a64instapi_p.h" />
<ClInclude Include="asmjit\arm\a64instdb.h" />
<ClInclude Include="asmjit\arm\a64instdb_p.h" />
<ClInclude Include="asmjit\arm\a64operand.h" />
<ClInclude Include="asmjit\arm\a64rapass_p.h" />
<ClInclude Include="asmjit\arm\armformatter_p.h" />
<ClInclude Include="asmjit\arm\armglobals.h" />
<ClInclude Include="asmjit\arm\armoperand.h" />
<ClInclude Include="asmjit\arm\armutils.h" />
<ClInclude Include="asmjit\asmjit-scope-begin.h" />
<ClInclude Include="asmjit\asmjit-scope-end.h" />
<ClInclude Include="asmjit\asmjit.h" />
Expand Down Expand Up @@ -389,21 +368,27 @@
<ClInclude Include="City.h" />
<ClInclude Include="CityTradeManager.h" />
<ClInclude Include="CultureManager.h" />
<ClInclude Include="EAVector.h" />
<ClInclude Include="EconomicManager.h" />
<ClInclude Include="EmergencyManager.h" />
<ClInclude Include="EventSystems.h" />
<ClInclude Include="Game.h" />
<ClInclude Include="GameDiplomacy.h" />
<ClInclude Include="Governor.h" />
<ClInclude Include="GovernorManager.h" />
<ClInclude Include="HavokScript.h" />
<ClInclude Include="MemoryManipulation.h" />
<ClInclude Include="NationalParks.h" />
<ClInclude Include="Player.h" />
<ClInclude Include="PlayerCities.h" />
<ClInclude Include="PlayerGovernors.h" />
<ClInclude Include="PlayerInfluence.h" />
<ClInclude Include="Plot.h" />
<ClInclude Include="ProxyTypes.h" />
<ClInclude Include="Runtime.h" />
<ClInclude Include="Unit.h" />
<ClInclude Include="UnitManager.h" />
<ClInclude Include="Data.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
Expand Down
Loading

0 comments on commit cc200f9

Please sign in to comment.