diff --git a/Commands/MiscCommands.cs b/Commands/MiscCommands.cs
index 3a55d6d..761cf4b 100644
--- a/Commands/MiscCommands.cs
+++ b/Commands/MiscCommands.cs
@@ -11,12 +11,12 @@
using Stunlock.Core;
using Unity.Entities;
using VampireCommandFramework;
-using static Bloodcraft.Services.DataService.PlayerDictionaries;
using static Bloodcraft.Services.PlayerService;
using static VCF.Core.Basics.RoleCommands;
using User = ProjectM.Network.User;
namespace Bloodcraft.Commands;
+
internal static class MiscCommands
{
static EntityManager EntityManager => Core.EntityManager;
@@ -84,9 +84,18 @@ public static void KitMe(ChatCommandContext ctx)
ServerGameManager.TryAddInventoryItem(character, item.Key, item.Value);
}
- string kitItems = KitPrefabs.Select(x => $"{x.Key.GetPrefabName()}")
- .Aggregate((x, y) => $"{x}, {y}");
- LocalizationService.HandleReply(ctx, $"You've received a starting kit with {kitItems}!");
+ List kitItems = KitPrefabs.Select(x => $"{x.Key.GetPrefabName()}").ToList();
+
+ LocalizationService.HandleReply(ctx, $"You've received a starting kit with:");
+
+ const int maxPerMessage = 6;
+ for (int i = 0; i < kitItems.Count; i += maxPerMessage)
+ {
+ var batch = kitItems.Skip(i).Take(maxPerMessage);
+ string items = string.Join(", ", batch);
+
+ LocalizationService.HandleReply(ctx, $"{items}");
+ }
}
else
{
@@ -258,10 +267,11 @@ public static void CleanUpFams(ChatCommandContext ctx)
});
int counter = 0;
+
try
{
- Dictionary FamiliarActives = new(familiarActives);
- List dismissedFamiliars = familiarActives.Values.Select(x => x.Familiar).ToList();
+ Dictionary FamiliarActives = new(DataService.PlayerDictionaries.familiarActives);
+ List dismissedFamiliars = FamiliarActives.Values.Select(x => x.Familiar).ToList();
IEnumerable disabledFamiliars = EntityUtilities.GetEntitiesEnumerable(familiarsQuery); // need to filter for active/dismissed familiars and not destroy them
foreach (Entity entity in disabledFamiliars)
@@ -269,14 +279,14 @@ public static void CleanUpFams(ChatCommandContext ctx)
if (dismissedFamiliars.Contains(entity)) continue;
else
{
- if (entity.GetTeamEntity().Has() && entity.ReadBuffer()[0].DropTrigger.Equals(DropTriggerType.OnSalvageDestroy))
+ if (entity.TryGetTeamEntity(out Entity teamEntity) && teamEntity.Has() && entity.TryGetBuffer(out var buffer) && buffer[0].DropTrigger.Equals(DropTriggerType.OnSalvageDestroy))
{
if (entity.Has())
{
entity.Remove();
if (entity.Has()) entity.Remove();
- if (entity.Has()) entity.Remove();
-
+ if (entity.Has()) entity.Remove();
+
EntityManager.DestroyEntity(entity);
counter++;
}
@@ -297,6 +307,7 @@ public static void CleanUpFams(ChatCommandContext ctx)
});
counter = 0;
+
try
{
IEnumerable networkedSequences = EntityUtilities.GetEntitiesEnumerable(networkedSequencesQuery);
@@ -312,6 +323,10 @@ public static void CleanUpFams(ChatCommandContext ctx)
if (secondaryTarget.TryGetComponent(out PrefabGUID secondaryTargetPrefab) && secondaryTarget.Has())
{
+ if (secondaryTarget.Has()) secondaryTarget.Remove();
+ if (secondaryTarget.Has()) secondaryTarget.Remove();
+ if (secondaryTarget.Has()) secondaryTarget.Remove();
+
DestroyUtility.Destroy(EntityManager, secondaryTarget, DestroyDebugReason.None);
counter++;
}
@@ -374,92 +389,4 @@ public static void CleanUpFams(ChatCommandContext ctx)
LocalizationService.HandleReply(ctx, $"Destroyed {counter} entities found in player FollowerBuffers and MinionBuffers...");
}
-
- /*
- [Command(name: "switcheroo", adminOnly: true, usage: ".switch [OriginalPlayer] [NewPlayer]", description: "Swaps the steamIDs of two players for testing.")] // this is just swapplayers without kicking people to use their mod data, ty Odjit <3 don't feel like finding out if it works like I think it will right now so commenting out >_>
- public static void SwitchPlayers(ChatCommandContext ctx, string originalPlayer, string newPlayer)
- {
- if (originalPlayer.TryGetPlayerInfo(out PlayerInfo originalPlayerInfo) && newPlayer.TryGetPlayerInfo(out PlayerInfo newPlayerInfo))
- {
- Entity originalUserEntity = originalPlayerInfo.UserEntity;
- Entity newUserEntity = newPlayerInfo.UserEntity;
-
- User originalUser = originalUserEntity.Read();
- User newUser = newUserEntity.Read();
-
- (originalUser.PlatformId, newUser.PlatformId) = (newUser.PlatformId, originalUser.PlatformId);
-
- originalUserEntity.Write(originalUser);
- newUserEntity.Write(newUser);
-
- ctx.Reply($"Switched steamIds for {originalPlayerInfo.User.CharacterName} with {newPlayerInfo.User.CharacterName}!");
- }
- }
-
- [Command(name: "bloblog", shortHand:"blob", adminOnly: true, usage: ".blob [PrefabGUID]", description: "BlobString testing.")]
- public static void BlobStringLogCommand(ChatCommandContext ctx, int guidHash)
- {
- if (!Core.SystemService.PrefabCollectionSystem._PrefabGuidToEntityMap.TryGetValue(new(guidHash), out Entity prefabEntity))
- {
- ctx.Reply("Couldn't find prefab...");
- return;
- }
- else if (prefabEntity.TryGetComponent(out AbilityCastCondition castCondition))
- {
- unsafe
- {
- BlobAssetReference blobAssetReference = castCondition.Condition;
- ConditionBlob* conditionBlob = (ConditionBlob*)blobAssetReference.GetUnsafePtr();
- ConditionInfo conditionInfo = conditionBlob->Info;
-
- ReadBlobString(ref conditionInfo);
- }
- }
- else
- {
- ctx.Reply("AbilityCastCondition not found on prefab entity...");
- }
- }
- unsafe static void ReadBlobString(ref ConditionInfo conditionInfo)
- {
- // Get a pointer to the ConditionInfo structure
- fixed (ConditionInfo* conditionInfoPtr = &conditionInfo)
- {
- // Get the pointer to the Prefab BlobString
- BlobString* prefabBlobStringPtr = &conditionInfoPtr->Prefab;
-
- // Read the Prefab string
- string prefabName = ParseBlobString(prefabBlobStringPtr);
-
- // Get the pointer to the Component BlobString
- BlobString* componentBlobStringPtr = &conditionInfoPtr->Component;
-
- // Read the Component string
- string componentName = ParseBlobString(componentBlobStringPtr);
-
- // Now you can log or use the strings as needed
- Core.Log.LogInfo($"Prefab: {prefabName}");
- Core.Log.LogInfo($"Component: {componentName}");
- }
- }
- unsafe static string ParseBlobString(BlobString* blobStringPtr)
- {
- // Get a pointer to the BlobArray Data field
- BlobArray* dataPtr = &blobStringPtr->Data;
-
- // Get the base pointer, which is the address of the m_OffsetPtr field
- byte* basePtr = (byte*)&dataPtr->m_OffsetPtr;
-
- // Compute the data pointer using the offset
- byte* bytes = basePtr + dataPtr->m_OffsetPtr;
-
- // Read the length from the m_Length field
- int length = dataPtr->m_Length;
-
- // Convert the bytes to a string using UTF8 encoding
- string result = BlobString.ToString(bytes, length);
-
- return result;
- }
- */
-}
+}
\ No newline at end of file
diff --git a/Commands/WeaponCommands.cs b/Commands/WeaponCommands.cs
index 259acbf..792f0fa 100644
--- a/Commands/WeaponCommands.cs
+++ b/Commands/WeaponCommands.cs
@@ -4,8 +4,13 @@
using ProjectM;
using ProjectM.Scripting;
using ProjectM.Shared;
+using Steamworks;
using Stunlock.Core;
+using Unity.Collections;
using Unity.Entities;
+using Unity.Mathematics;
+using Unity.Transforms;
+using UnityEngine.TextCore.Text;
using VampireCommandFramework;
using static Bloodcraft.Services.PlayerService;
using static Bloodcraft.Systems.Expertise.WeaponManager;
@@ -260,42 +265,87 @@ public static void ListWeaponsCommand(ChatCommandContext ctx)
LocalizationService.HandleReply(ctx, $"Available Weapon Expertises: {weaponTypes}");
}
- [Command(name: "setspells", shortHand: "spell", adminOnly: true, usage: ".wep spell [Name] [Slot] [PrefabGUID]", description: "Manually sets spells for testing.")]
- public static void SetSpellCommand(ChatCommandContext ctx, string name, int slot, int ability)
+ [Command(name: "setspells", shortHand: "spell", adminOnly: true, usage: ".wep spell [Name] [Slot] [PrefabGUID] [Radius]", description: "Manually sets spells for testing (if you enter a radius it will apply to players around the entered name).")]
+ public static void SetSpellCommand(ChatCommandContext ctx, string name, int slot, int ability, float radius = 0f)
{
if (!ConfigService.UnarmedSlots)
{
LocalizationService.HandleReply(ctx, "Extra spell slots are not enabled.");
return;
}
+
if (slot < 1 || slot > 2)
{
- LocalizationService.HandleReply(ctx, "Invalid slot.");
+ LocalizationService.HandleReply(ctx, "Invalid slot (1 for Q or 2 for E)");
return;
}
- PlayerInfo playerInfo = PlayerCache.FirstOrDefault(kvp => kvp.Key.ToLower() == name.ToLower()).Value;
- if (!playerInfo.UserEntity.Exists())
+ if (radius > 0f)
{
- ctx.Reply($"Couldn't find player.");
- return;
- }
+ Entity character = ctx.Event.SenderCharacterEntity;
+ float3 charPosition = character.Read().Value;
+
+ HashSet processed = [];
+ Dictionary players = new(OnlineCache);
- ulong SteamID = playerInfo.User.PlatformId;
+ foreach (PlayerInfo playerInfo in players.Values)
+ {
+ if (processed.Contains(playerInfo)) continue;
+ else if (playerInfo.CharEntity.TryGetComponent(out Translation translation) && math.distance(charPosition, translation.Value) <= radius)
+ {
+ ulong steamId = playerInfo.User.PlatformId;
- if (SteamID.TryGetPlayerSpells(out var spells))
+ if (steamId.TryGetPlayerSpells(out var spells))
+ {
+ if (slot == 1)
+ {
+ spells.FirstUnarmed = ability;
+ LocalizationService.HandleReply(ctx, $"First unarmed slot set to {new PrefabGUID(ability).LookupName()} for {playerInfo.User.CharacterName.Value}.");
+ }
+ else if (slot == 2)
+ {
+ spells.SecondUnarmed = ability;
+ LocalizationService.HandleReply(ctx, $"Second unarmed slot set to {new PrefabGUID(ability).LookupName()} for {playerInfo.User.CharacterName.Value}.");
+ }
+
+ steamId.SetPlayerSpells(spells);
+ }
+
+ processed.Add(playerInfo);
+ }
+ }
+ }
+ else if (radius < 0f)
{
- if (slot == 1)
+ LocalizationService.HandleReply(ctx, "Radius must be positive if entering a value!");
+ return;
+ }
+ else
+ {
+ PlayerInfo playerInfo = PlayerCache.FirstOrDefault(kvp => kvp.Key.ToLower() == name.ToLower()).Value;
+ if (!playerInfo.UserEntity.Exists())
{
- spells.FirstUnarmed = ability;
- LocalizationService.HandleReply(ctx, $"First unarmed slot set to {new PrefabGUID(ability).LookupName()} for {playerInfo.User.CharacterName.Value}.");
+ ctx.Reply($"Couldn't find player.");
+ return;
}
- else
+
+ ulong steamId = playerInfo.User.PlatformId;
+
+ if (steamId.TryGetPlayerSpells(out var spells))
{
- spells.SecondUnarmed = ability;
- LocalizationService.HandleReply(ctx, $"Second unarmed slot set to {new PrefabGUID(ability).LookupName()} for {playerInfo.User.CharacterName.Value}.");
+ if (slot == 1)
+ {
+ spells.FirstUnarmed = ability;
+ LocalizationService.HandleReply(ctx, $"First unarmed slot set to {new PrefabGUID(ability).LookupName()} for {playerInfo.User.CharacterName.Value}.");
+ }
+ else if (slot == 2)
+ {
+ spells.SecondUnarmed = ability;
+ LocalizationService.HandleReply(ctx, $"Second unarmed slot set to {new PrefabGUID(ability).LookupName()} for {playerInfo.User.CharacterName.Value}.");
+ }
+
+ steamId.SetPlayerSpells(spells);
}
- SteamID.SetPlayerSpells(spells);
}
}
diff --git a/Core.cs b/Core.cs
index 1f15819..2756b6f 100644
--- a/Core.cs
+++ b/Core.cs
@@ -61,7 +61,7 @@ public static void Initialize()
//DeathEventListenerSystemPatch.OnDeathEvent += FamiliarLevelingSystem.OnUpdate;
DeathEventListenerSystemPatch.OnDeathEvent += FamiliarUnlockSystem.OnUpdate;
}
-
+
/*
foreach (var kvp in Server.m_SystemLookup)
{
@@ -83,11 +83,9 @@ public static void Initialize()
}
*/
- //CleanSCTPRefabs();
-
OLD_SHARED_KEY = Convert.FromBase64String(SecretManager.GetOldSharedKey());
NEW_SHARED_KEY = Convert.FromBase64String(SecretManager.GetNewSharedKey());
-
+
hasInitialized = true;
}
static World GetServerWorld()
@@ -104,115 +102,4 @@ public static void StartCoroutine(IEnumerator routine)
MonoBehaviour.StartCoroutine(routine.WrapToIl2Cpp());
}
-
- /*
- static void OverrideVBloodMenuLevels()
- {
- Il2CppSystem.Collections.Generic.List vBloodUnitSettings = SystemService.ServerGameSettingsSystem._Settings.VBloodUnitSettings;
- List shardBearers = SpawnTransformSystemOnSpawnPatch.shardBearers.Select(x => x._Value).ToList();
-
- foreach (VBloodUnitSetting vBloodUnitSetting in vBloodUnitSettings)
- {
- if (shardBearers.Contains(vBloodUnitSetting.UnitId))
- {
- vBloodUnitSetting.UnitLevel = (byte)ConfigService.ShardBearerLevel;
- }
- }
-
- SystemService.ServerGameSettingsSystem._Settings.VBloodUnitSettings = vBloodUnitSettings;
-
- SystemService.ServerBootstrapSystem._SteamPlatformSystem.SetServerSettings(SystemService.ServerGameSettingsSystem._Settings.ToStruct(true));
- SystemService.ServerBootstrapSystem._SteamPlatformSystem.SetServerGameSettingsHash(SystemService.ServerGameSettingsSystem._Settings);
-
- SystemService.ServerBootstrapSystem.ReloadSettings();
- }
- */
-
- /*
- static readonly PrefabGUID SCTPrefab = new(-1661525964);
-
- static readonly ComponentType[] PrefabGUIDComponent =
- [
- ComponentType.ReadOnly(Il2CppType.Of()),
- ];
-
- static readonly PrefabGUID UndeadLeader = new(-1365931036);
- static void CleanSCTPRefabs()
- {
- EntityQuery prefabGUIDQuery = EntityManager.CreateEntityQuery(new EntityQueryDesc
- {
- All = PrefabGUIDComponent,
- Options = EntityQueryOptions.IncludeDisabled
- });
-
- NativeArray entities = prefabGUIDQuery.ToEntityArray(Allocator.TempJob);
-
- Entity Kriig = Entity.Null;
- int sctCounter = 0;
- int targetCounter = 0;
- try
- {
- foreach (Entity entity in entities)
- {
- if (!entity.Has() && entity.TryGetComponent(out PrefabGUID prefabGUID))
- {
- if (prefabGUID.Equals(SCTPrefab))
- {
- ScrollingCombatTextMessage scrollingCombatTextMessage = entity.Read();
- Entity targetEntity = scrollingCombatTextMessage.Target.GetEntityOnServer();
-
- if (targetEntity.Exists() && targetEntity.TryGetComponent(out PrefabGUID targetPrefabGUID) && targetEntity.TryGetComponent(out EntityOwner owner))
- {
- if (owner.Owner.Exists() && owner.Owner.IsPlayer())
- {
- //ownedPrefabGUIDs.Add(targetPrefabGUID);
- //Log.LogInfo($"{targetPrefabGUID.LookupName()} | {owner.Owner.Read().Name.Value}");
- }
- else if (owner.Owner.Exists() && owner.Owner.TryGetComponent(out PrefabGUID ownerPrefabGUID))
- {
- //Log.LogInfo($"{targetPrefabGUID.LookupName()} | {ownerPrefabGUID.LookupName()}");
- }
-
- if (targetEntity.Has()) continue;
-
- DestroyUtility.Destroy(EntityManager, targetEntity);
- targetCounter++;
- }
-
- if (entity.Has()) continue;
-
- DestroyUtility.Destroy(EntityManager, entity);
- sctCounter++;
- }
- else if (prefabGUID.Equals(UndeadLeader))
- {
- entity.LogComponentTypes();
- if (entity.Has())
- {
- entity.Remove();
- if (entity.Has()) entity.Remove();
- if (entity.Has()) entity.Remove();
-
- Kriig = entity;
- DestroyUtility.Destroy(EntityManager, entity);
- //Log.LogInfo("Destroyed Undead Leader...");
- }
- }
- }
- }
- }
- finally
- {
- entities.Dispose();
- prefabGUIDQuery.Dispose();
- Log.LogWarning($"Destroyed {sctCounter} | {targetCounter} SCT prefab entities and targets...");
-
- if (Kriig.Exists())
- {
- EntityManager.DestroyEntity(Kriig);
- Log.LogInfo("Still exists, using alternate destroy method...");
- }
- }
- }
- */
}
diff --git a/Extensions.cs b/Extensions.cs
index 9dd9174..145d102 100644
--- a/Extensions.cs
+++ b/Extensions.cs
@@ -85,6 +85,17 @@ public static bool TryGetComponent(this Entity entity, out T componentData) w
return false;
}
+ public static bool TryRemoveComponent(this Entity entity) where T : struct
+ {
+ if (entity.Has())
+ {
+ entity.Remove();
+
+ return true;
+ }
+
+ return false;
+ }
public static bool Has(this Entity entity)
{
var ct = new ComponentType(Il2CppType.Of());
@@ -102,23 +113,26 @@ public static string GetPrefabName(this PrefabGUID itemPrefabGUID)
public static void LogComponentTypes(this Entity entity)
{
NativeArray.Enumerator enumerator = EntityManager.GetComponentTypes(entity).GetEnumerator();
+
Core.Log.LogInfo("===");
+
while (enumerator.MoveNext())
{
ComponentType current = enumerator.Current;
Core.Log.LogInfo($"{current}");
}
+
Core.Log.LogInfo("===");
+
+ enumerator.Dispose();
}
public static void Add(this Entity entity)
{
- var ct = new ComponentType(Il2CppType.Of());
- EntityManager.AddComponent(entity, ct);
+ EntityManager.AddComponent(entity, new(Il2CppType.Of()));
}
public static void Remove(this Entity entity)
{
- var ct = new ComponentType(Il2CppType.Of());
- EntityManager.RemoveComponent(entity, ct);
+ EntityManager.RemoveComponent(entity, new(Il2CppType.Of()));
}
public static Entity GetOwner(this Entity entity)
{
@@ -157,6 +171,16 @@ public static bool IsPlayer(this Entity entity)
{
return true;
}
+
+ return false;
+ }
+ public static bool IsDifferentPlayer(this Entity entity, Entity target)
+ {
+ if (entity.IsPlayer() && target.IsPlayer() && !entity.Equals(target))
+ {
+ return true;
+ }
+
return false;
}
public static bool IsFollowingPlayer(this Entity entity)
@@ -169,6 +193,7 @@ public static bool IsFollowingPlayer(this Entity entity)
return true;
}
}
+
return false;
}
public static Entity GetBuffTarget(this Entity entity)
@@ -183,13 +208,23 @@ public static Entity GetSpellTarget(this Entity entity)
{
return CreateGameplayEventServerUtility.GetSpellTarget(EntityManager, entity);
}
- public static Entity GetTeamEntity(this Entity entity)
+ public static bool TryGetTeamEntity(this Entity entity, out Entity teamEntity)
{
- if (entity.Has())
+ teamEntity = Entity.Null;
+
+ if (entity.TryGetComponent(out TeamReference teamReference))
{
- return entity.Read().Value._Value;
+ Entity teamReferenceEntity = teamReference.Value._Value;
+
+ if (teamReferenceEntity.Exists())
+ {
+ teamEntity = teamReferenceEntity;
+
+ return true;
+ }
}
- return Entity.Null;
+
+ return false;
}
public static bool Exists(this Entity entity)
{
@@ -246,7 +281,9 @@ public static Entity GetUserEntity(this Entity character)
public static User GetUser(this Entity character)
{
User user = User.Empty;
+
if (character.TryGetComponent(out PlayerCharacter playerCharacter) && playerCharacter.UserEntity.TryGetComponent(out user)) return user;
+
return user;
}
public static bool HasBuff(this Entity entity, PrefabGUID buffPrefabGUID)
@@ -262,4 +299,17 @@ public static bool TryGetBuff(this Entity entity, PrefabGUID buffPrefabGUID, out
return false;
}
+ public static unsafe bool TryGetBuffer(this Entity entity, out DynamicBuffer dynamicBuffer) where T : struct
+ {
+ if (ServerGameManager.TryGetBuffer(entity, out dynamicBuffer))
+ {
+ return true;
+ }
+
+ return false;
+ }
+ public static void Remove(this Entity entity, EntityCommandBuffer entityCommandBuffer)
+ {
+ entityCommandBuffer.RemoveComponent(entity, new(Il2CppType.Of()));
+ }
}
\ No newline at end of file
diff --git a/Patches/BehaviourStateChangedSystemPatch.cs b/Patches/BehaviourStateChangedSystemPatch.cs
index ea0d35d..732e1db 100644
--- a/Patches/BehaviourStateChangedSystemPatch.cs
+++ b/Patches/BehaviourStateChangedSystemPatch.cs
@@ -4,7 +4,6 @@
using ProjectM;
using ProjectM.Behaviours;
using ProjectM.Gameplay.Systems;
-using Stunlock.Core;
using Unity.Collections;
using Unity.Entities;
@@ -15,9 +14,6 @@ namespace Bloodcraft.Patches;
{
static EntityManager EntityManager => Core.EntityManager;
- static readonly PrefabGUID TailorFleeBuff = new(-530519474);
- static readonly PrefabGUID WandererFleeBuff = new(573463911);
-
[HarmonyPatch(typeof(CreateGameplayEventOnBehaviourStateChangedSystem), nameof(CreateGameplayEventOnBehaviourStateChangedSystem.OnUpdate))]
[HarmonyPrefix]
static void OnUpdatePrefix(CreateGameplayEventOnBehaviourStateChangedSystem __instance)
@@ -51,7 +47,7 @@ static void OnUpdatePrefix(CreateGameplayEventOnBehaviourStateChangedSystem __in
{
Entity familiar = behaviourTreeStateChangedEvent.Entity;
- FamiliarUtilities.ReturnFamiliar(player, familiar);
+ FamiliarUtilities.TryReturnFamiliar(player, familiar);
}
}
}
diff --git a/Patches/BuffSpawnServerPatches.cs b/Patches/BuffSpawnServerPatches.cs
index cac7d9b..f091344 100644
--- a/Patches/BuffSpawnServerPatches.cs
+++ b/Patches/BuffSpawnServerPatches.cs
@@ -49,6 +49,8 @@ internal static class BuffSystemSpawnPatches
static readonly PrefabGUID WitchPigTransformationBuff = new(1356064917);
+ static readonly PrefabGUID WranglerPotionBuff = new(387154469);
+
[HarmonyPatch(typeof(BuffSystem_Spawn_Server), nameof(BuffSystem_Spawn_Server.OnUpdate))]
[HarmonyPrefix]
static void OnUpdatePrefix(BuffSystem_Spawn_Server __instance)
@@ -143,7 +145,7 @@ static void OnUpdatePrefix(BuffSystem_Spawn_Server __instance)
if (familiar.Exists())
{
- FamiliarUtilities.ReturnFamiliar(player, familiar);
+ FamiliarUtilities.TryReturnFamiliar(player, familiar);
}
}
}
@@ -158,7 +160,7 @@ static void OnUpdatePrefix(BuffSystem_Spawn_Server __instance)
if (familiar.Exists())
{
- FamiliarUtilities.ReturnFamiliar(player, familiar);
+ FamiliarUtilities.TryReturnFamiliar(player, familiar);
if (!FamiliarPvP) FamiliarUtilities.UnbindFamiliar(player, userEntity, steamId);
}
@@ -183,24 +185,13 @@ static void OnUpdatePrefix(BuffSystem_Spawn_Server __instance)
if (entity.Has()) entity.Remove();
}
- if (Familiars) // player->familiar potion sharing
+ if (Familiars && !prefabGUID.Equals(WranglerPotionBuff)) // player->familiar potion sharing
{
Entity familiar = FamiliarUtilities.FindPlayerFamiliar(player);
if (familiar.Exists())
{
- ApplyBuffDebugEvent applyBuffDebugEvent = new()
- {
- BuffPrefabGUID = prefabGUID,
- };
-
- FromCharacter fromCharacter = new()
- {
- Character = familiar,
- User = familiar
- };
-
- DebugEventsSystem.ApplyBuff(fromCharacter, applyBuffDebugEvent);
+ BuffUtilities.TryApplyBuff(familiar, prefabGUID);
}
}
@@ -380,7 +371,7 @@ static void HandlePvECombat(Entity buffTarget)
if (EntityManager.Exists(familiar))
{
- FamiliarUtilities.ReturnFamiliar(playerCharacter, familiar);
+ FamiliarUtilities.TryReturnFamiliar(playerCharacter, familiar);
}
}
}
diff --git a/Patches/DealDamageSystemPatch.cs b/Patches/DealDamageSystemPatch.cs
index f3908b4..12b1504 100644
--- a/Patches/DealDamageSystemPatch.cs
+++ b/Patches/DealDamageSystemPatch.cs
@@ -75,20 +75,20 @@ static void OnUpdatePrefix(DealDamageSystem __instance)
else if (!dealDamageEvent.Target.Exists() || !dealDamageEvent.SpellSource.Exists()) continue; // checks are kind of excessive here but null entities in this system can reeeeally mess things up for a save
else if (dealDamageEvent.SpellSource.TryGetComponent(out PrefabGUID sourcePrefabGUID) && (sourcePrefabGUID.Equals(silverDebuff) || sourcePrefabGUID.Equals(garlicDebuff))) continue; // skip if source is silver or garlic
- if (!dealDamageEvent.SpellSource.TryGetComponent(out EntityOwner entityOwner) || !entityOwner.Owner.Exists()) continue; // not really sure why this would be the case but seems to be popping up in console so okay I guess
+ if (!dealDamageEvent.SpellSource.TryGetComponent(out EntityOwner entityOwner) || !entityOwner.Owner.Exists()) continue;
- //Core.Log.LogInfo(dealDamageEvent.SpellSource.GetPrefabGUID().LookupName());
- //Core.Log.LogInfo($"{dealDamageEvent.SpellSource.GetOwner().GetPrefabGUID().LookupName()} | {dealDamageEvent.Target.GetPrefabGUID().LookupName()}");
-
- if (entityOwner.Owner.IsFollowingPlayer() && dealDamageEvent.Target.IsPlayer() && ServerGameManager.IsAllies(entityOwner.Owner, dealDamageEvent.Target)) // not sure if any fam besides raziel does this
+ if (entityOwner.Owner.TryGetFollowedPlayer(out Entity player)) // not sure if any fam besides raziel does this
{
- //DestroyUtility.Destroy(EntityManager, entity);
- EntityManager.DestroyEntity(entity); // need to destroy with main entityManager, destroyEvent not sufficient to prevent damage
+ //if (dealDamageEvent.Target.IsPlayer() && ServerGameManager.IsAllies(entityOwner.Owner, dealDamageEvent.Target))
+ if (dealDamageEvent.Target.IsPlayer() && player.Equals(dealDamageEvent.Target))
+ {
+ EntityManager.DestroyEntity(entity); // need to destroy with main entityManager, destroyEvent not sufficient to prevent damage
+ }
}
if (dealDamageEvent.MainType != MainDamageType.Physical && dealDamageEvent.MainType != MainDamageType.Spell) continue; // skip if source isn't phys/spell at this point
- if (Quests && dealDamageEvent.Target.Has() && entityOwner.Owner.TryGetPlayer(out Entity player))
+ if (Quests && dealDamageEvent.Target.Has() && entityOwner.Owner.TryGetPlayer(out player))
{
ulong steamId = player.GetSteamId();
LastDamageTime[steamId] = DateTime.UtcNow;
@@ -158,13 +158,16 @@ static void OnUpdatePrefix(DealDamageSystem __instance)
}
}
}
- else if (Familiars && GameMode.Equals(GameModeType.PvP) && entityOwner.Owner.TryGetPlayer(out player) && dealDamageEvent.Target.IsPlayer())
+ else if (Familiars)
{
- Entity familiar = FamiliarUtilities.FindPlayerFamiliar(player);
-
- if (familiar.Exists() && !familiar.IsDisabled())
+ if (entityOwner.Owner.TryGetPlayer(out player) && GameMode.Equals(GameModeType.PvP) && dealDamageEvent.Target.IsPlayer())
{
- FamiliarUtilities.AddToFamiliarAggroBuffer(familiar, dealDamageEvent.Target);
+ Entity familiar = FamiliarUtilities.FindPlayerFamiliar(player);
+
+ if (familiar.Exists() && !familiar.IsDisabled())
+ {
+ FamiliarUtilities.AddToFamiliarAggroBuffer(familiar, dealDamageEvent.Target);
+ }
}
}
}
diff --git a/Patches/EmoteSystemPatch.cs b/Patches/EmoteSystemPatch.cs
index c3af18b..da683b2 100644
--- a/Patches/EmoteSystemPatch.cs
+++ b/Patches/EmoteSystemPatch.cs
@@ -136,9 +136,13 @@ public static void CallDismiss(User user, Entity character, ulong steamId)
}
else
{
- LocalizationService.HandleServerReply(EntityManager, user, "No active familiar found...");
+ LocalizationService.HandleServerReply(EntityManager, user, "Active familiar doesn't exist! If this doesn't seem right try using '.fam reset'.");
}
}
+ else
+ {
+ LocalizationService.HandleServerReply(EntityManager, user, "No active familiar found...");
+ }
}
public static void CombatMode(User user, Entity character, ulong steamId)
{
diff --git a/Patches/InitializationPatch.cs b/Patches/InitializationPatch.cs
index d941edf..3487f90 100644
--- a/Patches/InitializationPatch.cs
+++ b/Patches/InitializationPatch.cs
@@ -19,9 +19,9 @@ static void ShutdownStreamingSupportPostfix()
Plugin.Harmony.Unpatch(typeof(SceneSystem).GetMethod("ShutdownStreamingSupport"), typeof(InitializationPatch).GetMethod("ShutdownStreamingSupportPostfix"));
}
}
- catch
+ catch (Exception ex)
{
- Core.Log.LogError($"{MyPluginInfo.PLUGIN_NAME}[{MyPluginInfo.PLUGIN_VERSION}] failed to initialize, exiting on try-catch...");
+ Core.Log.LogError($"{MyPluginInfo.PLUGIN_NAME}[{MyPluginInfo.PLUGIN_VERSION}] failed to initialize, exiting on try-catch: {ex}");
}
}
}
\ No newline at end of file
diff --git a/Patches/LinkMinionToOwnerOnSpawnSystemPatch.cs b/Patches/LinkMinionToOwnerOnSpawnSystemPatch.cs
index a70018b..f6884de 100644
--- a/Patches/LinkMinionToOwnerOnSpawnSystemPatch.cs
+++ b/Patches/LinkMinionToOwnerOnSpawnSystemPatch.cs
@@ -19,6 +19,8 @@ internal static class LinkMinionToOwnerOnSpawnSystemPatch
static SystemService SystemService => Core.SystemService;
static DebugEventsSystem DebugEventsSystem => SystemService.DebugEventsSystem;
+ static readonly GameModeType GameMode = SystemService.ServerGameSettingsSystem._Settings.GameModeType;
+
static readonly PrefabGUID InkCrawlerDeathBuff = new(1273155981);
public static readonly Dictionary> FamiliarMinions = [];
@@ -71,7 +73,7 @@ static void OnUpdatePrefix(LinkMinionToOwnerOnSpawnSystem __instance)
}
}
- entity.Write(new EntityOwner { Owner = player });
+ if (!GameMode.Equals(GameModeType.PvE)) entity.Write(new EntityOwner { Owner = player });
}
}
else if (entityOwner.Owner.TryGetComponent(out entityOwner) && entityOwner.Owner.IsPlayer())
diff --git a/Patches/LoadPersistenceSystemPatch.cs b/Patches/LoadPersistenceSystemPatch.cs
new file mode 100644
index 0000000..33002bd
--- /dev/null
+++ b/Patches/LoadPersistenceSystemPatch.cs
@@ -0,0 +1,72 @@
+using HarmonyLib;
+using ProjectM;
+using Unity.Collections;
+using Unity.Entities;
+
+namespace Bloodcraft.Patches;
+
+/*
+[HarmonyPatch]
+internal static class LoadPersistenceSystemPatch
+{
+ [HarmonyPatch(typeof(LoadPersistenceSystemV2), nameof(LoadPersistenceSystemV2.DeserializeSystemData))]
+ [HarmonyPostfix]
+ unsafe static void PreventDuplicateKeys(ref NativeParallelHashMap fromOldToNewEntity) // This is likely the 'PrefabRemapping' field
+ {
+ NativeArray keyArray = default;
+ NativeList seenKeys = default;
+ NativeList duplicates = default;
+
+ try
+ {
+ // Get all unique keys into a NativeArray using GetUniqueKeyArray
+ keyArray = fromOldToNewEntity.GetKeyArray(Allocator.TempJob);
+ int length = keyArray.Length;
+
+ // Store detected duplicates
+ seenKeys = new NativeList(length, Allocator.TempJob);
+ duplicates = new NativeList(length, Allocator.TempJob);
+
+ // Iterate over the unique keys
+ for (int i = 0; i < keyArray.Length; i++)
+ {
+ Entity key = keyArray[i];
+
+ if (seenKeys.Contains(key))
+ {
+ duplicates.AddNoResize(key); // Add duplicate key
+ Plugin.LogInstance.LogWarning($"Duplicate key detected: {key}");
+ }
+ else
+ {
+ seenKeys.AddNoResize(key); // Add unique key
+ }
+ }
+
+ // Handle duplicates (log or remove them)
+ for (int i = 0; i < duplicates.Length; i++)
+ {
+ Entity duplicateKey = duplicates[i];
+ fromOldToNewEntity.Remove(duplicateKey);
+ Plugin.LogInstance.LogWarning($"Removed duplicate key: {duplicateKey}");
+ }
+
+ // Dispose of temporary containers
+ keyArray.Dispose();
+ seenKeys.Dispose();
+ duplicates.Dispose();
+ }
+ catch (Exception ex)
+ {
+ Plugin.LogInstance.LogError($"Error while checking for duplicates: {ex.Message}\n{ex.StackTrace}");
+ }
+ finally
+ {
+ // Dispose of all temporary containers
+ if (keyArray.IsCreated) keyArray.Dispose();
+ if (seenKeys.IsCreated) seenKeys.Dispose();
+ if (duplicates.IsCreated) duplicates.Dispose();
+ }
+ }
+}
+*/
\ No newline at end of file
diff --git a/Patches/ServerBootstrapSystemPatches.cs b/Patches/ServerBootstrapSystemPatches.cs
index 9d62e58..a9fbd58 100644
--- a/Patches/ServerBootstrapSystemPatches.cs
+++ b/Patches/ServerBootstrapSystemPatches.cs
@@ -25,6 +25,7 @@ internal static class ServerBootstrapSystemPatches
static ServerGameManager ServerGameManager => Core.ServerGameManager;
static SystemService SystemService => Core.SystemService;
static PrefabCollectionSystem PrefabCollectionSystem => SystemService.PrefabCollectionSystem;
+ static EntityCommandBufferSystem EntityCommandBufferSystem => SystemService.EntityCommandBufferSystem;
static readonly PrefabGUID InsideWoodenCoffin = new(381160212);
static readonly PrefabGUID InsideStoneCoffin = new(569692162);
@@ -431,6 +432,8 @@ static void OnUserConnectedPostfix(ServerBootstrapSystem __instance, NetConnecti
if (exists)
{
+ EntityCommandBuffer entityCommandBuffer = EntityCommandBufferSystem.CreateCommandBuffer();
+
if (ClassUtilities.HasClass(steamId) && playerCharacter.Has())
{
PrefabGUID bloodPrefab = playerCharacter.Read().BloodType;
@@ -459,7 +462,8 @@ static void OnUserConnectedPostfix(ServerBootstrapSystem __instance, NetConnecti
if (bloodQualityBuffs.Contains(classBuff)) continue; // after filtering out class buffs the player should have, check against remaining buffs then see if they are supposed to have it based on blood type and destroy it if not?
else
{
- DestroyUtility.Destroy(EntityManager, buffEntity, DestroyDebugReason.TryRemoveBuff);
+ //DestroyUtility.Destroy(EntityManager, buffEntity, DestroyDebugReason.TryRemoveBuff);
+ entityCommandBuffer.DestroyEntity(buffEntity);
}
}
}
@@ -501,7 +505,9 @@ static void OnUserConnectedPostfix(ServerBootstrapSystem __instance, NetConnecti
if (vBloodAbilityBuffer.IsIndexWithinRange(index))
{
vBloodAbilityBuffer.RemoveAt(index);
- DestroyUtility.Destroy(EntityManager, entity, DestroyDebugReason.TryRemoveBuff);
+
+ //DestroyUtility.Destroy(EntityManager, entity, DestroyDebugReason.TryRemoveBuff);
+ entityCommandBuffer.DestroyEntity(entity);
}
}
}
@@ -599,4 +605,43 @@ static void OnUserDisconnectedPrefix(KickBanSystem_Server __instance)
entities.Dispose();
}
}
+
+ /*
+ static readonly HashSet UserNetworkStateCleared = [];
+
+ [HarmonyPatch(typeof(SerializePersistenceSystemV2), nameof(SerializePersistenceSystemV2.CompleteAndFinalizeExistingSaveOperation))]
+ [HarmonyPostfix]
+ public static void CompleteAndFinalizeExistingSaveOperationPostfix()
+ {
+ Core.StartCoroutine(DelayedBufferClear());
+ }
+ static IEnumerator DelayedBufferClear()
+ {
+ yield return new WaitForSeconds(10f);
+
+ Dictionary onlineCache = new(OnlineCache);
+ HashSet playerInfos = [.. onlineCache.Values];
+
+ foreach (PlayerInfo playerInfo in playerInfos)
+ {
+ if (!UserNetworkStateCleared.Contains(playerInfo.User.CharacterName.Value) && playerInfo.UserEntity.Has())
+ {
+
+ for (int i = buffer.Length - 1; i >= 0; i--)
+ {
+ if (buffer[i].Generation == 0)
+ {
+ buffer.RemoveAt(i);
+ }
+ }
+
+ ServerBootstrapSystem.ClearUserNetworkState(EntityManager, playerInfo.UserEntity, playerInfo.UserEntity.Read(), true);
+ ServerBootstrapSystem.ClearUserNetworkState(EntityManager, playerInfo.UserEntity, playerInfo.UserEntity.Read(), false);
+
+ UserNetworkStateCleared.Add(playerInfo.User.CharacterName.Value);
+ Core.Log.LogInfo($"Cleared {playerInfo.User.CharacterName.Value}'s UserEntityNetworkState buffer...");
+ }
+ }
+ }
+ */
}
\ No newline at end of file
diff --git a/Patches/UpdateBuffsBufferDestroyPatch.cs b/Patches/UpdateBuffsBufferDestroyPatch.cs
index 09c3576..e0c7e8b 100644
--- a/Patches/UpdateBuffsBufferDestroyPatch.cs
+++ b/Patches/UpdateBuffsBufferDestroyPatch.cs
@@ -21,6 +21,10 @@ internal static class UpdateBuffsBufferDestroyPatch
static readonly PrefabGUID PhasingBuff = new(-79611032);
static readonly PrefabGUID ExoFormBuff = new(-31099041);
+ static readonly bool Prestige = ConfigService.PrestigeSystem;
+ static readonly bool ExoPrestige = ConfigService.ExoPrestiging;
+ static readonly bool Familiars = ConfigService.FamiliarSystem;
+
public static readonly List PrestigeBuffs = [];
public static readonly Dictionary> ClassBuffs = [];
@@ -29,7 +33,7 @@ internal static class UpdateBuffsBufferDestroyPatch
static void OnUpdatePostix(UpdateBuffsBuffer_Destroy __instance)
{
if (!Core.hasInitialized) return;
- else if (!(ConfigService.FamiliarSystem || ConfigService.PrestigeSystem || Classes)) return;
+ else if (!(Familiars || Prestige || Classes)) return;
NativeArray entities = __instance.__query_401358720_0.ToEntityArray(Allocator.Temp);
try
@@ -38,22 +42,25 @@ static void OnUpdatePostix(UpdateBuffsBuffer_Destroy __instance)
{
if (!entity.TryGetComponent(out PrefabGUID prefabGUID)) continue;
- if (ConfigService.FamiliarSystem && prefabGUID.Equals(CombatBuff))
+ if (Familiars && prefabGUID.Equals(CombatBuff))
{
if (entity.GetBuffTarget().TryGetPlayer(out Entity character))
{
Entity familiar = FamiliarUtilities.FindPlayerFamiliar(character);
+
if (familiar.Exists())
{
character.With((ref CombatMusicListener_Shared shared) =>
{
shared.UnitPrefabGuid = PrefabGUID.Empty;
});
+
+ FamiliarUtilities.TryReturnFamiliar(character, familiar);
}
}
}
- if (ConfigService.PrestigeSystem && entity.GetBuffTarget().TryGetPlayer(out Entity player)) // check if need to reapply prestige buff
+ if (Prestige && entity.GetBuffTarget().TryGetPlayer(out Entity player)) // check if need to reapply prestige buff
{
User user = player.GetUser();
ulong steamId = user.PlatformId;
@@ -61,17 +68,16 @@ static void OnUpdatePostix(UpdateBuffsBuffer_Destroy __instance)
if (PrestigeBuffs.Contains(prefabGUID)) // check if the buff is for prestige and reapply if so
{
if (steamId.TryGetPlayerPrestiges(out var prestigeData) && prestigeData.TryGetValue(PrestigeType.Experience, out var prestigeLevel))
- {
- //Core.Log.LogInfo($"UpdateBuffsBuffer_Destroy | {steamId} | {prestigeLevel} | {PrestigeBuffs.IndexOf(prefabGUID)} | {prefabGUID.LookupName()}");
-
+ {
if (prestigeLevel > PrestigeBuffs.IndexOf(prefabGUID)) BuffUtilities.ApplyPermanentBuff(player, prefabGUID); // at 0 will not be greater than index of 0 so won't apply buffs, if greater than 0 will apply if allowed based on order of prefabs
}
}
- else if (ConfigService.ExoPrestiging && prefabGUID.Equals(TauntEmoteBuff) && PlayerUtilities.GetPlayerBool(steamId, "ExoForm"))
+ else if (ExoPrestige && prefabGUID.Equals(TauntEmoteBuff) && PlayerUtilities.GetPlayerBool(steamId, "ExoForm"))
{
if (EmoteSystemPatch.ExitingForm.Contains(steamId))
{
EmoteSystemPatch.ExitingForm.Remove(steamId);
+
continue;
}
else if (ExoFormUtilities.CheckExoFormCharge(user, steamId)) ApplyExoFormBuff(player); // could maybe try SpawnPrefabOnGameplayEvent or something like that instead of slingshotting this around, will ponder
diff --git a/Services/EclipseService.cs b/Services/EclipseService.cs
index 6064b5b..96fb1f3 100644
--- a/Services/EclipseService.cs
+++ b/Services/EclipseService.cs
@@ -78,7 +78,7 @@ public static void HandleClientMessage(string message)
if (!ulong.TryParse(match.Groups[3].Value, out ulong steamId))
{
- Core.Log.LogWarning("Invalid steamId in new format message!");
+ Core.Log.LogWarning("Invalid steamId in new (>=1.2.2) format message!");
return;
}
@@ -107,7 +107,7 @@ public static void HandleClientMessage(string message)
if (!ulong.TryParse(oldMatch.Groups[2].Value, out ulong steamId))
{
- Core.Log.LogWarning("Invalid steamId in legacy Eclipse message!");
+ Core.Log.LogWarning("Invalid steamId in legacy (<1.2.2) Eclipse message!");
return;
}
@@ -119,7 +119,7 @@ public static void HandleClientMessage(string message)
break;
default:
- Core.Log.LogError($"Unknown networkEventSubtype encountered while handling legacy version of Eclipse! {eventType}");
+ Core.Log.LogError($"Unknown networkEventSubtype encountered while handling legacy version (<1.2.2) of Eclipse! {eventType}");
break;
}
@@ -132,7 +132,7 @@ public static void HandleClientMessage(string message)
static void RegisterUser(ulong steamId, string version)
{
if (RegisteredUsersAndClientVersions.ContainsKey(steamId)) return;
- else if (steamId.TryGetPlayerInfo(out PlayerInfo playerInfo) && playerInfo.CharEntity.Exists())
+ else if (steamId.TryGetPlayerInfo(out PlayerInfo playerInfo) && playerInfo.CharEntity.Exists() && playerInfo.User.IsConnected)
{
if (HandleRegistration(playerInfo, steamId, version))
{
@@ -187,57 +187,6 @@ static bool HandleRegistration(PlayerInfo playerInfo, ulong steamId, string vers
return false;
}
}
-
- /*
- public static void SendClientConfigV1_1_1(User user)
- {
- string message = BuildConfigMessageV1_1_1();
- string messageWithMAC = $"{message};mac{ChatMessageSystemPatch.GenerateMAC(message)}";
-
- LocalizationService.HandleServerReply(EntityManager, user, messageWithMAC);
- }
- public static void SendClientConfigV1_2_1(User user)
- {
- string message = BuildConfigMessageV1_2_1();
- string messageWithMAC = $"{message};mac{ChatMessageSystemPatch.GenerateMAC(message)}";
-
- LocalizationService.HandleServerReply(EntityManager, user, messageWithMAC);
- }
- public static void SendClientProgressV1_1_1(Entity character, ulong steamId)
- {
- Entity userEntity = character.Read().UserEntity;
- User user = userEntity.Read();
-
- var experienceData = GetExperienceData(steamId);
- var legacyData = GetLegacyData(character, steamId);
- var expertiseData = GetExpertiseData(character, steamId);
- var dailyQuestData = GetQuestData(steamId, Systems.Quests.QuestSystem.QuestType.Daily);
- var weeklyQuestData = GetQuestData(steamId, Systems.Quests.QuestSystem.QuestType.Weekly);
-
- string message = BuildProgressMessageV1_1_1(experienceData, legacyData, expertiseData, dailyQuestData, weeklyQuestData);
- string messageWithMAC = $"{message};mac{ChatMessageSystemPatch.GenerateMAC(message)}";
-
- LocalizationService.HandleServerReply(EntityManager, user, messageWithMAC);
- }
- public static void SendClientProgressV1_2_1(Entity character, ulong steamId)
- {
- Entity userEntity = character.Read().UserEntity;
- User user = userEntity.Read();
-
- var experienceData = GetExperienceData(steamId);
- var legacyData = GetLegacyData(character, steamId);
- var expertiseData = GetExpertiseData(character, steamId);
- var familiarData = GetFamiliarData(character, steamId);
- var professionData = GetProfessionData(steamId);
- var dailyQuestData = GetQuestData(steamId, Systems.Quests.QuestSystem.QuestType.Daily);
- var weeklyQuestData = GetQuestData(steamId, Systems.Quests.QuestSystem.QuestType.Weekly);
-
- string message = BuildProgressMessageV1_2_1(experienceData, legacyData, expertiseData, familiarData, professionData, dailyQuestData, weeklyQuestData);
- string messageWithMAC = $"{message};mac{ChatMessageSystemPatch.GenerateMAC(message)}";
-
- LocalizationService.HandleServerReply(EntityManager, user, messageWithMAC);
- }
- */
public static (int Percent, int Level, int Prestige, int Class) GetExperienceData(ulong steamId)
{
int experiencePercent = 0;
@@ -489,7 +438,7 @@ static IEnumerator DelayedRegistration(ulong steamId, string version)
{
yield return NewUserDelay;
- if (steamId.TryGetPlayerInfo(out PlayerInfo playerInfo) && playerInfo.CharEntity.Exists())
+ if (steamId.TryGetPlayerInfo(out PlayerInfo playerInfo) && playerInfo.CharEntity.Exists() && playerInfo.User.IsConnected)
{
if (HandleRegistration(playerInfo, steamId, version))
{
@@ -510,19 +459,19 @@ static IEnumerator ClientUpdateLoop()
{
if (RegisteredUsersAndClientVersions.Count == 0)
{
- yield return Delay; // Wait 30 seconds if no players
+ yield return Delay;
continue;
}
- Dictionary players = new(OnlineCache); // Shallow copy of the player cache to make sure updates to that don't interfere with loop
- Dictionary users = new(RegisteredUsersAndClientVersions);
+ HashSet playerInfos = [..OnlineCache.Values];
+ Dictionary registeredUsers = new(RegisteredUsersAndClientVersions);
- foreach (ulong steamId in users.Keys)
+ foreach (PlayerInfo playerInfo in playerInfos)
{
- if (players.TryGetValue(steamId.ToString(), out PlayerInfo playerInfo))
- {
- string version = users[steamId];
+ ulong steamId = playerInfo.User.PlatformId;
+ if (registeredUsers.TryGetValue(steamId, out string version))
+ {
try
{
switch (version)
@@ -542,7 +491,7 @@ static IEnumerator ClientUpdateLoop()
default:
// Handle unsupported versions or fallback
Core.Log.LogWarning($"Unsupported client version in EclipseService! {steamId}:Eclipse{version}, unregistering user to avoid console spam...");
-
+
if (RegisteredUsersAndClientVersions.ContainsKey(steamId))
{
RegisteredUsersAndClientVersions.Remove(steamId);
@@ -551,13 +500,13 @@ static IEnumerator ClientUpdateLoop()
break;
}
}
- catch (Exception e)
+ catch (Exception ex)
{
- Core.Log.LogError($"Failed sending progress in EclipseService! {steamId}:Eclipse{version}, Error - {e}");
+ Core.Log.LogWarning($"Failed sending progress in EclipseService! {steamId}:Eclipse{version}, Error - {ex}");
}
- }
- yield return null;
+ yield return null;
+ }
}
yield return Delay;
diff --git a/Services/PlayerService.cs b/Services/PlayerService.cs
index f24fc6a..0027adb 100644
--- a/Services/PlayerService.cs
+++ b/Services/PlayerService.cs
@@ -1,7 +1,6 @@
using Bloodcraft.Utilities;
using Il2CppInterop.Runtime;
using ProjectM.Network;
-using ProjectM.Scripting;
using System.Collections;
using Unity.Entities;
using UnityEngine;
@@ -71,34 +70,6 @@ static IEnumerator PlayerUpdateLoop()
}
});
- /*
- if (!abilityGroupSlotBuffersCleared)
- {
- HashSet processedPlayers = [];
-
- foreach (PlayerInfo player in PlayerCache.Values)
- {
- if (!processedPlayers.Contains(player.CharEntity) && player.CharEntity.Exists() && ServerGameManager.TryGetBuffer(player.CharEntity, out var buffer))
- {
- foreach (AbilityGroupSlotBuffer abilityGroupSlotBuffer in buffer)
- {
- Entity abilityGroupSlotEntity = abilityGroupSlotBuffer.GroupSlotEntity.GetEntityOnServer();
-
- if (abilityGroupSlotEntity.Exists() && abilityGroupSlotEntity.TryGetComponent(out AbilityGroupSlot abilityGroupSlot) && abilityGroupSlot.SlotId > 8)
- {
- DestroyUtility.Destroy(EntityManager, abilityGroupSlotEntity);
- }
- }
-
- buffer.RemoveRange(9, buffer.Length);
- processedPlayers.Add(player.CharEntity);
- }
- }
-
- abilityGroupSlotBuffersCleared = true;
- }
- */
-
yield return Delay;
}
}
diff --git a/Services/SystemService.cs b/Services/SystemService.cs
index 4eb56f5..ded7588 100644
--- a/Services/SystemService.cs
+++ b/Services/SystemService.cs
@@ -84,6 +84,9 @@ public class SystemService(World world)
AttachParentIdSystem _attachParentIdSystem;
public AttachParentIdSystem AttachParentIdSystem => _attachParentIdSystem ??= GetSystem();
+
+ //ModificationSystem _modificationSystem;
+ //public ModificationSystem ModificationSystem => _modificationSystem ??= GetSystem();
T GetSystem() where T : ComponentSystemBase
{
return _world.GetExistingSystemManaged() ?? throw new InvalidOperationException($"Failed to get {Il2CppType.Of().FullName} from the Server...");
diff --git a/Systems/Quests/QuestSystem.cs b/Systems/Quests/QuestSystem.cs
index 530fe3c..572dc19 100644
--- a/Systems/Quests/QuestSystem.cs
+++ b/Systems/Quests/QuestSystem.cs
@@ -122,16 +122,6 @@ static HashSet GetKillPrefabsForLevel(int playerLevel)
foreach (PrefabGUID prefab in TargetPrefabs.Keys)
{
- /* betting this is what caused overleveled targets sometimes if familiars are present in the cache and filtering those out when doing query would be a possible performance hit
- Entity targetEntity = TargetPrefabs[prefab].FirstOrDefault();
-
- if (targetEntity.TryGetComponent(out UnitLevel unitLevel) && Math.Abs(unitLevel.Level._Value - playerLevel) <= 10)
- {
- if (targetEntity.Has() && unitLevel.Level._Value > playerLevel) continue;
- prefabs.Add(prefab);
- }
- */
-
if (PrefabCollectionSystem._PrefabGuidToEntityMap.TryGetValue(prefab, out Entity targetEntity) && targetEntity.TryGetComponent(out UnitLevel unitLevel))
{
bool isVBlood = targetEntity.Has();
diff --git a/Utilities/FamiliarUtilities.cs b/Utilities/FamiliarUtilities.cs
index 34702ac..3653a18 100644
--- a/Utilities/FamiliarUtilities.cs
+++ b/Utilities/FamiliarUtilities.cs
@@ -21,6 +21,7 @@ internal static class FamiliarUtilities
static ServerGameManager ServerGameManager => Core.ServerGameManager;
static SystemService SystemService => Core.SystemService;
static PrefabCollectionSystem PrefabCollectionSystem => SystemService.PrefabCollectionSystem;
+ static EntityCommandBufferSystem EntityCommandBufferSystem => SystemService.EntityCommandBufferSystem;
public static readonly Dictionary AutoCallMap = [];
@@ -138,6 +139,8 @@ public static void ParseAddedFamiliar(ChatCommandContext ctx, ulong steamId, str
LocalizationService.HandleReply(ctx, "Invalid prefab (not an integer) or name (does not start with CHAR/char).");
}
}
+
+ /*
public static void ReturnFamiliar(Entity player, Entity familiar)
{
Follower following = familiar.Read();
@@ -155,6 +158,36 @@ public static void ReturnFamiliar(Entity player, Entity familiar)
ResetAggro(familiar);
}
}
+ */
+ public static void TryReturnFamiliar(Entity player, Entity familiar)
+ {
+ float3 playerPos = player.Read().Value;
+ float distance = UnityEngine.Vector3.Distance(familiar.Read().Value, playerPos);
+
+ if (distance >= 25f)
+ {
+ ReturnFamiliar(playerPos, familiar);
+ }
+ }
+ public static void ReturnFamiliar(float3 position, Entity familiar)
+ {
+ familiar.With((ref Follower follower) =>
+ {
+ follower.ModeModifiable._Value = 1;
+ });
+
+ familiar.With((ref LastTranslation lastTranslation) =>
+ {
+ lastTranslation.Value = position;
+ });
+
+ familiar.With((ref Translation translation) =>
+ {
+ translation.Value = position;
+ });
+
+ ResetAggro(familiar);
+ }
public static void ToggleShinies(ChatCommandContext ctx, ulong steamId)
{
PlayerUtilities.TogglePlayerBool(steamId, "FamiliarVisual");
@@ -189,27 +222,31 @@ public static bool TryParseFamiliarStat(string statType, out FamiliarStatType pa
}
public static void ClearBuffers(Entity playerCharacter, ulong steamId)
{
+ EntityCommandBuffer entityCommandBuffer = EntityCommandBufferSystem.CreateCommandBuffer();
+
if (playerCharacter.Has())
{
var buffer = playerCharacter.ReadBuffer();
-
+
foreach (FollowerBuffer follower in buffer)
{
Entity followerEntity = follower.Entity.GetEntityOnServer();
if (followerEntity.Exists())
{
- if (followerEntity.Has()) followerEntity.Remove();
- if (followerEntity.Has()) followerEntity.Remove();
- if (followerEntity.Has()) followerEntity.Remove();
- if (followerEntity.Has()) followerEntity.Remove();
- if (followerEntity.Has()) followerEntity.Remove();
-
- DestroyUtility.Destroy(EntityManager, followerEntity);
+ if (followerEntity.Has()) followerEntity.Remove(entityCommandBuffer);
+ if (followerEntity.Has()) followerEntity.Remove(entityCommandBuffer);
+ if (followerEntity.Has()) followerEntity.Remove(entityCommandBuffer);
+ if (followerEntity.Has()) followerEntity.Remove(entityCommandBuffer);
+ if (followerEntity.Has()) followerEntity.Remove(entityCommandBuffer);
+
+ //DestroyUtility.Destroy(EntityManager, followerEntity);
+ entityCommandBuffer.DestroyEntity(followerEntity);
}
}
- buffer.Clear();
+ //buffer.Clear();
+ entityCommandBuffer.SetBuffer(playerCharacter).Clear();
}
if (playerCharacter.Has())
@@ -220,17 +257,19 @@ public static void ClearBuffers(Entity playerCharacter, ulong steamId)
{
if (minion.Entity.Exists())
{
- if (minion.Entity.Has()) minion.Entity.Remove();
- if (minion.Entity.Has()) minion.Entity.Remove();
- if (minion.Entity.Has()) minion.Entity.Remove();
- if (minion.Entity.Has()) minion.Entity.Remove();
- if (minion.Entity.Has()) minion.Entity.Remove();
-
- DestroyUtility.Destroy(EntityManager, minion.Entity);
+ if (minion.Entity.Has()) minion.Entity.Remove(entityCommandBuffer);
+ if (minion.Entity.Has()) minion.Entity.Remove(entityCommandBuffer);
+ if (minion.Entity.Has()) minion.Entity.Remove(entityCommandBuffer);
+ if (minion.Entity.Has()) minion.Entity.Remove(entityCommandBuffer);
+ if (minion.Entity.Has()) minion.Entity.Remove(entityCommandBuffer);
+
+ //DestroyUtility.Destroy(EntityManager, minion.Entity);
+ entityCommandBuffer.DestroyEntity(minion.Entity);
}
}
- buffer.Clear();
+ //buffer.Clear();
+ entityCommandBuffer.SetBuffer(playerCharacter).Clear();
}
ClearFamiliarActives(steamId);
@@ -290,11 +329,20 @@ public static void DismissFamiliar(Entity playerCharacter, Entity familiar, User
}
public static void ResetAggro(Entity familiar)
{
+ EntityCommandBuffer entityCommandBuffer = EntityCommandBufferSystem.CreateCommandBuffer();
+
+ if (familiar.Has()) entityCommandBuffer.SetBuffer(familiar).Clear();
+ if (familiar.Has()) entityCommandBuffer.SetBuffer(familiar).Clear();
+ if (familiar.Has()) entityCommandBuffer.SetBuffer(familiar).Clear();
+ if (familiar.Has()) entityCommandBuffer.SetBuffer(familiar).Clear();
+
+ /*
if (ServerGameManager.TryGetBuffer(familiar, out var alertBuffer)) alertBuffer.Clear();
if (ServerGameManager.TryGetBuffer(familiar, out var damageHistoryBuffer)) damageHistoryBuffer.Clear();
if (ServerGameManager.TryGetBuffer(familiar, out var aggroCandidateBuffer)) aggroCandidateBuffer.Clear();
if (ServerGameManager.TryGetBuffer(familiar, out var externalAggroBuffer)) externalAggroBuffer.Clear();
if (ServerGameManager.TryGetBuffer(familiar, out var aggroBuffer)) aggroBuffer.Clear();
+ */
familiar.With((ref AggroConsumer aggroConsumer) =>
{
@@ -304,11 +352,20 @@ public static void ResetAggro(Entity familiar)
}
public static void ResetAndDisableAggro(Entity familiar)
{
+ EntityCommandBuffer entityCommandBuffer = EntityCommandBufferSystem.CreateCommandBuffer();
+
+ if (familiar.Has()) entityCommandBuffer.SetBuffer(familiar).Clear();
+ if (familiar.Has()) entityCommandBuffer.SetBuffer(familiar).Clear();
+ if (familiar.Has()) entityCommandBuffer.SetBuffer(familiar).Clear();
+ if (familiar.Has()) entityCommandBuffer.SetBuffer(familiar).Clear();
+
+ /*
if (ServerGameManager.TryGetBuffer(familiar, out var alertBuffer)) alertBuffer.Clear();
if (ServerGameManager.TryGetBuffer(familiar, out var damageHistoryBuffer)) damageHistoryBuffer.Clear();
if (ServerGameManager.TryGetBuffer(familiar, out var aggroCandidateBuffer)) aggroCandidateBuffer.Clear();
if (ServerGameManager.TryGetBuffer(familiar, out var externalAggroBuffer)) externalAggroBuffer.Clear();
if (ServerGameManager.TryGetBuffer(familiar, out var aggroBuffer)) aggroBuffer.Clear();
+ */
familiar.With((ref AggroConsumer aggroConsumer) =>
{
diff --git a/Utilities/PlayerUtilities.cs b/Utilities/PlayerUtilities.cs
index 34c6c28..53ccc70 100644
--- a/Utilities/PlayerUtilities.cs
+++ b/Utilities/PlayerUtilities.cs
@@ -167,7 +167,7 @@ static void AddPlayerToParty(ChatCommandContext ctx, ulong ownerId, string playe
return;
}
- if (!ownerId.TryGetPlayerParties(out HashSet party))
+ if (!ownerId.TryGetPlayerParties(out HashSet party) || party == null)
{
ownerId.SetPlayerParties([ownerName]);
}