| By Kevin Hoffman | Article Rating: |
|
| November 2, 2006 11:30 AM EST | Reads: |
6,493 |
If you have read enough of my blog entries, you know that when I encounter a new technology, the first thing I ask is, "That's great, but can I game with it?". The answer to WF is of course, yes.
The basic idea is that NPCs will be instances of workflows managed by a central workflow runtime within the Universe Server. The Universe Server is the server-side portion of UA that drives all of the central state management as well as manages all NPCs and player-persisted data. Each of these NPC workflows will be a state machine. I would have had figures, but my blog software made the "upload" button dissappear on my file space. So, if I had a picture, imagine that in this picture, you saw an initial state. From this initial state, the NPC immediately drops into a state called Patrolling. There's also an end state and possibly a couple other states like Combat and Corpse. The Corpse state is awesome because what I can do is have the hull wreckage still visible (still broadcasting radar pings), but then after a set delay like 30 seconds, I can go to the workflow termination state - at which point the instance dissappears, the memory goes away, and the NPC stops broadcasting radar pings because the workflow isn't running. All of this without having to clog up the main server itself.
I have a state initialization activity on the Patrolling state. As soon as the NPC enters this state, I have an activity that I coded called LaunchWFActivity (should probably call it LaunchPatrolWorkflowActivity now that I think about it... that's what I get for starting with an unrelated proof of concept) that is invoked. This activity launches a sequential workflow called Patrol (stored in Patrol.xoml). Here's the code for the launching activity (again, the naming is poor):
using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Collections;
using System.Drawing;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel.Serialization;
using System.Workflow.Runtime;
using System.Workflow.Activities;
using System.Workflow.Activities.Rules;
namespace NPCWorkflowTest
{
public partial class LaunchWFActivity: SequenceActivity
{
public LaunchWFActivity()
{
InitializeComponent();
}
public static DependencyProperty LaunchedWFGuidProperty =
System.Workflow.ComponentModel.DependencyProperty.Register(
"LaunchedWFGuid", typeof(Guid), typeof(LaunchWFActivity));
[Description("")]
[Category("")]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public Guid LaunchedWFGuid
{
get
{
return ((Guid)(base.GetValue(LaunchWFActivity.LaunchedWFGuidProperty)));
}
set
{
base.SetValue(LaunchWFActivity.LaunchedWFGuidProperty, value);
}
}
protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
{
IStartWorkflow startWorkflow =
executionContext.GetService(typeof(IStartWorkflow)) as IStartWorkflow;
LaunchedWFGuid = startWorkflow.StartWorkflow(typeof(Patrol), null);
Console.WriteLine("Launched patrol WF with Guid {0}", LaunchedWFGuid.ToString());
return ActivityExecutionStatus.Closed;
}
}
}
Something that will prove to be crucial is that I hit the "Promote Bindable Properties" hotlink in the quick tasks panel that shows up below the activity properties when looking at the LaunchWFActivity item in the designer. This makes it so that I can bind the accompanying ShutDownWFActivity (which, of course, should also be renamed to ShutdownPatrolWorkflowActivity) so that it knows what GUID to shut down.
I also need a service that performs the actual shutdown. The model here is that the shutdown activity will grab the (not a) instance of the shutdown service from the execution context and then use the shutdown service to kill the (data-bound) appropriate GUID. Here's the code for the shutdown service (I cut out the using directives, they're the same as the previous code sample):
namespace NPCWorkflowTest
{
public class WFShutDownService : WorkflowRuntimeService
{
public void ShutDownWorkflow(Guid workflowGuidtoShutdown)
{
WorkflowInstance wi = this.Runtime.GetWorkflow(workflowGuidtoShutdown);
wi.Terminate("normal shutdown");
}
}
}
And finally, here's the code from the shutdown activity (which should be called ShutdownPatrolWorkflowActivity):
namespace NPCWorkflowTest
{
public partial class ShutdownWFActivity : Activity
{
public static DependencyProperty WFToShutDownGuidProperty =
System.Workflow.ComponentModel.DependencyProperty.Register("WFToShutDownGuid", typeof(Guid),
typeof(ShutdownWFActivity));
[Description("")]
[Category("")]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public Guid WFToShutDownGuid
{
get
{
return ((Guid)base.GetValue(ShutdownWFActivity.WFToShutDownGuidProperty));
}
set
{
base.SetValue(ShutdownWFActivity.WFToShutDownGuidProperty, value);
}
}
protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
{
WFShutDownService shutdownService = executionContext.GetService<WFShutDownService>();
shutdownService.ShutDownWorkflow(this.WFToShutDownGuid);
return ActivityExecutionStatus.Closed;
}
}
}
In order for this to work, you have to make absolutely sure that you bind the WFToShutDownGuid property to the promoted property fed by the LaunchedWFGuid property from the launch activity. You can have as many child workflows running as you want, that can be interrupted by external events. For example, my implementation uses the ShutdownWFActivity activity to shut down the patrol activity when the state machine workflow as a whole (the NPC) is attacked.
So let's review: I've illustrated by example of NPC behavorial simulation that you can create state machine workflows that spawn sequential workflows when certain states are entered or even when certain events are signalled into the workflow by outside stimuli. You can also dynamically shut down these workflows in response to additional stimuli.
Where am I going with this?:
- I could use the System.IO.Packaging namespace as well as self-host a WF designer to allow anyone running a Universe Server to actually edit the behavior of all classes of NPCs, or maybe even create new classes of NPCS! - all packaged up in a nice neat package like Enemies.pak or something.
- The entire system of NPC interaction could be built into workflows. For example, the NPC could have an infinitely looping sequential workflow that broadcasts a rader ping into the galaxy in which the NPC is currently located. This ping workflow could be toggled on an off based on whether the NPC activates a stealth ability or dies.
- The persistence feature of the workflow system could be used to maintain state for each instance of all running NPCs - completely independent of the Universe Server application. In other words - nearly all of the work involved with maintaining, manipulating, tracking, and persisting NPCs in the game can be managed entirely by the Workflow foundation with the Universe Server just being responsible for instantiating new NPCs on demand.
I'd love to hear comments about this system from WF enthusiasts or even WF critics.
p.s. I also want to thank Serge for a lot of help with the syntax. Now that I look at how its implemented, it seems only natural. But staring at a blank workflow surface trying to figure this out with no samples (that I could find) on the web was daunting.
tags: workflow ulysses wf ai npc behavior
links: digg this del.icio.us technorati reddit
Published November 2, 2006 Reads 6,493
Copyright © 2006 SYS-CON Media, Inc. — All Rights Reserved.
Syndicated stories and blog feeds, all rights reserved by the author.
More Stories By Kevin Hoffman
Kevin Hoffman, editor-in-chief of SYS-CON's iPhone Developer's Journal, has been programming since he was 10 and has written everything from DOS shareware to n-tier, enterprise web applications in VB, C++, Delphi, and C. Hoffman is coauthor of Professional .NET Framework (Wrox Press) and co-author with Robert Foster of Microsoft SharePoint 2007 Development Unleashed. He authors The .NET Addict's Blog at .NET Developer's Journal.
- Kindle 2 vs Nook
- Confessions of a Ulitzer Addict
- IBM Hardware Chief, Intel VC Exec Arrested in Insider Trading Scam
- Tactical Cloud Computing Panel at 1st Annual GovIT Expo
- Ulitzer.com Named Exclusive "New Media" Sponsor of Cloud Computing Conference & Expo
- Infrastructure-as-a-Service Will Mature in 2010: Microsoft's David Chou
- Windows 7 – Microsoft’s First Step to the Cloud
- Cloud Expo and the End of Tech Recession
- Jill Tummler Singer, Deputy CIO of CIA, Keynotes at GovIT Expo
- Reality Check at the Cloud Computing Expo
- Visual Studio 2010 Is Cloud Friendly
- Fired SCO CEO Fires Back
- Kindle 2 vs Nook
- The Difference Between Web Hosting and Cloud Computing
- Ajax in RichFaces 3.3, JSF 2 and RichFaces 4
- Confessions of a Ulitzer Addict
- Wave on Ulitzer: Confessions of a Google Wave Fanboy
- IBM Hardware Chief, Intel VC Exec Arrested in Insider Trading Scam
- Cloud Computing Best Practices
- Tactical Cloud Computing Panel at 1st Annual GovIT Expo
- Ulitzer.com Named Exclusive "New Media" Sponsor of Cloud Computing Conference & Expo
- Infrastructure-as-a-Service Will Mature in 2010: Microsoft's David Chou
- Eval JavaScript in a Global Context
- Windows 7 – Microsoft’s First Step to the Cloud
- Google Maps and ASP.NET
- Crystal Reports XI & How It Has Changed
- Converting VB6 to VB.NET, Part I
- Creating Controls for.NET Compact Framework in Visual Studio 2005
- Where Are RIA Technologies Headed in 2008?
- How to Write High-Performance C# Code
- AJAX World RIA Conference & Expo Kicks Off in New York City
- Implementing Tab Navigation with ASP.NET 2.0
- i-Technology Photo Exclusive: Bill Gates & Steve Jobs In "Nerds"
- .NET Archives: Getting Reacquainted with the Father of C#
- i-Technology Viewpoint: "SOA Sucks"
- Programmatically Posting Data to ASP .NET Web Applications




























