Updates movement packets & Fastwalk (#324)
- [X] Updates Movement packets
- [X] Adds OSI fastwalk packets. These aren't used on OSi anymore.
- [X] Adds new movement handling, but looks like the client doesn't use it. (Also leaving the 0x4000 Character List Flag off)
- [X] Adds time sync request handler, but also looks like the client doesn't use it.
- [X] Adds time sync response for time sync, just in case, but it isn't used, so not sure about the arguments.
- [X] Reimplements RunUO's fastwalk to use a circular array on the netstate instead of every mobile
- [X] Removes ClearFastwalkStack from RunUO implementation. This shouldn't be needed anymore
Changed fastwalk settings:
```cs
public static int WalkFootDelay { get; set; } = 440;
public static int RunFootDelay { get; set; } = 220;
public static int WalkMountDelay { get; set; } = 220;
public static int RunMountDelay { get; set; } = 110;
public static bool EnableFastwalkPrevention { get; set; } = true;
public static AccessLevel FastwalkExemptionLevel { get; set; } = AccessLevel.Counselor;
// If this is changed during runtime, then the steps array needs resizing.
public static int MaxSteps { get; private set; } = 4;
```
modernuo.json
```json
{
"settings": {
"movement.delay.runFoot": "220",
"movement.delay.runMount": "110",
"movement.delay.walkFoot": "440",
"movement.delay.walkMount": "220",
"movement.enableFastWalkPrevention": "True",
"movement.fastwalkExemptionLevel": "Counselor",
"movement.maxSteps": "4"
}
}
```
Notes about OSI fastwalk:
While it does work, I can't find a benefit in using it because of the variable speeds. If players moved at a single speed then we could refill the stack every X milliseconds with 6 keys and use a naive token bucket implementation.
Unfortunately variable speeds mount/run/walk/etc means we would have to use a leaky bucket algorithm.
If we are using a leaky bucket algorithm with a variable leak, then we don't need to send tokens because we are already tracking it on the server side.
ModernUO vs OSI Fastwalk:
When the fastwalk was implemented on OSI, it used up to 6 tokens. These tokens were probably distributed every 600-750 milliseconds. To get the same effect, the new fastwalk settings might need to be adjusted. I would tweak them and feel free to let me know what worked for you!
Bumps release version
This commit is contained in:
parent
b6cd408623
commit
351611a23a
25 changed files with 781 additions and 490 deletions
|
|
@ -85,12 +85,12 @@ namespace Server.Commands
|
|||
{
|
||||
if (e.Length == 1 && !e.GetBoolean(0))
|
||||
{
|
||||
from.Send(SpeedControl.Disable);
|
||||
from.NetState.SendSpeedControl(SpeedControlSetting.Disable);
|
||||
from.SendMessage("Speed boost has been disabled.");
|
||||
}
|
||||
else
|
||||
{
|
||||
from.Send(SpeedControl.MountSpeed);
|
||||
from.NetState.SendSpeedControl(SpeedControlSetting.Mount);
|
||||
from.SendMessage("Speed boost has been enabled.");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,9 +79,8 @@ namespace Server.Items
|
|||
else if (Core.SE && Utility.RandomDouble() > .20 && (from.Direction & Direction.Running) != 0 &&
|
||||
Core.TickCount - from.LastMoveTime < from.ComputeMovementSpeed(from.Direction))
|
||||
{
|
||||
from.SendLocalizedMessage(
|
||||
1063305
|
||||
); // Didn't your parents ever tell you not to run with scissors in your hand?!
|
||||
// Didn't your parents ever tell you not to run with scissors in your hand?!
|
||||
from.SendLocalizedMessage(1063305);
|
||||
}
|
||||
else if (targeted is Item item && !item.Movable)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,34 +0,0 @@
|
|||
namespace Server.Misc
|
||||
{
|
||||
// This fastwalk detection is no longer required
|
||||
// As of B36 PlayerMobile implements movement packet throttling which more reliably controls movement speeds
|
||||
public static class Fastwalk
|
||||
{
|
||||
private static readonly int MaxSteps = 4; // Maximum number of queued steps until fastwalk is detected
|
||||
private static readonly bool Enabled = false; // Is fastwalk detection enabled?
|
||||
private static readonly bool UOTDOverride = false; // Should UO:TD clients not be checked for fastwalk?
|
||||
|
||||
private static readonly AccessLevel
|
||||
AccessOverride = AccessLevel.GameMaster; // Anyone with this or higher access level is not checked for fastwalk
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
Mobile.FwdMaxSteps = MaxSteps;
|
||||
Mobile.FwdEnabled = Enabled;
|
||||
Mobile.FwdUOTDOverride = UOTDOverride;
|
||||
Mobile.FwdAccessOverride = AccessOverride;
|
||||
|
||||
if (Enabled)
|
||||
{
|
||||
EventSink.FastWalk += OnFastWalk;
|
||||
}
|
||||
}
|
||||
|
||||
public static void OnFastWalk(FastWalkEventArgs e)
|
||||
{
|
||||
e.Blocked = true; // disallow this fastwalk
|
||||
var state = e.NetState;
|
||||
state.WriteConsole("Fast movement detected (name={0})", state.Mobile.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -8,7 +8,7 @@ namespace Server.Misc
|
|||
|
||||
public static void Initialize()
|
||||
{
|
||||
IncomingPackets.Register(0xF0, 0, false, DecodeBundledPacket);
|
||||
// IncomingPackets.Register(0xF0, 0, false, DecodeBundledPacket);
|
||||
}
|
||||
|
||||
public static void Register(int packetID, bool ingame, OnPacketReceive onReceive)
|
||||
|
|
|
|||
|
|
@ -221,7 +221,7 @@ namespace Server.Mobiles
|
|||
{
|
||||
if (to.Alive && to.Player && !UnderCacophonicAttack(to))
|
||||
{
|
||||
to.Send(SpeedControl.WalkSpeed);
|
||||
to.NetState.SendSpeedControl(SpeedControlSetting.Walk);
|
||||
to.SendLocalizedMessage(1072069); // A cacophonic sound lambastes you, suppressing your ability to move.
|
||||
to.PlaySound(0x584);
|
||||
|
||||
|
|
@ -233,7 +233,7 @@ namespace Server.Mobiles
|
|||
public virtual void CacophonicEnd(Mobile from)
|
||||
{
|
||||
m_Table.Remove(from);
|
||||
from.Send(SpeedControl.Disable);
|
||||
from.NetState.SendSpeedControl(SpeedControlSetting.Disable);
|
||||
}
|
||||
|
||||
public static bool UnderCacophonicAttack(Mobile from) => m_Table.Contains(from);
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ using Server.Spells.Spellweaving;
|
|||
using Server.Targeting;
|
||||
using Server.Utilities;
|
||||
using BaseQuestGump = Server.Engines.MLQuests.Gumps.BaseQuestGump;
|
||||
using CalcMoves = Server.Movement.Movement;
|
||||
using QuestOfferGump = Server.Engines.MLQuests.Gumps.QuestOfferGump;
|
||||
using RankDefinition = Server.Guilds.RankDefinition;
|
||||
|
||||
|
|
@ -96,9 +97,6 @@ namespace Server.Mobiles
|
|||
{
|
||||
private static bool m_NoRecursion;
|
||||
|
||||
private static readonly bool FastwalkPrevention = true; // Is fastwalk prevention enabled?
|
||||
private static readonly int FastwalkThreshold = 400; // Fastwalk prevention will become active after 0.4 seconds
|
||||
|
||||
private static readonly Point3D[] m_TrammelDeathDestinations =
|
||||
{
|
||||
new Point3D(1481, 1612, 20),
|
||||
|
|
@ -166,7 +164,6 @@ namespace Server.Mobiles
|
|||
private RankDefinition m_GuildRank;
|
||||
|
||||
private int m_HairModID = -1, m_HairModHue;
|
||||
private bool m_HasMoved;
|
||||
|
||||
public DateTime m_hontime;
|
||||
|
||||
|
|
@ -188,7 +185,7 @@ namespace Server.Mobiles
|
|||
|
||||
private DateTime m_NextJustAward;
|
||||
|
||||
private long m_NextMovementTime;
|
||||
private int m_NextMovementTime;
|
||||
private int m_NextProtectionCheck = 10;
|
||||
private DateTime m_NextSmithBulkOrder;
|
||||
private DateTime m_NextTailorBulkOrder;
|
||||
|
|
@ -715,8 +712,6 @@ namespace Server.Mobiles
|
|||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public SolenFriendship SolenFriendship { get; set; }
|
||||
|
||||
public virtual bool UsesFastwalkPrevention => AccessLevel < AccessLevel.Counselor;
|
||||
|
||||
public Type EnemyOfOneType
|
||||
{
|
||||
get => m_EnemyOfOneType;
|
||||
|
|
@ -1031,11 +1026,6 @@ namespace Server.Mobiles
|
|||
|
||||
public static void Initialize()
|
||||
{
|
||||
if (FastwalkPrevention)
|
||||
{
|
||||
IncomingPackets.RegisterThrottler(0x02, MovementThrottle_Callback);
|
||||
}
|
||||
|
||||
EventSink.Login += OnLogin;
|
||||
EventSink.Logout += OnLogout;
|
||||
EventSink.Connected += EventSink_Connected;
|
||||
|
|
@ -4264,59 +4254,30 @@ namespace Server.Mobiles
|
|||
SentHonorContext?.Cancel();
|
||||
}
|
||||
|
||||
public override int ComputeMovementSpeed(Direction dir, bool checkTurning)
|
||||
public override int ComputeMovementSpeed(Direction dir, bool checkTurning = true)
|
||||
{
|
||||
if (checkTurning && (dir & Direction.Mask) != (Direction & Direction.Mask))
|
||||
{
|
||||
return RunMount; // We are NOT actually moving (just a direction change)
|
||||
return CalcMoves.RunMountDelay; // We are NOT actually moving (just a direction change)
|
||||
}
|
||||
|
||||
var context = TransformationSpellHelper.GetContext(this);
|
||||
|
||||
if (context?.Type == typeof(ReaperFormSpell))
|
||||
{
|
||||
return WalkFoot;
|
||||
return CalcMoves.WalkFootDelay;
|
||||
}
|
||||
|
||||
var running = (dir & Direction.Running) != 0;
|
||||
|
||||
var onHorse = Mount != null;
|
||||
|
||||
var animalContext = AnimalForm.GetContext(this);
|
||||
|
||||
if (onHorse || animalContext?.SpeedBoost == true)
|
||||
if (onHorse || AnimalForm.GetContext(this)?.SpeedBoost == true)
|
||||
{
|
||||
return running ? RunMount : WalkMount;
|
||||
return running ? CalcMoves.RunMountDelay : CalcMoves.WalkMountDelay;
|
||||
}
|
||||
|
||||
return running ? RunFoot : WalkFoot;
|
||||
}
|
||||
|
||||
public static TimeSpan MovementThrottle_Callback(NetState ns)
|
||||
{
|
||||
if (!(ns.Mobile is PlayerMobile pm) || !pm.UsesFastwalkPrevention)
|
||||
{
|
||||
return TimeSpan.Zero;
|
||||
}
|
||||
|
||||
if (!pm.m_HasMoved)
|
||||
{
|
||||
// has not yet moved
|
||||
pm.m_NextMovementTime = Core.TickCount;
|
||||
pm.m_HasMoved = true;
|
||||
return TimeSpan.Zero;
|
||||
}
|
||||
|
||||
var ts = pm.m_NextMovementTime - Core.TickCount;
|
||||
|
||||
if (ts < 0)
|
||||
{
|
||||
// been a while since we've last moved
|
||||
pm.m_NextMovementTime = Core.TickCount;
|
||||
return TimeSpan.Zero;
|
||||
}
|
||||
|
||||
return ts < FastwalkThreshold ? TimeSpan.Zero : TimeSpan.FromTicks(ts);
|
||||
return running ? CalcMoves.RunFootDelay : CalcMoves.WalkFootDelay;
|
||||
}
|
||||
|
||||
private void DeltaEnemies(Type oldType, Type newType)
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ namespace Server.Regions
|
|||
if (ns != null && !TransformationSpellHelper.UnderTransformation(m, typeof(AnimalForm)) &&
|
||||
m.AccessLevel == AccessLevel.Player)
|
||||
{
|
||||
ns.Send(SpeedControl.WalkSpeed);
|
||||
ns.SendSpeedControl(SpeedControlSetting.Walk);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -32,7 +32,7 @@ namespace Server.Regions
|
|||
var ns = m.NetState;
|
||||
if (ns != null && !TransformationSpellHelper.UnderTransformation(m, typeof(AnimalForm)))
|
||||
{
|
||||
ns.Send(SpeedControl.Disable);
|
||||
ns.SendSpeedControl(SpeedControlSetting.Disable);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -40,7 +40,7 @@ namespace Server.Regions
|
|||
{
|
||||
if (m.Region.IsPartOf<TwistedWealdDesertRegion>() && m.AccessLevel == AccessLevel.Player)
|
||||
{
|
||||
m.NetState.Send(SpeedControl.WalkSpeed);
|
||||
m.NetState.SendSpeedControl(SpeedControlSetting.Walk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ namespace Server.Spells.Ninjitsu
|
|||
{
|
||||
if (GetContext(m)?.SpeedBoost == true)
|
||||
{
|
||||
m.Send(SpeedControl.MountSpeed);
|
||||
m.NetState.SendSpeedControl(SpeedControlSetting.Mount);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -243,7 +243,7 @@ namespace Server.Spells.Ninjitsu
|
|||
|
||||
if (entry.SpeedBoost)
|
||||
{
|
||||
m.Send(SpeedControl.MountSpeed);
|
||||
m.NetState.SendSpeedControl(SpeedControlSetting.Mount);
|
||||
}
|
||||
|
||||
SkillMod mod = null;
|
||||
|
|
@ -296,7 +296,7 @@ namespace Server.Spells.Ninjitsu
|
|||
|
||||
if (context.SpeedBoost)
|
||||
{
|
||||
m.Send(SpeedControl.Disable);
|
||||
m.NetState.SendSpeedControl(SpeedControlSetting.Disable);
|
||||
}
|
||||
|
||||
var mod = context.Mod;
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ namespace Server.Spells.Spellweaving
|
|||
|
||||
if (context?.Type == typeof(ReaperFormSpell))
|
||||
{
|
||||
m.Send(SpeedControl.WalkSpeed);
|
||||
m.NetState.SendSpeedControl(SpeedControlSetting.Walk);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -46,12 +46,12 @@ namespace Server.Spells.Spellweaving
|
|||
{
|
||||
m.PlaySound(0x1BA);
|
||||
|
||||
m.Send(SpeedControl.WalkSpeed);
|
||||
m.NetState.SendSpeedControl(SpeedControlSetting.Walk);
|
||||
}
|
||||
|
||||
public override void RemoveEffect(Mobile m)
|
||||
{
|
||||
m.Send(SpeedControl.Disable);
|
||||
m.NetState.SendSpeedControl(SpeedControlSetting.Disable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue