Skip to content

Commit

Permalink
Merge pull request #1037 from Bannerlord-Coop-Team/HastedHeroProperties
Browse files Browse the repository at this point in the history
Hero properties
  • Loading branch information
EgardA authored Dec 15, 2024
2 parents b189716 + dad918d commit ccf60b6
Show file tree
Hide file tree
Showing 5 changed files with 271 additions and 55 deletions.
173 changes: 173 additions & 0 deletions source/E2E.Tests/Services/Heroes/HeroPropertyTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
using E2E.Tests.Environment;
using E2E.Tests.Environment.Instance;
using E2E.Tests.Util;
using System.Runtime.InteropServices;
using TaleWorlds.CampaignSystem;
using TaleWorlds.CampaignSystem.Settlements.Buildings;
using TaleWorlds.CampaignSystem.Settlements;
using Xunit.Abstractions;
using TaleWorlds.Core;
using Autofac.Features.OwnedInstances;
using TaleWorlds.Localization;
using TaleWorlds.CampaignSystem.Issues;
using static TaleWorlds.CampaignSystem.Issues.BettingFraudIssueBehavior;
using TaleWorlds.CampaignSystem.Actions;
using TaleWorlds.CampaignSystem.Party;

namespace E2E.Tests.Services.Heroes
{
public class HeroPropertyTests : IDisposable
{
E2ETestEnvironment TestEnvironment { get; }

EnvironmentInstance Server => TestEnvironment.Server;

IEnumerable<EnvironmentInstance> Clients => TestEnvironment.Clients;

private string HeroId;
private string OtherHeroId;
private string ClanId;
private string SettlementId;
private string TownId;
private string MobilePartyId;
private string CivEquipmentId;
private string BattleEquipmentId;

StaticBodyProperties body = new StaticBodyProperties(1, 2, 1, 2, 1, 3, 1, 2);
float newFloat = 5f;
int newInt = 9;
long newLong = 99;
TextObject newText = new TextObject("testText");
CampaignTime newCampaignTime = new CampaignTime(999);
FormationClass newFormation = new FormationClass();
Hero.CharacterStates newCharState = Hero.CharacterStates.Released;
Occupation newOccupation = Occupation.Mercenary;
KillCharacterAction.KillCharacterActionDetail newKillAction = KillCharacterAction.KillCharacterActionDetail.Murdered;
EquipmentElement newEquipmentElement = new EquipmentElement();

public HeroPropertyTests(ITestOutputHelper output)
{
TestEnvironment = new E2ETestEnvironment(output);
}

public void Dispose()
{
TestEnvironment.Dispose();
}

[Fact]
public void Server_Sync_Hero()
{
var server = TestEnvironment.Server;
Hero hero = null;
Hero newHero = null;

server.Call(() =>
{
hero = GameObjectCreator.CreateInitializedObject<Hero>();
newHero = GameObjectCreator.CreateInitializedObject<Hero>();
Clan newClan = GameObjectCreator.CreateInitializedObject<Clan>();
Settlement newSettlement = GameObjectCreator.CreateInitializedObject<Settlement>();
Town newTown = GameObjectCreator.CreateInitializedObject<Town>();
MobileParty newMobileParty = GameObjectCreator.CreateInitializedObject<MobileParty>();

Equipment newBattleEquipment = GameObjectCreator.CreateInitializedObject<Equipment>();
Equipment newCivEquipment = GameObjectCreator.CreateInitializedObject<Equipment>();
BettingFraudIssue newIssue = new BettingFraudIssue(hero);

hero.StaticBodyProperties = body;
hero.Weight = newFloat;
hero.Build = newFloat;
hero.PassedTimeAtHomeSettlement = newFloat;
hero.EncyclopediaText = newText;
hero.IsFemale = true;
hero._battleEquipment = newBattleEquipment;
hero._civilianEquipment = newCivEquipment;
hero.CaptivityStartTime = newCampaignTime;
hero.PreferredUpgradeFormation = newFormation;
hero.HeroState = newCharState;
hero.IsMinorFactionHero = true;
hero.CompanionOf = newClan;
hero.Occupation = newOccupation;
hero.DeathMark = newKillAction;
hero.DeathMarkKillerHero = newHero;
hero.LastKnownClosestSettlement = newSettlement;
hero.DeathDay = newCampaignTime;
hero.LastExaminedLogEntryID = newLong;
hero.Clan = newClan;
hero.SupporterOf = newClan;
hero.GovernorOf = newTown;
hero.PartyBelongedTo = newMobileParty;
hero.PartyBelongedToAsPrisoner = newMobileParty.Party;
hero.StayingInSettlement = newSettlement;
hero.IsKnownToPlayer = true;
hero.HasMet = true;
hero.LastMeetingTimeWithPlayer = newCampaignTime;
hero.BornSettlement = newSettlement;
hero.Gold = newInt;
hero.RandomValue = newInt;
hero.Father = newHero;
hero.Mother = newHero;
hero.Spouse = newHero;

Assert.Equal(body, hero.StaticBodyProperties);

Assert.True(server.ObjectManager.TryGetId(hero, out HeroId));
Assert.True(server.ObjectManager.TryGetId(newHero, out OtherHeroId));
Assert.True(server.ObjectManager.TryGetId(newSettlement, out SettlementId));
Assert.True(server.ObjectManager.TryGetId(newClan, out ClanId));
Assert.True(server.ObjectManager.TryGetId(newTown, out TownId));
Assert.True(server.ObjectManager.TryGetId(newMobileParty, out MobilePartyId));
Assert.True(server.ObjectManager.TryGetId(newCivEquipment, out CivEquipmentId));
Assert.True(server.ObjectManager.TryGetId(newBattleEquipment, out BattleEquipmentId));
});

foreach (var client in Clients)
{
Assert.True(client.ObjectManager.TryGetObject<Hero>(HeroId, out var clientHero));
Assert.True(client.ObjectManager.TryGetObject<Hero>(OtherHeroId, out var clientOtherHero));
Assert.True(client.ObjectManager.TryGetObject<Settlement>(SettlementId, out var clientSettlement));
Assert.True(client.ObjectManager.TryGetObject<Clan>(ClanId, out var clientClan));
Assert.True(client.ObjectManager.TryGetObject<Town>(TownId, out var clientTown));
Assert.True(client.ObjectManager.TryGetObject<MobileParty>(MobilePartyId, out var clientMobileParty));
Assert.True(client.ObjectManager.TryGetObject<Equipment>(CivEquipmentId, out var clientCivEquipment));
Assert.True(client.ObjectManager.TryGetObject<Equipment>(BattleEquipmentId, out var clientBattleEquipment));

Assert.Equal(clientCivEquipment, clientHero._civilianEquipment);
Assert.Equal(clientBattleEquipment, clientHero._battleEquipment);
Assert.Equal(clientClan, clientHero.Clan);
Assert.Equal(clientOtherHero, clientHero.DeathMarkKillerHero);
Assert.Equal(clientSettlement, clientHero.LastKnownClosestSettlement);
Assert.Equal(clientClan, clientHero.CompanionOf);
Assert.Equal(clientClan, clientHero.SupporterOf);
Assert.Equal(clientTown, clientHero.GovernorOf);
Assert.Equal(clientMobileParty, clientHero.PartyBelongedTo);
Assert.Equal(clientMobileParty.Party, clientHero.PartyBelongedToAsPrisoner);
Assert.Equal(clientSettlement, clientHero.StayingInSettlement);
Assert.Equal(clientSettlement, clientHero.BornSettlement);
Assert.Equal(clientOtherHero, clientHero.Mother);
Assert.Equal(clientOtherHero, clientHero.Father);
Assert.Equal(clientOtherHero, clientHero.Spouse);
Assert.Equal(body, clientHero.StaticBodyProperties);
Assert.Equal(newFloat, clientHero.Weight);
Assert.Equal(newFloat, clientHero.Build);
Assert.Equal(newFloat, clientHero.PassedTimeAtHomeSettlement);
Assert.Equal(newText.Value, clientHero.EncyclopediaText.Value);
Assert.True(clientHero.IsFemale);
Assert.Equal(newCampaignTime, clientHero.CaptivityStartTime);
Assert.Equal(newFormation, clientHero.PreferredUpgradeFormation);
Assert.Equal(newCharState, clientHero.HeroState);
Assert.True(clientHero.IsMinorFactionHero);
Assert.Equal(newOccupation, clientHero.Occupation);
Assert.Equal(newKillAction, clientHero.DeathMark);
Assert.Equal(newCampaignTime, clientHero.DeathDay);
Assert.Equal(newLong, clientHero.LastExaminedLogEntryID);
Assert.True(clientHero.IsKnownToPlayer);
Assert.True(clientHero.HasMet);
Assert.Equal(newCampaignTime, clientHero.LastMeetingTimeWithPlayer);
Assert.Equal(newInt, clientHero.Gold);
Assert.Equal(newInt, clientHero.RandomValue);
}
}
}
}
95 changes: 42 additions & 53 deletions source/E2E.Tests/Services/Heroes/HeroSetNameTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using E2E.Tests.Environment;
using E2E.Tests.Environment.Instance;
using E2E.Tests.Util;
using TaleWorlds.CampaignSystem;
using TaleWorlds.Localization;
using Xunit.Abstractions;
Expand All @@ -8,6 +10,9 @@ namespace E2E.Tests.Services.Heroes;
public class HeroSetNameTests : IDisposable
{
E2ETestEnvironment TestEnvironment { get; }

IEnumerable<EnvironmentInstance> Clients => TestEnvironment.Clients;

public HeroSetNameTests(ITestOutputHelper output)
{
TestEnvironment = new E2ETestEnvironment(output);
Expand All @@ -24,37 +29,31 @@ public void ServerSetName_SyncAllClients()
// Arrange
var server = TestEnvironment.Server;

var networkId = "CoopHero_1";
// Creates a new hero and registers it with the objectManager
// using the networkId as an identifier
var serverHero = TestEnvironment.Server.CreateRegisteredObject<Hero>(networkId);

// Creates and stores heroes on the clients with same id as server
var clientHeroes = new List<Hero>();
foreach(var client in TestEnvironment.Clients)
{
clientHeroes.Add(client.CreateRegisteredObject<Hero>(networkId));
}
string HeroId = null;

// Create new text objects for name fields
var fullName = new TextObject("Test Name");
var firstName = new TextObject("Name");
// Create new text objects for name fields for server to set
var originalFullName = new TextObject("Test Name");
var originalFirstName = new TextObject("Name");

// Act
server.Call(() =>
{
serverHero.SetName(fullName, firstName);
});
Hero hero = GameObjectCreator.CreateInitializedObject<Hero>();
hero.SetName(originalFullName, originalFirstName);

// Assert
Assert.Equal(fullName.Value, serverHero.Name.Value);
Assert.Equal(firstName.Value, serverHero.FirstName.Value);
server.ObjectManager.TryGetId(hero, out HeroId);

// Assert
Assert.Equal(originalFullName.Value, hero.Name.Value);
Assert.Equal(originalFirstName.Value, hero.FirstName.Value);
});

foreach (var clientHero in clientHeroes)
foreach(var client in Clients)
{
Assert.Equal(fullName.Value, clientHero.Name.Value);
Assert.Equal(firstName.Value, clientHero.FirstName.Value);
client.ObjectManager.TryGetObject(HeroId, out Hero hero);

Assert.Equal(originalFullName.Value, hero.Name.Value);
Assert.Equal(originalFirstName.Value, hero.FirstName.Value);
}
}

Expand All @@ -65,53 +64,43 @@ public void ClientSetName_DoesNothing()
var server = TestEnvironment.Server;
var client1 = TestEnvironment.Clients.First();

var networkId = "CoopHero_1";

// Creates a new hero and registers it with the objectManager
// using the networkId as an identifier
var serverHero = TestEnvironment.Server.CreateRegisteredObject<Hero>(networkId);

// Creates and stores heroes on the clients with same id as server
var clientHeroes = new List<Hero>();
foreach (var client in TestEnvironment.Clients)
{
clientHeroes.Add(client.CreateRegisteredObject<Hero>(networkId));
}
string HeroId = null;

// Create new text objects for name fields for server to set
var originalFullName = new TextObject("Test Name");
var originalFirstName = new TextObject("Name");

server.Call(() =>
{
serverHero.SetName(originalFullName, originalFirstName);
});

// Create new text objects for name fields for client to attempt to set
// expected that it does not change
var differentFullName = new TextObject("Dont set me");
var differentFirstName = new TextObject("Dont set me");

// Act
client1.Call(() =>
server.Call(() =>
{
clientHeroes.First().SetName(differentFullName, differentFirstName);
});
Hero hero = GameObjectCreator.CreateInitializedObject<Hero>();
hero.SetName(originalFullName, originalFirstName);

// Assert
Assert.Equal(originalFullName.Value, serverHero.Name.Value);
Assert.Equal(originalFirstName.Value, serverHero.FirstName.Value);
server.ObjectManager.TryGetId(hero, out HeroId);

Assert.NotEqual(differentFullName.Value, serverHero.Name.Value);
Assert.NotEqual(differentFirstName.Value, serverHero.FirstName.Value);
// Assert
Assert.Equal(originalFullName.Value, hero.Name.Value);
Assert.Equal(originalFirstName.Value, hero.FirstName.Value);

foreach (var clientHero in clientHeroes)
Assert.NotEqual(differentFullName.Value, hero.Name.Value);
Assert.NotEqual(differentFirstName.Value, hero.FirstName.Value);
});

client1.Call(() =>
{
Assert.Equal(originalFullName.Value, clientHero.Name.Value);
Assert.Equal(originalFirstName.Value, clientHero.FirstName.Value);
client1.ObjectManager.TryGetObject(HeroId, out Hero hero);
hero.SetName(differentFullName, differentFirstName);

Assert.NotEqual(differentFullName.Value, clientHero.Name.Value);
Assert.NotEqual(differentFirstName.Value, clientHero.FirstName.Value);
}
Assert.Equal(originalFullName.Value, hero.Name.Value);
Assert.Equal(originalFirstName.Value, hero.FirstName.Value);

Assert.NotEqual(differentFullName.Value, hero.Name.Value);
Assert.NotEqual(differentFirstName.Value, hero.FirstName.Value);
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ private static bool ctorPrefix(ref CultureObject __instance)
Logger.Error("Client created unmanaged {name}\n"
+ "Callstack: {callstack}", typeof(CultureObject), Environment.StackTrace);

return true;
return false;
}

var message = new CultureObjectCreated(__instance);
Expand Down
4 changes: 3 additions & 1 deletion source/GameInterface/Services/Heroes/HeroRegistry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System;
using System.Linq;
using System.Reflection;
using System.Threading;
using TaleWorlds.CampaignSystem;
using TaleWorlds.CampaignSystem.Party;

Expand All @@ -14,6 +15,7 @@ namespace GameInterface.Services.Registry;
internal class HeroRegistry : RegistryBase<Hero>
{
public static readonly string HeroStringIdPrefix = "CoopHero";
private int InstanceCounter = 0;

public HeroRegistry(IRegistryCollection collection) : base(collection) { }

Expand Down Expand Up @@ -45,7 +47,7 @@ public override bool RegisterExistingObject(string id, object obj)

protected override string GetNewId(Hero hero)
{
hero.StringId = Campaign.Current.CampaignObjectManager.FindNextUniqueStringId<Hero>(HeroStringIdPrefix);
hero.StringId = $"{HeroStringIdPrefix}_{Interlocked.Increment(ref InstanceCounter)}";
return hero.StringId;
}

Expand Down
Loading

0 comments on commit ccf60b6

Please sign in to comment.