Core/Conversations: Conversation actor improvements

Port From (https://github.com/TrinityCore/TrinityCore/commit/fda65981c7a4c475c270755c198dee85cd38dfa3)
This commit is contained in:
hondacrx
2022-05-31 15:25:11 -04:00
parent 48042ffab0
commit 940ecad00a
4 changed files with 243 additions and 99 deletions
+2 -2
View File
@@ -2875,8 +2875,8 @@ namespace Framework.Constants
public enum ConversationActorType
{
WorldObjectActor = 0,
CreatureActor = 1
WorldObject = 0,
TalkingHead = 1
}
public enum CorpseDynFlags
@@ -32,8 +32,7 @@ namespace Game.DataStorage
_conversationLineTemplateStorage.Clear();
_conversationTemplateStorage.Clear();
Dictionary<uint, ConversationActor[]> actorsByConversation = new();
Dictionary<uint, ulong[]> actorGuidsByConversation = new();
Dictionary<uint, List<ConversationActorTemplate>> actorsByConversation = new();
SQLResult lineTemplates = DB.World.Query("SELECT Id, UiCameraID, ActorIdx, Flags FROM conversation_line_template");
if (!lineTemplates.IsEmpty())
@@ -67,7 +66,7 @@ namespace Game.DataStorage
Log.outInfo(LogFilter.ServerLoading, "Loaded 0 Conversation line templates. DB table `conversation_line_template` is empty.");
}
SQLResult actorResult = DB.World.Query("SELECT ConversationId, ConversationActorId, ConversationActorGuid, Idx, CreatureId, CreatureDisplayInfoId FROM conversation_actors");
SQLResult actorResult = DB.World.Query("SELECT ConversationId, ConversationActorId, ConversationActorGuid, Idx, CreatureId, CreatureDisplayInfoId, NoActorObject, ActivePlayerObject FROM conversation_actors");
if (!actorResult.IsEmpty())
{
uint oldMSTime = Time.GetMSTime();
@@ -75,62 +74,37 @@ namespace Game.DataStorage
do
{
uint conversationId = actorResult.Read<uint>(0);
uint actorId = actorResult.Read<uint>(1);
ulong actorGuid = actorResult.Read<ulong>(2);
ushort idx = actorResult.Read<ushort>(3);
uint creatureId = actorResult.Read<uint>(4);
uint creatureDisplayInfoId = actorResult.Read<uint>(5);
ConversationActorDbRow data;
ConversationActorTemplate actor = new();
if (creatureId != 0 && actorGuid != 0)
{
Log.outError(LogFilter.Sql, $"Table `conversation_actors` references both actor (ID: {actorId}) and actorGuid (GUID: {actorGuid}) for Conversation {conversationId}, skipped.");
data.ConversationId = actorResult.Read<uint>(0);
data.ConversationId = actorResult.Read<uint>(1);
data.SpawnId = actorResult.Read<ulong>(2);
data.ActorIndex = actor.Index = actorResult.Read<ushort>(3);
data.CreatureId = actorResult.Read<uint>(4);
data.CreatureDisplayInfoId = actorResult.Read<uint>(5);
bool noActorObject = actorResult.Read<byte>(6) == 1;
bool activePlayerObject = actorResult.Read<byte>(7) == 1;
if (activePlayerObject)
actor.ActivePlayerTemplate = new();
else if (noActorObject)
actor.NoObjectTemplate = new();
else if (data.SpawnId != 0)
actor.WorldObjectTemplate = new();
else
actor.TalkingHeadTemplate = new();
bool valid = data.Invoke(actor);
if (!valid)
continue;
}
if (creatureId != 0)
{
if (creatureDisplayInfoId != 0)
{
ConversationActor conversationActor = new();
conversationActor.ActorId = actorId;
conversationActor.CreatureId = creatureId;
conversationActor.CreatureDisplayInfoId = creatureDisplayInfoId;
if (!actorsByConversation.ContainsKey(data.ConversationId))
actorsByConversation[data.ConversationId] = new();
if (!actorsByConversation.ContainsKey(conversationId))
actorsByConversation[conversationId] = new ConversationActor[idx + 1];
ConversationActor[] actors = actorsByConversation[conversationId];
if (actors.Length <= idx)
Array.Resize(ref actors, idx + 1);
actors[idx] = conversationActor;
actorsByConversation[data.ConversationId].Add(actor);
++count;
}
else
Log.outError(LogFilter.Sql, $"Table `conversation_actors` references an actor (CreatureId: {creatureId}) without CreatureDisplayInfoId for Conversation {conversationId}, skipped");
}
else if (actorGuid != 0)
{
CreatureData creData = Global.ObjectMgr.GetCreatureData(actorGuid);
if (creData != null)
{
if (!actorGuidsByConversation.ContainsKey(conversationId))
actorGuidsByConversation[conversationId] = new ulong[idx + 1];
var guids = actorGuidsByConversation[conversationId];
if (guids.Length <= idx)
Array.Resize(ref guids, idx + 1);
guids[idx] = actorGuid;
++count;
}
else
Log.outError(LogFilter.Sql, $"Table `conversation_actors` references an invalid creature guid (GUID: {actorGuid}) for Conversation {conversationId}, skipped");
}
}
while (actorResult.NextRow());
} while (actorResult.NextRow());
Log.outInfo(LogFilter.ServerLoading, "Loaded {0} Conversation actors in {1} ms", count, Time.GetMSTimeDiffToNow(oldMSTime));
}
@@ -153,7 +127,6 @@ namespace Game.DataStorage
conversationTemplate.ScriptId = Global.ObjectMgr.GetScriptId(templateResult.Read<string>(3));
conversationTemplate.Actors = actorsByConversation.TryGetValue(conversationTemplate.Id, out var actors) ? actors.ToList() : null;
conversationTemplate.ActorGuids = actorGuidsByConversation.TryGetValue(conversationTemplate.Id, out var actorGuids) ? actorGuids.ToList() : null;
ConversationLineRecord currentConversationLine = CliDB.ConversationLineStorage.LookupByKey(conversationTemplate.FirstLineId);
if (currentConversationLine == null)
@@ -197,13 +170,138 @@ namespace Game.DataStorage
Dictionary<uint, ConversationTemplate> _conversationTemplateStorage = new();
Dictionary<uint, ConversationLineTemplate> _conversationLineTemplateStorage = new();
}
public class ConversationActor
struct ConversationActorDbRow
{
public uint ActorId;
public uint ConversationId;
public uint ActorIndex;
public ulong SpawnId;
public uint CreatureId;
public uint CreatureDisplayInfoId;
public bool Invoke(ConversationActorTemplate template)
{
if (template.WorldObjectTemplate == null)
return Invoke(template.WorldObjectTemplate);
if (template.NoObjectTemplate == null)
return Invoke(template.NoObjectTemplate);
if (template.ActivePlayerTemplate == null)
return Invoke(template.ActivePlayerTemplate);
if (template.TalkingHeadTemplate == null)
return Invoke(template.TalkingHeadTemplate);
return false;
}
public bool Invoke(ConversationActorWorldObjectTemplate worldObject)
{
if (Global.ObjectMgr.GetCreatureData(SpawnId) == null)
{
Log.outError(LogFilter.Sql, $"Table `conversation_actors` references an invalid creature guid (GUID: {SpawnId}) for Conversation {ConversationId} and Idx {ActorIndex}, skipped.");
return false;
}
if (CreatureId != 0)
Log.outError(LogFilter.Sql, $"Table `conversation_actors` with ConversationActorGuid cannot have CreatureId ({CreatureId}). Conversation {ConversationId} and Idx {ActorIndex}.");
if (CreatureDisplayInfoId != 0)
Log.outError(LogFilter.Sql, $"Table `conversation_actors` with ConversationActorGuid cannot have CreatureDisplayInfoId ({CreatureDisplayInfoId}). Conversation {ConversationId} and Idx {ActorIndex}.");
worldObject.SpawnId = SpawnId;
return true;
}
public bool Invoke(ConversationActorNoObjectTemplate noObject)
{
if (Global.ObjectMgr.GetCreatureTemplate(CreatureId) == null)
{
Log.outError(LogFilter.Sql, $"Table `conversation_actors` references an invalid creature id ({CreatureId}) for Conversation {ConversationId} and Idx {ActorIndex}, skipped.");
return false;
}
if (CreatureDisplayInfoId != 0 && !CliDB.CreatureDisplayInfoStorage.ContainsKey(CreatureDisplayInfoId))
{
Log.outError(LogFilter.Sql, $"Table `conversation_actors` references an invalid creature display id ({CreatureDisplayInfoId}) for Conversation {ConversationId} and Idx {ActorIndex}, skipped.");
return false;
}
if (SpawnId != 0)
Log.outError(LogFilter.Sql, $"Table `conversation_actors` with NoActorObject cannot have ConversationActorGuid ({SpawnId}). Conversation {ConversationId} and Idx {ActorIndex}.");
noObject.CreatureId = CreatureId;
noObject.CreatureDisplayInfoId = CreatureDisplayInfoId;
return true;
}
public bool Invoke(ConversationActorActivePlayerTemplate activePlayer)
{
if (SpawnId != 0)
Log.outError(LogFilter.Sql, $"Table `conversation_actors` with ActivePlayerObject cannot have ConversationActorGuid ({SpawnId}). Conversation {ConversationId} and Idx {ActorIndex}.");
if (CreatureId != 0)
Log.outError(LogFilter.Sql, $"Table `conversation_actors` with ActivePlayerObject cannot have CreatureId ({CreatureId}). Conversation {ConversationId} and Idx {ActorIndex}.");
if (CreatureDisplayInfoId != 0)
Log.outError(LogFilter.Sql, $"Table `conversation_actors` with ActivePlayerObject cannot have CreatureDisplayInfoId ({CreatureDisplayInfoId}). Conversation {ConversationId} and Idx {ActorIndex}.");
return true;
}
public bool Invoke(ConversationActorTalkingHeadTemplate talkingHead)
{
if (Global.ObjectMgr.GetCreatureTemplate(CreatureId) == null)
{
Log.outError(LogFilter.Sql, $"Table `conversation_actors` references an invalid creature id ({CreatureId}) for Conversation {ConversationId} and Idx {ActorIndex}, skipped.");
return false;
}
if (CreatureDisplayInfoId != 0 && !CliDB.CreatureDisplayInfoStorage.ContainsKey(CreatureDisplayInfoId))
{
Log.outError(LogFilter.Sql, $"Table `conversation_actors` references an invalid creature display id ({CreatureDisplayInfoId}) for Conversation {ConversationId} and Idx {ActorIndex}, skipped.");
return false;
}
if (SpawnId != 0)
Log.outError(LogFilter.Sql, $"Table `conversation_actors` with TalkingHead cannot have ConversationActorGuid ({SpawnId}). Conversation {ConversationId} and Idx {ActorIndex}.");
talkingHead.CreatureId = CreatureId;
talkingHead.CreatureDisplayInfoId = CreatureDisplayInfoId;
return true;
}
}
}
public class ConversationActorWorldObjectTemplate
{
public ulong SpawnId;
}
public class ConversationActorNoObjectTemplate
{
public uint CreatureId;
public uint CreatureDisplayInfoId;
}
public class ConversationActorActivePlayerTemplate
{
}
public class ConversationActorTalkingHeadTemplate
{
public uint CreatureId;
public uint CreatureDisplayInfoId;
}
public struct ConversationActorTemplate
{
public int Id;
public uint Index;
public ConversationActorWorldObjectTemplate WorldObjectTemplate;
public ConversationActorNoObjectTemplate NoObjectTemplate;
public ConversationActorActivePlayerTemplate ActivePlayerTemplate;
public ConversationActorTalkingHeadTemplate TalkingHeadTemplate;
}
public class ConversationLineTemplate
@@ -212,7 +310,6 @@ namespace Game.DataStorage
public uint UiCameraID; // Link to UiCamera.db2
public byte ActorIdx; // Index from conversation_actors
public byte Flags;
public ushort Padding;
}
public class ConversationTemplate
@@ -222,8 +319,7 @@ namespace Game.DataStorage
public uint TextureKitId; // Background texture
public uint ScriptId;
public List<ConversationActor> Actors = new();
public List<ulong> ActorGuids = new();
public List<ConversationActorTemplate> Actors = new();
public List<ConversationLineTemplate> Lines = new();
}
+83 -34
View File
@@ -124,38 +124,8 @@ namespace Game.Entities
_textureKitId = conversationTemplate.TextureKitId;
if (conversationTemplate.Actors != null)
{
foreach (var actor in conversationTemplate.Actors)
{
if (actor != null)
{
ConversationActorField actorField = new();
actorField.CreatureID = actor.CreatureId;
actorField.CreatureDisplayInfoID = actor.CreatureDisplayInfoId;
actorField.Id = (int)actor.ActorId;
actorField.Type = ConversationActorType.CreatureActor;
AddDynamicUpdateFieldValue(m_values.ModifyValue(m_conversationData).ModifyValue(m_conversationData.Actors), actorField);
}
}
}
if (conversationTemplate.ActorGuids != null)
{
for (ushort actorIndex = 0; actorIndex < conversationTemplate.ActorGuids.Count; ++actorIndex)
{
ulong actorGuid = conversationTemplate.ActorGuids[actorIndex];
if (actorGuid == 0)
continue;
foreach (var creature in map.GetCreatureBySpawnIdStore().LookupByKey(actorGuid))
{
// we just need the last one, overriding is legit
AddActor(creature.GetGUID(), actorIndex);
}
}
}
new ConversationActorFillVisitor(this, creator, map, actor).Invoke(actor);
Global.ScriptMgr.OnConversationCreate(this, creator);
@@ -221,11 +191,26 @@ namespace Game.Entities
return true;
}
public void AddActor(ObjectGuid actorGuid, ushort actorIdx)
public void AddActor(int actorId, uint actorIdx, ObjectGuid actorGuid)
{
ConversationActorField actorField = m_values.ModifyValue(m_conversationData).ModifyValue(m_conversationData.Actors, actorIdx);
ConversationActorField actorField = m_values.ModifyValue(m_conversationData).ModifyValue(m_conversationData.Actors, (int)actorIdx);
SetUpdateFieldValue(ref actorField.CreatureID, 0u);
SetUpdateFieldValue(ref actorField.CreatureDisplayInfoID, 0u);
SetUpdateFieldValue(ref actorField.ActorGUID, actorGuid);
SetUpdateFieldValue(ref actorField.Type, ConversationActorType.WorldObjectActor);
SetUpdateFieldValue(ref actorField.Id, actorId);
SetUpdateFieldValue(ref actorField.Type, ConversationActorType.WorldObject);
SetUpdateFieldValue(ref actorField.NoActorObject, 0u);
}
public void AddActor(int actorId, uint actorIdx, ConversationActorType type, uint creatureId, uint creatureDisplayInfoId)
{
ConversationActorField actorField = m_values.ModifyValue(m_conversationData).ModifyValue(m_conversationData.Actors, (int)actorIdx);
SetUpdateFieldValue(ref actorField.CreatureID, creatureId);
SetUpdateFieldValue(ref actorField.CreatureDisplayInfoID, creatureDisplayInfoId);
SetUpdateFieldValue(ref actorField.ActorGUID, ObjectGuid.Empty);
SetUpdateFieldValue(ref actorField.Id, actorId);
SetUpdateFieldValue(ref actorField.Type, type);
SetUpdateFieldValue(ref actorField.NoActorObject, type == ConversationActorType.WorldObject ? 1 : 0u);
}
public TimeSpan GetLineStartTime(Locale locale, int lineId)
@@ -350,4 +335,68 @@ namespace Game.Entities
}
}
}
class ConversationActorFillVisitor
{
Conversation _conversation;
Unit _creator;
Map _map;
ConversationActorTemplate _actor;
public ConversationActorFillVisitor(Conversation conversation, Unit creator, Map map, ConversationActorTemplate actor)
{
_conversation = conversation;
_creator = creator;
_map = map;
_actor = actor;
}
public void Invoke(ConversationActorTemplate template)
{
if (template.WorldObjectTemplate == null)
Invoke(template.WorldObjectTemplate);
if (template.NoObjectTemplate == null)
Invoke(template.NoObjectTemplate);
if (template.ActivePlayerTemplate == null)
Invoke(template.ActivePlayerTemplate);
if (template.TalkingHeadTemplate == null)
Invoke(template.TalkingHeadTemplate);
}
public void Invoke(ConversationActorWorldObjectTemplate worldObject)
{
Creature bestFit = null;
foreach (var creature in _map.GetCreatureBySpawnIdStore().LookupByKey(worldObject.SpawnId))
{
bestFit = creature;
// If creature is in a personal phase then we pick that one specifically
if (creature.GetPhaseShift().GetPersonalGuid() == _creator.GetGUID())
break;
}
if (bestFit)
_conversation.AddActor(_actor.Id, _actor.Index, bestFit.GetGUID());
}
public void Invoke(ConversationActorNoObjectTemplate noObject)
{
_conversation.AddActor(_actor.Id, _actor.Index, ConversationActorType.WorldObject, noObject.CreatureId, noObject.CreatureDisplayInfoId);
}
public void Invoke(ConversationActorActivePlayerTemplate activePlayer)
{
_conversation.AddActor(_actor.Id, _actor.Index, ObjectGuid.Create(HighGuid.Player, 0xFFFFFFFFFFFFFFFF));
}
public void Invoke(ConversationActorTalkingHeadTemplate talkingHead)
{
_conversation.AddActor(_actor.Id, _actor.Index, ConversationActorType.TalkingHead, talkingHead.CreatureId, talkingHead.CreatureDisplayInfoId);
}
}
}
-1
View File
@@ -32,7 +32,6 @@ namespace Scripts.World
public override void OnConversationCreate(Conversation conversation, Unit creator)
{
conversation.AddActor(ObjectGuid.Create(HighGuid.Player, 0xFFFFFFFFFFFFFFFF), 1);
Player player = creator.ToPlayer();
if (player != null)
player.KilledMonsterCredit(NpcTalkToYourCommanderCredit);