Delay command execution over sockets
Posted
by
David
on Game Development
See other posts from Game Development
or by David
Published on 2013-10-30T22:00:47Z
Indexed on
2013/10/30
22:19 UTC
Read the original article
Hit count: 246
I've been trying to fix the game loop in a real time (tick delay) MUD. I realized using Thread.Sleep
would seem clunky when the user spammed commands through their choice of client (Zmud, etc) e.g. east;south;southwest would wait three move ticks and then output everything from the past couple rooms.
The game loop basically calls a Flush
and Fill
method for each socket during each tick (50ms)
private void DoLoop()
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
while (running)
{
// for each socket, flush and fill
ConnectionMonitor.Update();
stopWatch.Stop();
WaitIfNeeded(stopWatch.ElapsedMilliseconds);
stopWatch.Reset();
}
}
The Fill
method fires the command events, but as mentioned before, they currently block using Thread.Sleep
.
I tried adding a "ready" flag to the state object that attempts to execute the command along with a queue of spammed commands, but it ends up executing one command and queuing up the rest i.e. each subsequent command executes something that got queued up that should've been executed before. I must be missing something about the timer.
private readonly Queue<SpammedCommand> queuedCommands = new Queue<SpammedCommand>();
private bool ready = true;
private void TryExecuteCommand(string input)
{
var commandContext = CommandContext.Create(input);
var player = Server.Current.Database.Get<Player>(Session.Player.Key);
var commandInfo = Server.Current.CommandLookup
.FindCommand(commandContext.CommandName, player.IsAdmin);
if (commandInfo != null)
{
if (!ready)
{
// queue command
queuedCommands.Enqueue(new SpammedCommand()
{
Context = commandContext,
Info = commandInfo
});
return;
}
if (queuedCommands.Count > 0)
{
// queue the incoming command
queuedCommands.Enqueue(new SpammedCommand()
{
Context = commandContext,
Info = commandInfo,
});
// dequeue and execute
var command = queuedCommands.Dequeue();
command.Info.Command.Execute(Session, command.Context);
setTimeout(command.Info.TickLength);
return;
}
commandInfo.Command.Execute(Session, commandContext);
setTimeout(commandInfo.TickLength);
}
else
{
Session.WriteLine("Command not recognized");
}
}
Finally, setTimeout
was supposed to set the execution delay (TickLength
) for that command, and makeReady
just sets the ready
flag on the state object to true.
private void setTimeout(TickDelay tickDelay)
{
ready = false;
var t = new System.Timers.Timer()
{
Interval = (long) tickDelay,
AutoReset = false,
};
t.Elapsed += makeReady;
t.Start(); // fire this in tickDelay ms
}
// MAKE READYYYYY!!!!
private void makeReady(object sender, System.Timers.ElapsedEventArgs e)
{
ready = true;
}
Am I missing something about the System.Timers.Timer created in setTimeout? How can I execute (and output) spammed commands per TickLength
without using Thread.Sleep?
© Game Development or respective owner