public static bool CanCast(uint spellId, GameObject targetObject) and public static bool CanCast(string spellName, GameObject targetObject)Is there why AM.CanCast and AM.ActionReady are not sufficient?
I'm not using en client at the moment so I am not sure the exact name of these spell's categoryHasSpell just checks if the id is inside CurrentActions
What do you mean "extra spell"?
99% of the spells are ActionType.Spell, the remaining few are stuff like limit break, sprint, return, teleport, etc.
I've got some local work done on updating the CurrentActions that needs to finished up, I'll take a look at cancast while im working on it.
ActionManager.CurrentActions has been modified:
Pvp skills should now correctly show up in the list (Combo actions are stilled blocked from being directly cast)
Role actions will now correctly show up when in potd at low level
[03:00:35.816 N] [Lis5.31f38] Utc: 10/3/2020 3:00:35 AM | Eorzea Time: 993/02/12 17:20 | PauseTime: 993/02/12 17:43
[03:00:35.816 N] [Lis5.31f38] Deciding on next order.
[03:00:35.816 N] [Lis5.31f38] Executing normal directive.
[03:00:35.822 N] [Lis5.31f38] Gathering Fire Crystal.
[03:00:35.822 N] [Lis5.31f38] Gathering at 80 Mature Tree - Ladle.
[03:00:35.822 N] [Lis5.31f38] Traveling to area: Amh Araeng (West)
[03:00:37.795 N] [Lis5.31f38] Successful response in 357 ms.
[03:00:37.905 N] [Lis5.31f38] Executing route with 1 paths.
[03:00:37.908 N] [Lis5.31f38] Executing teleport step.
[03:00:37.908 N] [Lis5.31f38] Teleporting to Twine.
[03:00:37.987 D] Teleporting to Twine
[03:00:45.943 D] Exception while contacting authorization server.
[03:00:45.944 D] System.ServiceModel.CommunicationException: La connexion de socket a été abandonnée. Ceci peut être causé par une erreur lors du traitement de votre message, par le dépassement du délai d'attente de réception par l'hôte distant ou par un problème de ressource réseau sous-jacent. Le délai d'attente de socket local était '00:00:29.9861127'. ---> System.Net.Sockets.SocketException: Une connexion existante a dû être fermée par l’hôte distant
à System.ServiceModel.Channels.SocketConnection.ReadCore(Byte[] buffer, Int32 offset, Int32 size, TimeSpan timeout, Boolean closing)
--- Fin de la trace de la pile d'exception interne ---
Server stack trace:
à System.ServiceModel.Channels.SocketConnection.ReadCore(Byte[] buffer, Int32 offset, Int32 size, TimeSpan timeout, Boolean closing)
à System.ServiceModel.Channels.SocketConnection.Read(Byte[] buffer, Int32 offset, Int32 size, TimeSpan timeout)
à System.ServiceModel.Channels.DelegatingConnection.Read(Byte[] buffer, Int32 offset, Int32 size, TimeSpan timeout)
à System.ServiceModel.Channels.ClientFramingDuplexSessionChannel.SendPreamble(IConnection connection, ArraySegment`1 preamble, TimeoutHelper& timeoutHelper)
à System.ServiceModel.Channels.ClientFramingDuplexSessionChannel.DuplexConnectionPoolHelper.AcceptPooledConnection(IConnection connection, TimeoutHelper& timeoutHelper)
à System.ServiceModel.Channels.ConnectionPoolHelper.EstablishConnection(TimeSpan timeout)
à System.ServiceModel.Channels.ClientFramingDuplexSessionChannel.OnOpen(TimeSpan timeout)
à System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
à System.ServiceModel.Channels.ServiceChannel.OnOpen(TimeSpan timeout)
à System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
à System.ServiceModel.Channels.ServiceChannel.CallOpenOnce.System.ServiceModel.Channels.ServiceChannel.ICallOnce.Call(ServiceChannel channel, TimeSpan timeout)
à System.ServiceModel.Channels.ServiceChannel.CallOnceManager.CallOnce(TimeSpan timeout, CallOnceManager cascade)
à System.ServiceModel.Channels.ServiceChannel.EnsureOpened(TimeSpan timeout)
à System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
à System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
à System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
Exception rethrown at [0]:
à System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
à System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
à Buddy.Auth.SR.IA.Do(Byte b, Object[] args)
à Buddy.Auth.AuthService.Heartbeat(Object[] args)
à ff14bot.Core.<>c.(AuthService )
à Buddy.Auth.Service.Use[T](Func`2 codeBlock) --> System.Net.Sockets.SocketException (0x80004005): Une connexion existante a dû être fermée par l’hôte distant
à System.ServiceModel.Channels.SocketConnection.ReadCore(Byte[] buffer, Int32 offset, Int32 size, TimeSpan timeout, Boolean closing)
[03:00:45.974 D] Exception while contacting authorization server.
[03:00:45.974 D] System.ServiceModel.CommunicationException: La connexion de socket a été abandonnée. Ceci peut être causé par une erreur lors du traitement de votre message, par le dépassement du délai d'attente de réception par l'hôte distant ou par un problème de ressource réseau sous-jacent. Le délai d'attente de socket local était '00:00:29.9871037'. ---> System.Net.Sockets.SocketException: Une connexion existante a dû être fermée par l’hôte distant
à System.ServiceModel.Channels.SocketConnection.ReadCore(Byte[] buffer, Int32 offset, Int32 size, TimeSpan timeout, Boolean closing)
--- Fin de la trace de la pile d'exception interne ---
Server stack trace:
à System.ServiceModel.Channels.SocketConnection.ReadCore(Byte[] buffer, Int32 offset, Int32 size, TimeSpan timeout, Boolean closing)
à System.ServiceModel.Channels.SocketConnection.Read(Byte[] buffer, Int32 offset, Int32 size, TimeSpan timeout)
à System.ServiceModel.Channels.DelegatingConnection.Read(Byte[] buffer, Int32 offset, Int32 size, TimeSpan timeout)
à System.ServiceModel.Channels.ClientFramingDuplexSessionChannel.SendPreamble(IConnection connection, ArraySegment`1 preamble, TimeoutHelper& timeoutHelper)
à System.ServiceModel.Channels.ClientFramingDuplexSessionChannel.DuplexConnectionPoolHelper.AcceptPooledConnection(IConnection connection, TimeoutHelper& timeoutHelper)
à System.ServiceModel.Channels.ConnectionPoolHelper.EstablishConnection(TimeSpan timeout)
à System.ServiceModel.Channels.ClientFramingDuplexSessionChannel.OnOpen(TimeSpan timeout)
à System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
à System.ServiceModel.Channels.ServiceChannel.OnOpen(TimeSpan timeout)
à System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
à System.ServiceModel.Channels.ServiceChannel.CallOpenOnce.System.ServiceModel.Channels.ServiceChannel.ICallOnce.Call(ServiceChannel channel, TimeSpan timeout)
à System.ServiceModel.Channels.ServiceChannel.CallOnceManager.CallOnce(TimeSpan timeout, CallOnceManager cascade)
à System.ServiceModel.Channels.ServiceChannel.EnsureOpened(TimeSpan timeout)
à System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
à System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
à System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
Are you using SpellData.Charges to check one spell's availability? the cooldown for spells which have charges is the total cooldown all charges sums up, for gauss round it's 15*3=45s.
I usefor all spell's availability check since all non charged spells which are not in cooldown returns Charges == 1, and those spells have charges return >=1 when at least one charge is useable.Code:public bool Ready => ActionManager.HasSpell(ID) && DataManager.GetSpellData(ID).Charges >= 1;
public static async Task<bool> Cast(this SpellData spell, GameObject target, [CallerMemberName] string caller = null, [CallerLineNumber] int sourceLineNumber = 0, [CallerFilePath] string sourceFilePath = null)
{
if (BaseSettings.Instance.DebugCastingCallerMemberName)
{
Logger.WriteInfo($@"[Cast] [{sourceLineNumber}] {caller}");
if (BaseSettings.Instance.DebugCastingCallerMemberNameIncludePath)
{
Logger.WriteInfo($@"[Path] {sourceFilePath}");
}
}
return await DoAction(spell, target);
}
private static async Task<bool> DoAction(SpellData spell, GameObject target, uint aura = 0, bool needAura = false, bool useRefreshTime = false, int refreshTime = 0)
{
if (!Check(spell, target))
return false;
if (spell.GroundTarget)
{
if (!ActionManager.DoActionLocation(spell.Id, target.Location))
return false;
}
else
{
if (!ActionManager.DoAction(spell, target))
return false;
}
Logger.WriteCast($@"Cast: {spell}");
if (spell.AdjustedCastTime != TimeSpan.Zero)
{
if (!await Coroutine.Wait(3000, () => Core.Me.IsCasting))
{
return false;
}
}
Casting.CastingSpell = spell;
Casting.SpellCastTime = spell.AdjustedCastTime;
Casting.CastingHeal = false;
Casting.SpellTarget = target;
Casting.NeedAura = needAura;
Casting.Aura = aura;
Casting.UseRefreshTime = useRefreshTime;
Casting.RefreshTime = refreshTime;
Casting.CastingTime.Restart();
if (!BaseSettings.Instance.DebugPlayerCasting)
return true;
Debug.Instance.CastingSpell = spell;
Debug.Instance.CastingHeal = false;
Debug.Instance.SpellTarget = target;
Debug.Instance.NeedAura = needAura;
Debug.Instance.Aura = aura;
Debug.Instance.UseRefreshTime = useRefreshTime;
Debug.Instance.RefreshTime = refreshTime;
return true;
}
Hm, I'll remove that check and give it a go. Thanks.Going to assume w/e is inside your Check(spell,target) function is faulty.
Yeah, the Check Function has a ActionaManager.CanCast check. As you said it is not wise otherwise. I can also confirm that something within the Check Function is blocking it. Will investigate. Thank you.Replace it with ActionManager.CanCast, not wise to just assume you can cast w/e spell is being checked.
now i'm using this simple Cast Function To handle all non-groundtarget pvp spell castsThere are 0 checks on my PVP Ricco function, using the same code in PVE Ricco it will cast the 3 charges in a row (expected behaviour with the code I wrote, as it's just test code). However, in the case of PVPRicco it will refuse any other charges that aren't the first one.
So it uses Ricco, and will wait for the CD of the 3rd charge to be reset and then casts it again.
public static async Task<bool> PvPRicochet()
{
return await Spells.PVPRicochet.Cast(Core.Me.CurrentTarget);
}
I can even see RB spamming the following.
[00:16:45.350 D] DoAction Spell 17753 0x40000001
[00:16:45.353 N] Cast: Ricochet
[00:16:45.447 N] Time Casting: 93 - Expected: 0
[00:16:45.448 N] Successfully Casted Ricochet
[00:16:45.450 D] DoAction Spell 17749 0x40000001
[00:16:45.450 N] Cast: Drill
[00:16:45.537 N] Time Casting: 86 - Expected: 0
[00:16:45.537 N] Successfully Casted Drill
[00:16:45.537 D] DoAction Spell 18933 0x40000001
[00:16:45.537 D] DoAction Spell 17749 0x40000001
[00:16:45.538 D] DoAction Spell 17750 0x40000001
[00:16:45.627 D] DoAction Spell 18933 0x40000001
[00:16:45.627 D] DoAction Spell 17749 0x40000001
[00:16:45.627 D] DoAction Spell 17750 0x40000001
[00:16:45.717 D] DoAction Spell 18933 0x40000001
[00:16:45.717 D] DoAction Spell 17749 0x40000001
[00:16:45.717 D] DoAction Spell 17750 0x40000001
[00:16:45.806 D] DoAction Spell 18933 0x40000001
[00:16:45.806 D] DoAction Spell 17749 0x40000001
[00:16:45.806 D] DoAction Spell 17750 0x40000001
[00:16:45.902 D] DoAction Spell 18933 0x40000001
[00:16:45.902 N] Cast: Gauss Round
[00:16:45.988 N] Time Casting: 85 - Expected: 0
[00:16:45.988 N] Successfully Casted Gauss Round
[00:16:45.988 D] DoAction Spell 18933 0x40000001
[00:16:45.988 D] DoAction Spell 17750 0x40000001
[00:16:46.078 D] DoAction Spell 18933 0x40000001
[00:16:46.078 D] DoAction Spell 17750 0x40000001
[00:16:46.168 D] DoAction Spell 18933 0x40000001
[00:16:46.168 D] DoAction Spell 17750 0x40000001
[00:16:46.258 D] DoAction Spell 18933 0x40000001
[00:16:46.258 D] DoAction Spell 17750 0x40000001
[00:16:46.350 D] DoAction Spell 18933 0x40000001
[00:16:46.350 D] DoAction Spell 17750 0x40000001
[00:16:46.438 D] DoAction Spell 18933 0x40000001
[00:16:46.438 D] DoAction Spell 17750 0x40000001
[00:16:46.529 D] DoAction Spell 18933 0x40000001
[00:16:46.529 D] DoAction Spell 17750 0x40000001
public SpellData SpellData
{
get
{
SpellData spell;
if (SpellType == SpellType.PVPCombo)
DataManager.SpellCache.TryGetValue(ActionManager.GetPvPComboCurrentActionId(Combo), out spell);
else
spell = DataManager.GetSpellData(ID);
return spell;
}
}
public Task<bool> Cast(GameObject target = null, bool waitForGcd = false)
{
if (GCDType == GCDType.Off && waitForGcd && OnGcd()) return Task.FromResult(false);
if (target == null)
switch (CastType)
{
case CastType.Target:
if (!Core.Player.HasTarget) return Task.FromResult(false);
target = Core.Target;
break;
case CastType.Self:
target = Core.Me;
break;
default:
throw new ArgumentOutOfRangeException();
}
if (target.CombatDistance() > SpellData.Range) return Task.FromResult(false);
if (!target.InLineOfSight()) return Task.FromResult(false);
if (!ActionManager.CanCast(SpellData, target)) return Task.FromResult(false);
if (SpellType == SpellType.PVPCombo)
{
if (ActionManager.DoPvPCombo(Combo, target))
{
Log.WriteCast($"{SpellData.Id} {SpellData.LocalizedName} >> {target}");
RecentSpells.Enqueue(new RecentSpell(this, target));
return Task.FromResult(true);
}
}
else
{
if (ActionManager.DoAction(SpellData, target))
{
Log.WriteCast($"{SpellData.Id} {SpellData.LocalizedName} >> {target}");
RecentSpells.Enqueue(new RecentSpell(this, target));
return Task.FromResult(true);
}
}
return Task.FromResult(false);
}
now i'm using this simple Cast Function To handle all non-groundtarget pvp spell casts
Code:public SpellData SpellData { get { SpellData spell; if (SpellType == SpellType.PVPCombo) DataManager.SpellCache.TryGetValue(ActionManager.GetPvPComboCurrentActionId(Combo), out spell); else spell = DataManager.GetSpellData(ID); return spell; } } public Task<bool> Cast(GameObject target = null, bool waitForGcd = false) { if (GCDType == GCDType.Off && waitForGcd && OnGcd()) return Task.FromResult(false); if (target == null) switch (CastType) { case CastType.Target: if (!Core.Player.HasTarget) return Task.FromResult(false); target = Core.Target; break; case CastType.Self: target = Core.Me; break; default: throw new ArgumentOutOfRangeException(); } if (target.CombatDistance() > SpellData.Range) return Task.FromResult(false); if (!target.InLineOfSight()) return Task.FromResult(false); if (!ActionManager.CanCast(SpellData, target)) return Task.FromResult(false); if (SpellType == SpellType.PVPCombo) { if (ActionManager.DoPvPCombo(Combo, target)) { Log.WriteCast($"{SpellData.Id} {SpellData.LocalizedName} >> {target}"); RecentSpells.Enqueue(new RecentSpell(this, target)); return Task.FromResult(true); } } else { if (ActionManager.DoAction(SpellData, target)) { Log.WriteCast($"{SpellData.Id} {SpellData.LocalizedName} >> {target}"); RecentSpells.Enqueue(new RecentSpell(this, target)); return Task.FromResult(true); } } return Task.FromResult(false); }
not a lot of checks being needed, and it works pretty well for non-casters
@mastahg do we have a clean way to determine if a spell is successfully being casted or not other than keeps tracking the character's casting time?
[03:02:47.497 D] Exception while contacting authorization server.
[03:02:47.497 D] System.TimeoutException: Cette opération de demande envoyée à net.tcp://auth.eu.buddyauth.com:5031/AuthService.svc n'a pas reçu de réponse dans le délai imparti (00:00:30). Le temps alloué à cette opération fait peut-être partie d'un délai d'attente plus long. Ceci peut être dû au fait que le service est toujours en cours de traitement de l'opération ou qu'il n'a pas pu envoyer un message de réponse. Envisagez d'augmenter le délai d'attente de l'opération (en diffusant le canal/proxy vers IContextChannel et en définissant la propriété OperationTimeout) et vérifiez que le service peut se connecter au client.
Server stack trace:
à System.ServiceModel.Dispatcher.DuplexChannelBinder.Request(Message message, TimeSpan timeout)
à System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
à System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
à System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
Exception rethrown at [0]:
à System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
à System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
à Buddy.Auth.SR.IA.Do(Byte b, Object[] args)
à Buddy.Auth.AuthService.Heartbeat(Object[] args)
à ff14bot.Core.<>c.(AuthService )
à Buddy.Auth.Service.Use[T](Func`2 codeBlock)