├── Assets ├── README.md ├── snapshot.json └── templates.json ├── GameLogic ├── BallCollisionSystem.cs ├── BallData.cs ├── BallSpawningData.cs ├── BallSpawningSystem.cs ├── GameLogic.csproj ├── MapBoundsData.cs ├── MovementData.cs ├── MovementSystem.cs ├── PaddleCollectionSystem.cs ├── PaddleData.cs ├── PositionData.cs ├── Properties │ └── AssemblyInfo.cs ├── README.md ├── TemporaryData.cs └── TemporarySystem.cs ├── README.md ├── Unity ├── MapBoundsRenderer.cs ├── MapBoundsRenderer.cs.meta ├── PositionRenderer.cs ├── PositionRenderer.cs.meta ├── Resources.meta ├── Resources │ ├── BallPrefab.prefab │ ├── BallPrefab.prefab.meta │ ├── PaddlePrefab.prefab │ ├── PaddlePrefab.prefab.meta │ ├── WorldPrefab.prefab │ └── WorldPrefab.prefab.meta ├── SystemProvider.cs └── SystemProvider.cs.meta ├── XNA.sln ├── XNA ├── DLLs │ ├── Forge.AllLibraries.dll │ ├── Forge.AllLibraries.pdb │ ├── Forge.Collections.dll │ ├── Forge.Collections.pdb │ ├── Forge.Collections.xml │ ├── Forge.Entities.dll │ ├── Forge.Entities.pdb │ ├── Forge.Entities.xml │ ├── Forge.Extensions.dll │ ├── Forge.Extensions.pdb │ ├── Forge.Extensions.xml │ ├── Forge.Networking.dll │ ├── Forge.Networking.pdb │ ├── Forge.Networking.xml │ ├── Forge.Utilities.dll │ ├── Forge.Utilities.pdb │ ├── Forge.Utilities.xml │ ├── Lidgren.Network.dll │ ├── Lidgren.Network.pdb │ ├── Lidgren.Network.xml │ ├── Newtonsoft.Json.dll │ ├── Newtonsoft.Json.pdb │ ├── Newtonsoft.Json.xml │ ├── log4net.dll │ └── log4net.xml ├── XNA │ ├── ExtendedSpriteBatch.cs │ ├── Forge │ │ ├── DataRegistry.cs │ │ ├── DataRenderer.cs │ │ ├── EntityContainerEventMonitor.cs │ │ ├── GameEngineManager.cs │ │ ├── IEventMonitor.cs │ │ ├── PrefabData.cs │ │ ├── README.md │ │ └── Visualizer.cs │ ├── Game.ico │ ├── GameThumbnail.png │ ├── PositionRenderer.cs │ ├── Program.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── XNA.csproj │ ├── XNA.csproj.user │ └── XnaGame.cs └── XNAContent │ └── XNAContent.contentproj ├── demo_unity.gif └── demo_xna.gif /Assets/README.md: -------------------------------------------------------------------------------- 1 | `snapshot.json` is a saved game that contains some interesting initial data, such as where the paddles are and the dimensions of the map. Currently the `PrefabData` instances are only used for the Unity version, but if the XNA version implemented more sophisticated rendering it would also be used. 2 | 3 | `templates.json` contains the definition of a ball. The data serialization format here is going to change slightly in an upcoming patch to mirror that of `snapshot.json` (you won't see "$type" anymore). -------------------------------------------------------------------------------- /Assets/snapshot.json: -------------------------------------------------------------------------------- 1 | { 2 | "EntityIdGenerator": { 3 | "NextId": 4 4 | }, 5 | "GlobalEntity": [ 6 | { 7 | "UniqueId": 0, 8 | "PrettyName": "Global Entity", 9 | "Data": [ 10 | { 11 | "WasAdded": true, 12 | "DataType": "Forge.PrefabData", 13 | "CurrentData": { 14 | "PrefabResourcePath": "WorldPrefab" 15 | } 16 | }, 17 | { 18 | "WasAdded": true, 19 | "DataType": "GameSample.MapBoundsData", 20 | "CurrentData": { 21 | "Width": 13, 22 | "Height": 7 23 | } 24 | }, 25 | { 26 | "WasAdded": true, 27 | "DataType": "GameSample.BallSpawningData", 28 | "CurrentData": { 29 | "MaxTicks": 25, 30 | "MinTicks": 10, 31 | "Remaining": 0, 32 | "Ball": { 33 | "ReferencedId": 10000, 34 | "ReferenceType": "TemplateReference" 35 | } 36 | } 37 | } 38 | ] 39 | } 40 | ], 41 | "AddedEntities": [ 42 | { 43 | "UniqueId": 2, 44 | "PrettyName": "Paddle1", 45 | "Data": [ 46 | { 47 | "WasAdded": true, 48 | "DataType": "Forge.PrefabData", 49 | "CurrentData": { 50 | "PrefabResourcePath": "PaddlePrefab" 51 | } 52 | }, 53 | { 54 | "WasAdded": true, 55 | "DataType": "GameSample.PositionData", 56 | "CurrentData": { 57 | "Position": { 58 | "X": 5.0, 59 | "Z": 0.0, 60 | "Radius": 3.0 61 | } 62 | }, 63 | "PreviousData": { 64 | "Position": { 65 | "X": 0.0, 66 | "Z": 0.0, 67 | "Radius": 0.0 68 | } 69 | } 70 | }, 71 | { 72 | "WasAdded": true, 73 | "DataType": "GameSample.MovementData", 74 | "CurrentData": { 75 | "Velocity": { 76 | "X": 0.0, 77 | "Z": 0.100097656 78 | } 79 | }, 80 | "PreviousData": { 81 | "Velocity": { 82 | "X": 0.0, 83 | "Z": 0.0 84 | } 85 | } 86 | }, 87 | { 88 | "WasAdded": true, 89 | "DataType": "GameSample.PaddleData", 90 | "CurrentData": {} 91 | } 92 | ] 93 | }, 94 | { 95 | "UniqueId": 3, 96 | "PrettyName": "Paddle2", 97 | "Data": [ 98 | { 99 | "WasAdded": true, 100 | "DataType": "Forge.PrefabData", 101 | "CurrentData": { 102 | "PrefabResourcePath": "PaddlePrefab" 103 | } 104 | }, 105 | { 106 | "WasAdded": true, 107 | "DataType": "GameSample.PositionData", 108 | "CurrentData": { 109 | "Position": { 110 | "X": -5.0, 111 | "Z": 0.0, 112 | "Radius": 3.0 113 | } 114 | }, 115 | "PreviousData": { 116 | "Position": { 117 | "X": 0.0, 118 | "Z": 0.0, 119 | "Radius": 0.0 120 | } 121 | } 122 | }, 123 | { 124 | "WasAdded": true, 125 | "DataType": "GameSample.MovementData", 126 | "CurrentData": { 127 | "Velocity": { 128 | "X": 0.0, 129 | "Z": -0.100097656 130 | } 131 | }, 132 | "PreviousData": { 133 | "Velocity": { 134 | "X": 0.0, 135 | "Z": 0.0 136 | } 137 | } 138 | }, 139 | { 140 | "WasAdded": true, 141 | "DataType": "GameSample.PaddleData", 142 | "CurrentData": {} 143 | } 144 | ] 145 | } 146 | ], 147 | "ActiveEntities": [], 148 | "RemovedEntities": [], 149 | "Systems": [ 150 | { 151 | "Type": "GameSample.PaddleCollectionSystem", 152 | "System": { 153 | "$id": "1", 154 | "Paddles": [] 155 | } 156 | }, 157 | { 158 | "Type": "GameSample.BallCollisionSystem", 159 | "System": { 160 | "_paddles": { 161 | "$ref": "1" 162 | } 163 | } 164 | }, 165 | { 166 | "Type": "GameSample.MovementSystem", 167 | "System": {} 168 | }, 169 | { 170 | "Type": "GameSample.BallSpawningSystem", 171 | "System": {} 172 | }, 173 | { 174 | "Type": "GameSample.TemporarySystem", 175 | "System": {} 176 | } 177 | ] 178 | } -------------------------------------------------------------------------------- /Assets/templates.json: -------------------------------------------------------------------------------- 1 | { 2 | "Templates": [ 3 | { 4 | "TemplateId": 10000, 5 | "PrettyName": "Ball", 6 | "DefaultDataInstances": [ 7 | { 8 | "$type": "Forge.PrefabData", 9 | "PrefabResourcePath": "BallPrefab" 10 | }, 11 | { 12 | "$type": "GameSample.PositionData", 13 | "Position": { 14 | "X": 0.0, 15 | "Z": 0.0, 16 | "Radius": 0.300048828 17 | } 18 | }, 19 | { 20 | "$type": "GameSample.MovementData", 21 | "Velocity": { 22 | "X": 0.300048828, 23 | "Z": 0.199951172 24 | } 25 | }, 26 | { 27 | "$type": "GameSample.BallData", 28 | "CollisionDisabled": 0 29 | }, 30 | { 31 | "$type": "GameSample.TemporaryData", 32 | "TicksRemaining": 50 33 | } 34 | ] 35 | } 36 | ], 37 | "TemplateIdGenerator": { 38 | "NextId": 10001 39 | } 40 | } -------------------------------------------------------------------------------- /GameLogic/BallCollisionSystem.cs: -------------------------------------------------------------------------------- 1 | using Forge.Entities; 2 | using Forge.Utilities; 3 | using Newtonsoft.Json; 4 | using System; 5 | 6 | namespace GameSample { 7 | /// 8 | /// If a ball hits a paddle, then the ball reverses direction. 9 | /// 10 | [JsonObject(MemberSerialization.OptIn)] 11 | public class BallCollisionSystem : BaseSystem, Trigger.Update { 12 | /// 13 | /// The system that we get our paddles from. 14 | /// 15 | [JsonProperty] 16 | private PaddleCollectionSystem _paddles; 17 | 18 | public BallCollisionSystem(PaddleCollectionSystem paddles) { 19 | _paddles = paddles; 20 | } 21 | 22 | /// 23 | /// We want to ensure that our paddle system executes before us, as we are using data from 24 | /// it. 25 | /// 26 | protected override SystemExecutionOrdering GetExecutionOrdering(ISystem system) { 27 | if (system == _paddles) { 28 | return SystemExecutionOrdering.AfterOther; 29 | } 30 | 31 | return base.GetExecutionOrdering(system); 32 | } 33 | 34 | public void OnUpdate(IEntity ball) { 35 | // If we just modified the velocity of the ball, then don't modify it again until the 36 | // cooldown has finished. 37 | if (ball.Current().CollisionDisabled > 0) { 38 | ball.Modify().CollisionDisabled--; 39 | return; 40 | } 41 | 42 | foreach (IEntity paddle in _paddles.Paddles) { 43 | Bound paddlePosition = paddle.Current().Position; 44 | Bound ballPosition = ball.Current().Position; 45 | 46 | // change the direction of the ball if it's colliding with a paddle 47 | if (paddlePosition.Intersects(ballPosition)) { 48 | ball.Modify().MultVelocity(-1, 1); 49 | ball.Modify().CollisionDisabled = 5; 50 | break; 51 | } 52 | } 53 | } 54 | 55 | /// 56 | /// The ball collision system only cares about entities that have PongData, MovementData, 57 | /// and PositionData. 58 | /// 59 | public Type[] RequiredDataTypes { 60 | get { 61 | return new Type[] { 62 | typeof(BallData), typeof(MovementData), typeof(PositionData) 63 | }; 64 | } 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /GameLogic/BallData.cs: -------------------------------------------------------------------------------- 1 | using Forge.Entities; 2 | using Newtonsoft.Json; 3 | using System; 4 | using System.Collections.Generic; 5 | 6 | namespace GameSample { 7 | /// 8 | /// Contains information specific to a ball. 9 | /// 10 | [JsonObject(MemberSerialization.OptIn)] 11 | public class BallData : Data.NonVersioned { 12 | /// 13 | /// How many game ticks is collision disabled for? 14 | /// 15 | [JsonProperty] 16 | public int CollisionDisabled; 17 | } 18 | } -------------------------------------------------------------------------------- /GameLogic/BallSpawningData.cs: -------------------------------------------------------------------------------- 1 | using Forge.Entities; 2 | using Newtonsoft.Json; 3 | 4 | namespace GameSample { 5 | [JsonObject(MemberSerialization.OptIn)] 6 | public class BallSpawningData : Data.NonVersioned { 7 | /// 8 | /// The maximum number of ticks before a spawn occurs. 9 | /// 10 | [JsonProperty] 11 | public int MaxTicks; 12 | 13 | /// 14 | /// The minimum number of ticks before a spawn occurs. 15 | /// 16 | [JsonProperty] 17 | public int MinTicks; 18 | 19 | /// 20 | /// The number of ticks remaining until the next spawn. 21 | /// 22 | [JsonProperty] 23 | public int Remaining; 24 | 25 | /// 26 | /// The ball template used to create new ball entities. 27 | /// 28 | [JsonProperty] 29 | public ITemplate Ball; 30 | } 31 | } -------------------------------------------------------------------------------- /GameLogic/BallSpawningSystem.cs: -------------------------------------------------------------------------------- 1 | using Forge.Entities; 2 | using Forge.Utilities; 3 | using System; 4 | 5 | namespace GameSample { 6 | /// 7 | /// Spawns balls every so often. 8 | /// 9 | public class BallSpawningSystem : BaseSystem, Trigger.GlobalPostUpdate { 10 | public void OnGlobalPostUpdate() { 11 | BallSpawningData spawningData = GlobalEntity.Current(); 12 | 13 | // can we spawn? 14 | if (spawningData.Remaining <= 0) { 15 | // create a new ball 16 | IEntity spawned = spawningData.Ball.Instantiate(); 17 | 18 | // it isn't necessary to set the position of the spawned object to zero, but it 19 | // demos how to initialize a newly created entity 20 | PositionData spawnedPosition = spawned.AddOrModify(); 21 | spawnedPosition.Position = new Bound(0, 0, spawnedPosition.Position.Radius); 22 | 23 | // reset the ticks until the next spawn 24 | GlobalEntity.Modify().Remaining = 25 | GameRandom.Range(spawningData.MinTicks, spawningData.MaxTicks); 26 | } 27 | 28 | // can't spawn yet; decrement the number of ticks until we can spawn again 29 | else { 30 | GlobalEntity.Modify().Remaining--; 31 | } 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /GameLogic/GameLogic.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {A0314C4B-6CBA-4D0F-B32F-24B450A0DDEF} 8 | Library 9 | Properties 10 | GameLogic 11 | GameLogic 12 | v4.0 13 | 512 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | ..\XNA\DLLs\Forge.AllLibraries.dll 36 | 37 | 38 | ..\XNA\DLLs\Forge.Collections.dll 39 | 40 | 41 | ..\XNA\DLLs\Forge.Entities.dll 42 | 43 | 44 | ..\XNA\DLLs\Forge.Extensions.dll 45 | 46 | 47 | ..\XNA\DLLs\Forge.Networking.dll 48 | 49 | 50 | ..\XNA\DLLs\Forge.Utilities.dll 51 | 52 | 53 | ..\XNA\DLLs\Lidgren.Network.dll 54 | 55 | 56 | ..\XNA\DLLs\log4net.dll 57 | 58 | 59 | ..\XNA\DLLs\Newtonsoft.Json.dll 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 91 | -------------------------------------------------------------------------------- /GameLogic/MapBoundsData.cs: -------------------------------------------------------------------------------- 1 | using Forge.Entities; 2 | using Newtonsoft.Json; 3 | 4 | namespace GameSample { 5 | /// 6 | /// Data that contains the dimensions of the map. 7 | /// 8 | [JsonObject(MemberSerialization.OptIn)] 9 | public class MapBoundsData : Data.NonVersioned { 10 | /// 11 | /// Width the map 12 | /// 13 | [JsonProperty] 14 | public int Width; 15 | 16 | /// 17 | /// Height of the map 18 | /// 19 | [JsonProperty] 20 | public int Height; 21 | } 22 | } -------------------------------------------------------------------------------- /GameLogic/MovementData.cs: -------------------------------------------------------------------------------- 1 | using Forge.Entities; 2 | using Forge.Utilities; 3 | using Newtonsoft.Json; 4 | using System.Runtime.CompilerServices; 5 | 6 | namespace GameSample { 7 | /// 8 | /// Data that contains movement information for an object. Because this data type extends 9 | /// ConcurrentVersioned, it can be modified multiple times per update. 10 | /// 11 | [JsonObject(MemberSerialization.OptIn)] 12 | public class MovementData : Data.ConcurrentVersioned { 13 | /// 14 | /// The velocity of the object. This can be modified by multiple threads at the same time, 15 | /// so we ensure that it is synchronized. 16 | /// 17 | [JsonProperty] 18 | public Vector2r Velocity { 19 | get; 20 | private set; 21 | } 22 | 23 | /// 24 | /// Multiples the velocity by the given factors. 25 | /// 26 | /// The x factor to multiply the velocity by. 27 | /// The z factor to multiple the velocity by. 28 | [MethodImpl(MethodImplOptions.Synchronized)] 29 | public void MultVelocity(Real x, Real z) { 30 | Velocity = new Vector2r(Velocity.X * x, Velocity.Z * z); 31 | } 32 | 33 | public override void CopyFrom(MovementData source) { 34 | this.Velocity = source.Velocity; 35 | } 36 | 37 | /// 38 | /// If this data type needed to do some bookkeeping after each update (because modifications 39 | /// can happen concurrently), we can do it in this function. MovementData doesn't need any 40 | /// bookkeeping, so the function is empty. 41 | /// 42 | public override void ResolveConcurrentModifications() { 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /GameLogic/MovementSystem.cs: -------------------------------------------------------------------------------- 1 | using Forge.Entities; 2 | using Forge.Utilities; 3 | using Newtonsoft.Json; 4 | using System; 5 | 6 | namespace GameSample { 7 | /// 8 | /// The movement system ensures that objects do not leave the map and also moves them according 9 | /// to their velocity. 10 | /// 11 | [JsonObject(MemberSerialization.OptIn)] 12 | public class MovementSystem : BaseSystem, Trigger.Update { 13 | /// 14 | /// Every update, we want to ensure that objects are inside the map and we also want to move 15 | /// the object according to its velocity. 16 | /// 17 | public void OnUpdate(IEntity entity) { 18 | MapBoundsData mapBounds = GlobalEntity.Current(); 19 | 20 | RespondToMapBounds(mapBounds, entity); 21 | IntegratePosition(entity); 22 | } 23 | 24 | /// 25 | /// Moves an object to its next position according to its current velocity. 26 | /// 27 | private static void IntegratePosition(IEntity entity) { 28 | PositionData pos = entity.Current(); 29 | MovementData mov = entity.Current(); 30 | 31 | entity.Modify().Position = new Bound( 32 | pos.Position.X + mov.Velocity.X, 33 | pos.Position.Z + mov.Velocity.Z, 34 | pos.Position.Radius 35 | ); 36 | } 37 | 38 | /// 39 | /// Changes an objects velocity if it has left the map. 40 | /// 41 | private static void RespondToMapBounds(MapBoundsData mapBounds, IEntity entity) { 42 | PositionData pos = entity.Current(); 43 | MovementData mov = entity.Current(); 44 | 45 | if (((pos.Position.Z - pos.Position.Radius) < -mapBounds.Height && mov.Velocity.Z < 0) || 46 | ((pos.Position.Z + pos.Position.Radius) > mapBounds.Height && mov.Velocity.Z > 0)) { 47 | entity.Modify().MultVelocity(1, -1); 48 | } 49 | if (((pos.Position.X - pos.Position.Radius) < -mapBounds.Width && mov.Velocity.X < 0) || 50 | ((pos.Position.X + pos.Position.Radius) > mapBounds.Width && mov.Velocity.X > 0)) { 51 | entity.Modify().MultVelocity(-1, 1); 52 | } 53 | } 54 | 55 | /// 56 | /// We only want entities that have both MovementData and PositionData. 57 | /// 58 | public Type[] RequiredDataTypes { 59 | get { 60 | return new[] { 61 | typeof(MovementData), typeof(PositionData) 62 | }; 63 | } 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /GameLogic/PaddleCollectionSystem.cs: -------------------------------------------------------------------------------- 1 | using Forge.Entities; 2 | using Newtonsoft.Json; 3 | using System; 4 | using System.Collections.Generic; 5 | 6 | namespace GameSample { 7 | /// 8 | /// A system that merely collects a list of all paddles in the game. This may be unnecessary in 9 | /// a future version of Forge, but for now it works well as a sample for some more of the 10 | /// triggers. 11 | /// 12 | /// 13 | /// We serialize the object as a reference so that the BallCollisionSystem is properly restored. 14 | /// 15 | [JsonObject(MemberSerialization.OptIn, IsReference = true)] 16 | public class PaddleCollectionSystem : BaseSystem, Trigger.Added, Trigger.Removed { 17 | /// 18 | /// Every paddle in the game. 19 | /// 20 | [JsonProperty] 21 | public List Paddles = new List(); 22 | 23 | public void OnAdded(IEntity entity) { 24 | Paddles.Add(entity); 25 | } 26 | 27 | public void OnRemoved(IEntity entity) { 28 | Paddles.Remove(entity); 29 | } 30 | 31 | public Type[] RequiredDataTypes { 32 | get { return new[] { typeof(PositionData), typeof(PaddleData) }; } 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /GameLogic/PaddleData.cs: -------------------------------------------------------------------------------- 1 | using Forge.Entities; 2 | using Newtonsoft.Json; 3 | 4 | namespace GameSample { 5 | /// 6 | /// Data type used to mark an object as a paddle. 7 | /// 8 | [JsonObject(MemberSerialization.OptIn)] 9 | public class PaddleData : Data.NonVersioned { 10 | } 11 | } -------------------------------------------------------------------------------- /GameLogic/PositionData.cs: -------------------------------------------------------------------------------- 1 | using Forge.Entities; 2 | using Forge.Utilities; 3 | using Newtonsoft.Json; 4 | 5 | namespace GameSample { 6 | /// 7 | /// Provides an Entity with a position and a radius. Because the data extends Versioned, we can 8 | /// query the previous state of the data. 9 | /// 10 | [JsonObject(MemberSerialization.OptIn)] 11 | public class PositionData : Data.Versioned { 12 | /// 13 | /// The position and radius of the object. 14 | /// 15 | [JsonProperty] 16 | public Bound Position; 17 | 18 | /// 19 | /// There is another PositionData instance that we should copy values from into this 20 | /// instance. 21 | /// 22 | public override void CopyFrom(PositionData source) { 23 | this.Position = source.Position; 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /GameLogic/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("GameLogic")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("GameLogic")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("840a6021-35bf-4d40-915b-3be295a3875c")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /GameLogic/README.md: -------------------------------------------------------------------------------- 1 | # Files 2 | 3 | The `GameLogic` folder contains the interesting game-specific code. 4 | 5 | `BallCollisionSystem` causes balls to reverse direction when they hit entities with `PaddleData`. 6 | 7 | `BallData` defines what a ball is, and contains data that causes collision response to be temporarily disabled when a ball hits a paddle. 8 | 9 | `BallSpawningData` is data that is stored in the `GlobalEntity` that the `BallSpawningSystem` uses to spawn balls. 10 | 11 | `BallSpawningSystem` instantiates an `ITemplate` (that is defined in `snapshot.json` and `templates.json`) which is defined as a ball. 12 | 13 | `MapBoundsData` defines the size of the map and is only contained on the `GlobalEntity`. 14 | 15 | `MovementData` defines a velocity for an entity so that it can move around the map. 16 | 17 | `MovementSystem` takes entities with both `PositionData` and `MovementData` and moves them. 18 | 19 | `PaddleCollectionSystem` merely collects all entities that have `PaddleData`. This system is used by the `BallCollisionSystem`. 20 | 21 | `PaddleData` tags entities so that the `PaddleCollectionSystem` will contain said entity, 22 | 23 | `PositionData` defines the position of an entity on the map. 24 | 25 | `TemporaryData` gives an entity a limited lifetime; after a certain number of ticks, the `TemporarySystem` will destroy it. 26 | 27 | `TemporarySystem` destroys entities whose `TemporaryData` has reached 0. This system also demos input; `StopDestroyingInput` disables destroying entities and `StartDestroyingInput` enables destroying entities. Actually sending the input into the game is engine specific (as it depends on the input layer); in the XNA sample pressing the 1 key enables destruction and the 2 key disables it. -------------------------------------------------------------------------------- /GameLogic/TemporaryData.cs: -------------------------------------------------------------------------------- 1 | using Forge.Entities; 2 | using Newtonsoft.Json; 3 | 4 | namespace GameSample { 5 | /// 6 | /// An entity that contains TemporaryData will be removed after a certain number of game 7 | /// updates. 8 | /// 9 | [JsonObject(MemberSerialization.OptIn)] 10 | public class TemporaryData : Data.NonVersioned { 11 | /// 12 | /// The number of ticks that this object has left alive. 13 | /// 14 | [JsonProperty] 15 | public int TicksRemaining; 16 | } 17 | } -------------------------------------------------------------------------------- /GameLogic/TemporarySystem.cs: -------------------------------------------------------------------------------- 1 | using Forge.Entities; 2 | using Forge.Networking.AutomaticTurnGame; 3 | using Newtonsoft.Json; 4 | using System; 5 | 6 | namespace GameSample { 7 | /// 8 | /// Entities will no longer be destroyed by the temporary system. 9 | /// 10 | [JsonObject(MemberSerialization.OptIn)] 11 | public class StopDestroyingInput : IGameInput, IGameCommand { } 12 | 13 | /// 14 | /// Entities will be destroyed by the temporary system. 15 | /// 16 | [JsonObject(MemberSerialization.OptIn)] 17 | public class StartDestroyingInput : IGameInput, IGameCommand { } 18 | 19 | /// 20 | /// The temporary system removes entities who have expired according to their temporary data. 21 | /// 22 | [JsonObject(MemberSerialization.OptIn)] 23 | public class TemporarySystem : BaseSystem, Trigger.Update, Trigger.GlobalInput { 24 | [JsonProperty("Enabled")] 25 | private bool _enabled; 26 | 27 | public void OnUpdate(IEntity entity) { 28 | if (_enabled == false) { 29 | return; 30 | } 31 | 32 | if (entity.Current().TicksRemaining <= 0) { 33 | entity.Destroy(); 34 | } 35 | 36 | entity.Modify().TicksRemaining--; 37 | } 38 | 39 | public Type[] RequiredDataTypes { 40 | get { return new[] { typeof(TemporaryData) }; } 41 | } 42 | 43 | public Type[] InputTypes { 44 | get { return new[] { typeof(StopDestroyingInput), typeof(StartDestroyingInput) }; } 45 | } 46 | 47 | public void OnGlobalInput(IGameInput input) { 48 | if (input is StopDestroyingInput) { 49 | _enabled = false; 50 | } 51 | 52 | else if (input is StartDestroyingInput) { 53 | _enabled = true; 54 | } 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Game Sample 2 | 3 | The game sample demos nearly every important feature in Forge, including integration into both Unity and XNA! 4 | 5 | 6 | ## Running in Unity 7 | 8 | Sorry, the gifs are recorded at a low FPS. The games are both actually extremely smooth due to interpolation of position data (implemented in both Unity and XNA; see the `PositionRenderer`), despite the fact that they are both only updating 15 times a second. 9 | 10 | ![The game running in Unity](demo_unity.gif) 11 | 12 | ## Running in XNA 13 | 14 | Open up XNA.sln (if you have XNA installed) to run this demo locally. This gif may look a little funny because the paddles (the big rectangles) are actually being simulated as circles. 15 | 16 | ![The game running in XNA](demo_xna.gif) 17 | 18 | # Overview 19 | 20 | There are four folders. 21 | 22 | - `Assets`: A snapshot.json and templates.json file that will allow you to start up a simple game. These inject systems and data values into the engine. Feel free to look at the JSON files; they describe the serialization format of the game. Forge save games will be serialized into another snapshot.json. One way of viewing the `Unity` editor is a designer of save-game files, and when you start a new game you're really just loading a saved file. 23 | - `GameLogic`: Game logic that is independent from any framework. This builds directly on top of Forge APIs and implements the gameplay. 24 | - `Unity`: Integration into the Unity game engine. This requires the Forge Unity plug-in, which will be available soon. 25 | - `XNA`: Integration into XNA/MonoGame. This currently uses the unpolished XNA Forge bindings (they are found in the Forge directory under XNA). 26 | 27 | # Concepts 28 | 29 | `Forge` has a couple core concepts which allow the magic to happen. They are immutability, data, systems, and events. 30 | 31 | In regards to immutability, and speaking very roughly, there are 3 game states in memory at all times that you game can work with; the previous state, the current state, and the future state. The previous and current states are read-only, while the future state is write-only. Systems can be notified that a data instance has been modified and then it can query the previous state to see what it's old value was. This is one of the ways in which initialization/update order are solved. 32 | 33 | The game is composed of `IEntities` which contain `IData` instances (there are a variety of IData flavors, from ones which are Versioned (they support querying their previous states), to NonVersioned, which do not support querying, and Concurrent variants, which allow multiple writes in the same update). A data type can be something simple like your entities health or perhaps its position. Crucially, _data types contain no game logic_. 34 | 35 | Game logic goes into `ISystems`, which are executed concurrently on multiple threads. `ISystems` can listen for a number of `Triggers`, such as when an entity has been added. Further, they can express interest in only certain types of entities, for example, a `MovementSystem` can request only entities which have `MovementData` and `PositionData`. Some of the triggers are pretty nifty, such as `Trigger.Modified`, which allows a system to be notified whenever an entity that it contains is modified (for example, the entity's position has changed). The immutability system then allows the system to query the old position even while systems are processing the entities new position. 36 | 37 | `ISystems` do *not* deal with rendering any of the game state. Instead, the events API is used to notify the 3rd party renderer about how the simulation state has changed. Almost all of the busy work here is automated by the Unity/XNA integration packages. 38 | 39 | Additionally, most games need to create new entities at runtime; `ITemplates` are preconfigured entities which can be instantiated at runtime. They are similar in nature to Unity's prefabs. `ITemplates` are the only way to create new `IEntity` instances at runtime. 40 | 41 | ## License 42 | This sample is freely available under the MIT license. 43 | -------------------------------------------------------------------------------- /Unity/MapBoundsRenderer.cs: -------------------------------------------------------------------------------- 1 | using Forge.Entities; 2 | using Neon.Unity; 3 | using UnityEngine; 4 | 5 | namespace GameSample { 6 | /// 7 | /// Prepares the GameObject that contains the MapBoundsData so that the dimensions of the map 8 | /// are visible. 9 | /// 10 | [CustomDataRegistry(typeof(MapBoundsData))] 11 | public class MapBoundsRenderer : DataRenderer { 12 | protected override void OnInitialize() { 13 | MapBoundsData data = _entity.Current(); 14 | transform.localScale = new Vector3(data.Width * 2, 1, data.Height * 2); 15 | transform.position = new Vector3(0, -2, 0); 16 | } 17 | 18 | public override void UpdateVisualization(float percentage) { 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /Unity/MapBoundsRenderer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d7d32ba8faeab2649b0dda0abc81c6b9 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | -------------------------------------------------------------------------------- /Unity/PositionRenderer.cs: -------------------------------------------------------------------------------- 1 | using Forge.Entities; 2 | using Forge.Utilities; 3 | using Neon.Unity; 4 | using UnityEngine; 5 | 6 | namespace GameSample { 7 | /// 8 | /// Performs interpolation and rendering for PositionData. 9 | /// 10 | [CustomDataRegistry(typeof(PositionData))] 11 | public class PositionRenderer : DataRenderer { 12 | protected override void OnInitialize() { 13 | PositionData data = _entity.Current(); 14 | 15 | float radius = data.Position.Radius.AsFloat * 2; 16 | transform.localScale = new Vector3(radius, radius, radius); 17 | } 18 | 19 | public override void UpdateVisualization(float percentage) { 20 | Vector2r previous = ToVec(_entity.Previous().Position); 21 | Vector2r current = ToVec(_entity.Current().Position); 22 | 23 | float interpolatedX = Interpolate(previous.X.AsFloat, current.X.AsFloat, percentage); 24 | float interpolatedZ = Interpolate(previous.Z.AsFloat, current.Z.AsFloat, percentage); 25 | 26 | transform.position = new Vector3(interpolatedX, transform.position.y, interpolatedZ); 27 | } 28 | 29 | private static Vector2r ToVec(Bound bound) { 30 | return new Vector2r(bound.X, bound.Z); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /Unity/PositionRenderer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8bee4554ccea0604fa08f9cc0a43c720 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | -------------------------------------------------------------------------------- /Unity/Resources.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5d2637547650c394abbd7e1260481e83 3 | folderAsset: yes 4 | DefaultImporter: 5 | userData: 6 | -------------------------------------------------------------------------------- /Unity/Resources/BallPrefab.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1 &100000 4 | GameObject: 5 | m_ObjectHideFlags: 0 6 | m_PrefabParentObject: {fileID: 0} 7 | m_PrefabInternal: {fileID: 100100000} 8 | serializedVersion: 4 9 | m_Component: 10 | - 4: {fileID: 400000} 11 | - 23: {fileID: 2300000} 12 | - 33: {fileID: 3300000} 13 | m_Layer: 0 14 | m_Name: PongPrefab 15 | m_TagString: Untagged 16 | m_Icon: {fileID: 0} 17 | m_NavMeshLayer: 0 18 | m_StaticEditorFlags: 0 19 | m_IsActive: 1 20 | --- !u!4 &400000 21 | Transform: 22 | m_ObjectHideFlags: 1 23 | m_PrefabParentObject: {fileID: 0} 24 | m_PrefabInternal: {fileID: 100100000} 25 | m_GameObject: {fileID: 100000} 26 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 27 | m_LocalPosition: {x: 0, y: 0, z: 0} 28 | m_LocalScale: {x: .200000003, y: .200000003, z: .200000003} 29 | m_Children: [] 30 | m_Father: {fileID: 0} 31 | --- !u!23 &2300000 32 | Renderer: 33 | m_ObjectHideFlags: 1 34 | m_PrefabParentObject: {fileID: 0} 35 | m_PrefabInternal: {fileID: 100100000} 36 | m_GameObject: {fileID: 100000} 37 | m_Enabled: 1 38 | m_CastShadows: 1 39 | m_ReceiveShadows: 1 40 | m_LightmapIndex: 255 41 | m_LightmapTilingOffset: {x: 1, y: 1, z: 0, w: 0} 42 | m_Materials: 43 | - {fileID: 10302, guid: 0000000000000000f000000000000000, type: 0} 44 | m_SubsetIndices: 45 | m_StaticBatchRoot: {fileID: 0} 46 | m_UseLightProbes: 0 47 | m_LightProbeAnchor: {fileID: 0} 48 | m_ScaleInLightmap: 1 49 | m_SortingLayer: 0 50 | m_SortingOrder: 0 51 | m_SortingLayerID: 0 52 | --- !u!33 &3300000 53 | MeshFilter: 54 | m_ObjectHideFlags: 1 55 | m_PrefabParentObject: {fileID: 0} 56 | m_PrefabInternal: {fileID: 100100000} 57 | m_GameObject: {fileID: 100000} 58 | m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} 59 | --- !u!1001 &100100000 60 | Prefab: 61 | m_ObjectHideFlags: 1 62 | serializedVersion: 2 63 | m_Modification: 64 | m_TransformParent: {fileID: 0} 65 | m_Modifications: [] 66 | m_RemovedComponents: [] 67 | m_ParentPrefab: {fileID: 0} 68 | m_RootGameObject: {fileID: 100000} 69 | m_IsPrefabParent: 1 70 | m_IsExploded: 1 71 | -------------------------------------------------------------------------------- /Unity/Resources/BallPrefab.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0f381c4521a10964896d6f2495b36a75 3 | NativeFormatImporter: 4 | userData: 5 | -------------------------------------------------------------------------------- /Unity/Resources/PaddlePrefab.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1 &100000 4 | GameObject: 5 | m_ObjectHideFlags: 0 6 | m_PrefabParentObject: {fileID: 0} 7 | m_PrefabInternal: {fileID: 100100000} 8 | serializedVersion: 4 9 | m_Component: 10 | - 4: {fileID: 400000} 11 | - 23: {fileID: 2300000} 12 | - 33: {fileID: 3300000} 13 | m_Layer: 0 14 | m_Name: PaddlePrefab 15 | m_TagString: Untagged 16 | m_Icon: {fileID: 0} 17 | m_NavMeshLayer: 0 18 | m_StaticEditorFlags: 0 19 | m_IsActive: 1 20 | --- !u!4 &400000 21 | Transform: 22 | m_ObjectHideFlags: 1 23 | m_PrefabParentObject: {fileID: 0} 24 | m_PrefabInternal: {fileID: 100100000} 25 | m_GameObject: {fileID: 100000} 26 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 27 | m_LocalPosition: {x: 0, y: 0, z: 0} 28 | m_LocalScale: {x: 1, y: 1, z: 1} 29 | m_Children: [] 30 | m_Father: {fileID: 0} 31 | --- !u!23 &2300000 32 | Renderer: 33 | m_ObjectHideFlags: 1 34 | m_PrefabParentObject: {fileID: 0} 35 | m_PrefabInternal: {fileID: 100100000} 36 | m_GameObject: {fileID: 100000} 37 | m_Enabled: 1 38 | m_CastShadows: 1 39 | m_ReceiveShadows: 1 40 | m_LightmapIndex: 255 41 | m_LightmapTilingOffset: {x: 1, y: 1, z: 0, w: 0} 42 | m_Materials: 43 | - {fileID: 10302, guid: 0000000000000000f000000000000000, type: 0} 44 | m_SubsetIndices: 45 | m_StaticBatchRoot: {fileID: 0} 46 | m_UseLightProbes: 0 47 | m_LightProbeAnchor: {fileID: 0} 48 | m_ScaleInLightmap: 1 49 | m_SortingLayer: 0 50 | m_SortingOrder: 0 51 | m_SortingLayerID: 0 52 | --- !u!33 &3300000 53 | MeshFilter: 54 | m_ObjectHideFlags: 1 55 | m_PrefabParentObject: {fileID: 0} 56 | m_PrefabInternal: {fileID: 100100000} 57 | m_GameObject: {fileID: 100000} 58 | m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} 59 | --- !u!1001 &100100000 60 | Prefab: 61 | m_ObjectHideFlags: 1 62 | serializedVersion: 2 63 | m_Modification: 64 | m_TransformParent: {fileID: 0} 65 | m_Modifications: [] 66 | m_RemovedComponents: [] 67 | m_ParentPrefab: {fileID: 0} 68 | m_RootGameObject: {fileID: 100000} 69 | m_IsPrefabParent: 1 70 | m_IsExploded: 1 71 | -------------------------------------------------------------------------------- /Unity/Resources/PaddlePrefab.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 35bafa5bbca961f469f7b005c6a424cb 3 | NativeFormatImporter: 4 | userData: 5 | -------------------------------------------------------------------------------- /Unity/Resources/WorldPrefab.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1001 &100100000 4 | Prefab: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_Modification: 8 | m_TransformParent: {fileID: 0} 9 | m_Modifications: [] 10 | m_RemovedComponents: [] 11 | m_ParentPrefab: {fileID: 0} 12 | m_RootGameObject: {fileID: 0} 13 | m_IsPrefabParent: 1 14 | m_IsExploded: 1 15 | -------------------------------------------------------------------------------- /Unity/Resources/WorldPrefab.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 81bee1eb6026ccc4e999574713bee3f4 3 | NativeFormatImporter: 4 | userData: 5 | -------------------------------------------------------------------------------- /Unity/SystemProvider.cs: -------------------------------------------------------------------------------- 1 | using Forge.Entities; 2 | using Neon.Unity; 3 | using System.Collections.Generic; 4 | 5 | namespace GameSample { 6 | /// 7 | /// Provides the systems that should be used when generating the level. 8 | /// 9 | public class SystemProvider : ISystemProvider { 10 | public IEnumerable GetSystems() { 11 | PaddleCollectionSystem paddles = new PaddleCollectionSystem(); 12 | yield return paddles; 13 | yield return new BallCollisionSystem(paddles); 14 | yield return new MovementSystem(); 15 | yield return new BallSpawningSystem(); 16 | yield return new TemporarySystem(); 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /Unity/SystemProvider.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 08c0249d83e20294d8f907ccd070dd9a 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | -------------------------------------------------------------------------------- /XNA.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.21005.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XNA", "XNA\XNA\XNA.csproj", "{55DEEFF6-2A0C-4454-823D-F2BCD8644C5D}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XNAContent", "XNA\XNAContent\XNAContent.contentproj", "{97E2A491-3907-46F5-A4D0-66781E1A1AC7}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameLogic", "GameLogic\GameLogic.csproj", "{A0314C4B-6CBA-4D0F-B32F-24B450A0DDEF}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Debug|Mixed Platforms = Debug|Mixed Platforms 16 | Debug|x86 = Debug|x86 17 | Release|Any CPU = Release|Any CPU 18 | Release|Mixed Platforms = Release|Mixed Platforms 19 | Release|x86 = Release|x86 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {55DEEFF6-2A0C-4454-823D-F2BCD8644C5D}.Debug|Any CPU.ActiveCfg = Debug|x86 23 | {55DEEFF6-2A0C-4454-823D-F2BCD8644C5D}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 24 | {55DEEFF6-2A0C-4454-823D-F2BCD8644C5D}.Debug|Mixed Platforms.Build.0 = Debug|x86 25 | {55DEEFF6-2A0C-4454-823D-F2BCD8644C5D}.Debug|x86.ActiveCfg = Debug|x86 26 | {55DEEFF6-2A0C-4454-823D-F2BCD8644C5D}.Debug|x86.Build.0 = Debug|x86 27 | {55DEEFF6-2A0C-4454-823D-F2BCD8644C5D}.Release|Any CPU.ActiveCfg = Release|x86 28 | {55DEEFF6-2A0C-4454-823D-F2BCD8644C5D}.Release|Mixed Platforms.ActiveCfg = Release|x86 29 | {55DEEFF6-2A0C-4454-823D-F2BCD8644C5D}.Release|Mixed Platforms.Build.0 = Release|x86 30 | {55DEEFF6-2A0C-4454-823D-F2BCD8644C5D}.Release|x86.ActiveCfg = Release|x86 31 | {55DEEFF6-2A0C-4454-823D-F2BCD8644C5D}.Release|x86.Build.0 = Release|x86 32 | {97E2A491-3907-46F5-A4D0-66781E1A1AC7}.Debug|Any CPU.ActiveCfg = Debug|x86 33 | {97E2A491-3907-46F5-A4D0-66781E1A1AC7}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 34 | {97E2A491-3907-46F5-A4D0-66781E1A1AC7}.Debug|x86.ActiveCfg = Debug|x86 35 | {97E2A491-3907-46F5-A4D0-66781E1A1AC7}.Release|Any CPU.ActiveCfg = Release|x86 36 | {97E2A491-3907-46F5-A4D0-66781E1A1AC7}.Release|Mixed Platforms.ActiveCfg = Release|x86 37 | {97E2A491-3907-46F5-A4D0-66781E1A1AC7}.Release|x86.ActiveCfg = Release|x86 38 | {A0314C4B-6CBA-4D0F-B32F-24B450A0DDEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 39 | {A0314C4B-6CBA-4D0F-B32F-24B450A0DDEF}.Debug|Any CPU.Build.0 = Debug|Any CPU 40 | {A0314C4B-6CBA-4D0F-B32F-24B450A0DDEF}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU 41 | {A0314C4B-6CBA-4D0F-B32F-24B450A0DDEF}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU 42 | {A0314C4B-6CBA-4D0F-B32F-24B450A0DDEF}.Debug|x86.ActiveCfg = Debug|Any CPU 43 | {A0314C4B-6CBA-4D0F-B32F-24B450A0DDEF}.Release|Any CPU.ActiveCfg = Release|Any CPU 44 | {A0314C4B-6CBA-4D0F-B32F-24B450A0DDEF}.Release|Any CPU.Build.0 = Release|Any CPU 45 | {A0314C4B-6CBA-4D0F-B32F-24B450A0DDEF}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU 46 | {A0314C4B-6CBA-4D0F-B32F-24B450A0DDEF}.Release|Mixed Platforms.Build.0 = Release|Any CPU 47 | {A0314C4B-6CBA-4D0F-B32F-24B450A0DDEF}.Release|x86.ActiveCfg = Release|Any CPU 48 | EndGlobalSection 49 | GlobalSection(SolutionProperties) = preSolution 50 | HideSolutionNode = FALSE 51 | EndGlobalSection 52 | EndGlobal 53 | -------------------------------------------------------------------------------- /XNA/DLLs/Forge.AllLibraries.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacobdufault/forge-sample/6b18d3fb32a7a5c11df830f934995d0becdd45be/XNA/DLLs/Forge.AllLibraries.dll -------------------------------------------------------------------------------- /XNA/DLLs/Forge.AllLibraries.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacobdufault/forge-sample/6b18d3fb32a7a5c11df830f934995d0becdd45be/XNA/DLLs/Forge.AllLibraries.pdb -------------------------------------------------------------------------------- /XNA/DLLs/Forge.Collections.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacobdufault/forge-sample/6b18d3fb32a7a5c11df830f934995d0becdd45be/XNA/DLLs/Forge.Collections.dll -------------------------------------------------------------------------------- /XNA/DLLs/Forge.Collections.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacobdufault/forge-sample/6b18d3fb32a7a5c11df830f934995d0becdd45be/XNA/DLLs/Forge.Collections.pdb -------------------------------------------------------------------------------- /XNA/DLLs/Forge.Collections.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Forge.Collections 5 | 6 | 7 | 8 | 9 | An unordered collection of items. 10 | 11 | 12 | 13 | 14 | Copies from the given bag into this one. 15 | 16 | The bag to copy from 17 | 18 | 19 | 20 | Creates a duplicate of this bag that has a different backing array. 21 | 22 | 23 | 24 | 25 | Returns the index of the given item in the bag, or -1 if it is not found. 26 | 27 | 28 | 29 | 30 | Removes the item at given index from the bag in O(1) time. This operation does not 31 | maintain the order of elements inside of the bag! 32 | 33 | 34 | 35 | 36 | Clears all stored items from this instance. 37 | 38 | 39 | 40 | 41 | Remove the item from the bag. This is O(n) and has to scan the bag to find the item. 42 | 43 | True if the item was found and removed, false otherwise. 44 | 45 | 46 | 47 | Returns true if the Bag contains an instance of the given item. 48 | 49 | The item to search for. 50 | True if it is in the bag, false otherwise. 51 | 52 | 53 | 54 | A set of items where only one is active and used. 55 | 56 | The type of item stored. 57 | 58 | 59 | 60 | The stored items 61 | 62 | 63 | 64 | 65 | The _currentKeyboardState item that we are accessing 66 | 67 | 68 | 69 | 70 | Initializes a new instance of the class. 71 | 72 | The number of instances to allocate 73 | 74 | 75 | 76 | Initializes a new instance of the class. 77 | 78 | The instances to swap between. 79 | 80 | 81 | 82 | Swaps out the _currentKeyboardState item for the next one. 83 | 84 | The item that was deactivated 85 | 86 | 87 | 88 | Gets the currently active item. 89 | 90 | 91 | 92 | 93 | Returns an item in the rotation queue that is relative to the current item by the given 94 | offset. 95 | 96 | How far away from the current item 97 | 98 | 99 | 100 | 101 | Provides a queue where pushing is assumed to be done concurrently, but reading is done in a 102 | single-thread where no writing is done. 103 | 104 | The type of object stored. 105 | 106 | 107 | 108 | All thread-local bags; this is used when iterating over the entire contents of the bag. 109 | 110 | 111 | 112 | 113 | The thread-local bag that is used for appending items. 114 | 115 | 116 | 117 | 118 | Used to set the value of CanWrite. 119 | 120 | 121 | 122 | 123 | Construct a new concurrent writer bag. 124 | 125 | 126 | 127 | 128 | Adds the item in the collection. 129 | 130 | 131 | This is a thread-safe function. 132 | 133 | The item to enqueue 134 | 135 | 136 | 137 | Returns all items inside of the bag as a list. This method is not thread safe. This 138 | method does *not* clear the collection. 139 | 140 | 141 | 142 | 143 | Calls the iterator over every item in the bag and then clears the bags that were 144 | iterated. 145 | 146 | 147 | This method is **NOT** thread-safe; do NOT call Add while iterating the items. 148 | 149 | The function to invoke on the items. 150 | 151 | 152 | 153 | Gets/sets if writing is enabled or disabled. Thread-safe. Provides debug diagnostics 154 | only and is not critical for correct behavior. This is set to false by the methods which 155 | read collections as they are doing their reading. 156 | 157 | 158 | 159 | 160 | Interface for objects which are monitoring a specific region. 161 | 162 | 163 | 164 | 165 | Called when the given item has entered the region. 166 | 167 | 168 | 169 | 170 | Called when an item has left the region. 171 | 172 | 173 | 174 | 175 | Returns true if this rect intersects with the parameter rect. 176 | 177 | 178 | 179 | 180 | Returns true if the given point is contained with this rect. 181 | 182 | 183 | 184 | 185 | Returns true if this rect fully contains the parameter rect. 186 | 187 | 188 | 189 | 190 | Returns true if this rect is either intersecting with or fully contains the parameter 191 | rect. 192 | 193 | 194 | 195 | 196 | The items that the node contains 197 | 198 | 199 | 200 | 201 | The monitors that watch for adds/removes in this node 202 | 203 | 204 | 205 | 206 | The width/height of each chunk 207 | 208 | 209 | 210 | 211 | All of the chunks 212 | 213 | 214 | 215 | 216 | Stores a list of items where the are gaps between items; not every index in the array 217 | contains an element. 218 | 219 | 220 | 221 | 222 | The internal array of elements inside of the array. 223 | 224 | 225 | 226 | 227 | Creates a new SparseArray with the default capacity. 228 | 229 | 230 | 231 | 232 | Creates a new SparseArray with the given capacity. 233 | 234 | The capacity to initialize with 235 | 236 | 237 | 238 | Creates a new sparse array from the given enumerator. 239 | 240 | The items to allocate the array from. 241 | 242 | 243 | 244 | Clears out all elements inside of the SparseArray. 245 | 246 | 247 | 248 | 249 | Removes the element at the given index. 250 | 251 | The index of the element to remove 252 | If an element was removed 253 | 254 | 255 | 256 | Checks to see if there is an element at the given index. 257 | 258 | The index to check. 259 | True if there is a contained element, false otherwise. 260 | 261 | 262 | 263 | Gets the value associated with the specified key. 264 | 265 | The key whose value to get. 266 | When this method returns, the value associated with the specified 267 | key, if the key is found; otherwise, the default value for the type of the 268 | parameter. This parameter is passed uninitialized. 269 | true if the object that implements 270 | contains an element with the 271 | specified key; otherwise, false. 272 | 273 | 274 | 275 | Ensures that index is a valid index into the Elements array. 276 | 277 | The index to verify. 278 | 279 | 280 | 281 | Returns an enumerator that iterates through the collection. 282 | 283 | 284 | 285 | 286 | Gets or sets the element at the given index. 287 | 288 | The index to set 289 | If getting, then the value at the given index. 290 | 291 | 292 | 293 | Contains two items which can be swapped between a Previous and a Current state. 294 | 295 | The type of item stored 296 | 297 | 298 | 299 | The first item 300 | 301 | 302 | 303 | 304 | The second item 305 | 306 | 307 | 308 | 309 | The current item 310 | 311 | 312 | 313 | 314 | Initializes a new instance of the class. 315 | 316 | The first item. 317 | The second item. 318 | 319 | 320 | 321 | Swap the Current and Previous items. 322 | 323 | 324 | 325 | 326 | The current item. 327 | 328 | 329 | 330 | 331 | The previous item. 332 | 333 | 334 | 335 | 336 | A list of items that is unordered. This provides O(1) addition, O(1) removal, and O(1) 337 | iteration. However, having all of these nice properties requires some metadata to be stored 338 | on each item, which means that Add takes a parameter of metadata for the stored item. Same 339 | with remove. 340 | 341 | The type of item to store. 342 | 343 | 344 | 345 | The stored list of items. 346 | 347 | 348 | 349 | 350 | Creates a new UnorderedList with the given capacity. 351 | 352 | The capacity to give to the list 353 | 354 | 355 | 356 | Checks to see if the given item is contained in the UnorderedList. This is O(1). 357 | 358 | The item to check 359 | The item's metadata 360 | True if the item is contained, false otherwise 361 | 362 | 363 | 364 | Removes the stored item. 365 | 366 | True if the item was removed, false otherwise 367 | 368 | 369 | 370 | Adds an item to the list. The location of the item in the list is unspecified. 371 | 372 | 373 | 374 | 375 | The number of stored objects in Items. 376 | 377 | 378 | 379 | 380 | Set or get the item at the specified index. 381 | 382 | 383 | 384 | 385 | Data stored inside of the UnorderedList. 386 | 387 | 388 | 389 | 390 | -------------------------------------------------------------------------------- /XNA/DLLs/Forge.Entities.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacobdufault/forge-sample/6b18d3fb32a7a5c11df830f934995d0becdd45be/XNA/DLLs/Forge.Entities.dll -------------------------------------------------------------------------------- /XNA/DLLs/Forge.Entities.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacobdufault/forge-sample/6b18d3fb32a7a5c11df830f934995d0becdd45be/XNA/DLLs/Forge.Entities.pdb -------------------------------------------------------------------------------- /XNA/DLLs/Forge.Extensions.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacobdufault/forge-sample/6b18d3fb32a7a5c11df830f934995d0becdd45be/XNA/DLLs/Forge.Extensions.dll -------------------------------------------------------------------------------- /XNA/DLLs/Forge.Extensions.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacobdufault/forge-sample/6b18d3fb32a7a5c11df830f934995d0becdd45be/XNA/DLLs/Forge.Extensions.pdb -------------------------------------------------------------------------------- /XNA/DLLs/Forge.Extensions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Forge.Extensions 5 | 6 | 7 | 8 | 9 | Common extensions of types which implement the IList[T] interface. 10 | 11 | 12 | 13 | 14 | Shuffle the specified list. 15 | 16 | The list to shuffle. 17 | 18 | 19 | 20 | Checks if the given list is empty. 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /XNA/DLLs/Forge.Networking.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacobdufault/forge-sample/6b18d3fb32a7a5c11df830f934995d0becdd45be/XNA/DLLs/Forge.Networking.dll -------------------------------------------------------------------------------- /XNA/DLLs/Forge.Networking.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacobdufault/forge-sample/6b18d3fb32a7a5c11df830f934995d0becdd45be/XNA/DLLs/Forge.Networking.pdb -------------------------------------------------------------------------------- /XNA/DLLs/Forge.Networking.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Forge.Networking 5 | 6 | 7 | 8 | 9 | Supports turn-based games where there are a high number of game turns per second (>5) that 10 | are automatically ended. 11 | 12 | 13 | 14 | 15 | How much time has elapsed since the last time we popped an update? 16 | 17 | 18 | 19 | 20 | Accumulator used for clients when they are updating (so if we receive two updates really 21 | quickly, we don't want to actually execute those updates immediately; we instead want to 22 | wait until we can update them). 23 | 24 | 25 | 26 | 27 | How much time has elapsed since the last time we updated? 28 | 29 | 30 | 31 | 32 | How much time should elapse between updates for us to meet our target updates/second? 33 | 34 | 35 | 36 | 37 | Create a new AutomaticTurnGame. 38 | 39 | The networking context. 40 | The number of updates/turns that will occur every 41 | second. 42 | 43 | 44 | 45 | Clean up the game from the NetworkContext. 46 | 47 | 48 | 49 | 50 | Send the given set of game commands to the server. It will be processed at a later point 51 | by every client. 52 | 53 | The commands to send. 54 | 55 | 56 | 57 | Update the game. Potentially dispatch game commands for execution by all computers if 58 | enough time has elapsed. 59 | 60 | The amount of time that has elapsed since the last call to 61 | Update. 62 | 63 | 64 | 65 | The number of updates we second the game should run at. 66 | 67 | 68 | 69 | 70 | Configure the lag between giving input and actually receiving that input. A lower value 71 | will cause stuttering on slow networks, but user responsiveness will be higher. A higher 72 | value will cause less stuttering, but lower user responsiveness. 73 | 74 | 75 | 76 | 77 | Returns how far along we are until the next update. 78 | 79 | 80 | 81 | 82 | Client code that is executed upon the receipt of a network message. 83 | 84 | 85 | 86 | 87 | Handle a network message. 88 | 89 | The player that sent the message. 90 | The message itself (an instance of a type from 91 | HandledTypes) . 92 | 93 | 94 | 95 | The types that this message handler can process. 96 | 97 | 98 | 99 | 100 | Sends commands out for the network turn. 101 | 102 | 103 | 104 | 105 | If the local computer issues a command turn N, then the command will actually be 106 | executed on turn (N+TurnDelay). This parameter heavily impacts responsiveness. This 107 | value is only used on the server but can be changed by any computer on the network. A 108 | low value will mean that user input will get processed more quickly, but the game is 109 | more likely to stutter from a missed update. 110 | 111 | 112 | 113 | 114 | Helper class that simplifies the management of delayed messages. 115 | 116 | The type of message to store. 117 | 118 | 119 | 120 | Construct a new circular queue with the given capacity. 121 | 122 | How big the queue should be. 123 | 124 | 125 | 126 | Read only value to get the current turn delay that the server is using. 127 | 128 | 129 | 130 | 131 | Does the client has an update ready to be executed? 132 | 133 | 134 | 135 | 136 | Does the client have a large backlog of updates that are waiting to be executed? 137 | 138 | 139 | 140 | 141 | A message transmitted over the network. Network messages are always transmitted in order and 142 | reliably. 143 | 144 | 145 | 146 | 147 | Every command (from every computer) that should be issued. 148 | 149 | 150 | 151 | 152 | The update the commands should be issued on. 153 | 154 | 155 | 156 | 157 | Message that goes from clients to the server specifying commands that have been issued. 158 | 159 | 160 | 161 | 162 | The requested commands to issue. 163 | 164 | 165 | 166 | 167 | The update number that the command was submitted on. 168 | 169 | 170 | 171 | 172 | Message that only the server processes to adjust the turn delay. 173 | 174 | 175 | 176 | 177 | The new delay for the game. 178 | 179 | 180 | 181 | 182 | An IGameCommand is some user input that modifies game state during a turn. This interface is 183 | not implemented internally; instead it gives some type safety for the API (otherwise only 184 | object could be used as parameter types). 185 | 186 | 187 | 188 | 189 | Processes ChatNetworkMessages and adds them to a displayable message list depending on if 190 | the local player should be allowed to see the message. 191 | 192 | 193 | 194 | 195 | The local player. 196 | 197 | 198 | 199 | 200 | All received chat messages. 201 | 202 | 203 | 204 | 205 | All chat messages that should be displayed. 206 | 207 | 208 | 209 | 210 | Returns true if this computer should display the message for the given set of message 211 | receivers. 212 | 213 | 214 | 215 | 216 | A network message that is used when sending chat messages. 217 | 218 | 219 | 220 | 221 | The content of the chat message. 222 | 223 | 224 | 225 | 226 | The player that sent the message. 227 | 228 | 229 | 230 | 231 | Specifies what players should see the given message. This will be empty if every player 232 | should see the message, and non-empty if not everyone should see it. 233 | 234 | 235 | 236 | 237 | A chat message that has been received. 238 | 239 | 240 | 241 | 242 | The time that the message was received. 243 | 244 | 245 | 246 | 247 | The player that sent the message. 248 | 249 | 250 | 251 | 252 | The content of the message. 253 | 254 | 255 | 256 | 257 | This class contains Lidgren.Network configuration settings that are used when creating 258 | NetPeer (typically either a NetServer or a NetClient type) instances. 259 | 260 | 261 | 262 | 263 | The port that is used when hosting. 264 | 265 | 266 | 267 | 268 | Global application name that is used to distinguish Forge. 269 | 270 | 271 | 272 | 273 | Contains the core APIS for sending and receiving chat messages. 274 | 275 | 276 | 277 | 278 | The networking context to use for retrieving our local player and for adding our 279 | ChatNetworkMessage handler. 280 | 281 | 282 | 283 | 284 | The ChatMessageHandler we use to get chat messages from. 285 | 286 | 287 | 288 | 289 | Construct a new ChatManager using the given networking context and the given object for 290 | mapping network players to a directed player relation graph. 291 | 292 | The networking context. 293 | 294 | 295 | 296 | Cleans up the ChatManager from the NetworkContext it was constructed with. 297 | 298 | 299 | 300 | 301 | Send a chat message to all players that have the given relationship with the sending 302 | player. 303 | 304 | The message to send. 305 | The players that should receive the message. 306 | 307 | 308 | 309 | Sends a chat message to every player. 310 | 311 | The message to send. 312 | 313 | 314 | 315 | All of the chat messages that have been received that should be displayed. 316 | 317 | 318 | 319 | 320 | All received chat messages. 321 | 322 | 323 | 324 | 325 | The hosting player. 326 | 327 | 328 | 329 | 330 | The title of the game. 331 | 332 | 333 | 334 | 335 | Contains information about a running server. 336 | 337 | 338 | 339 | 340 | The player that is hosting the server. 341 | 342 | 343 | 344 | 345 | The title of the server. 346 | 347 | 348 | 349 | 350 | The IP that can be used to connect to the server. 351 | 352 | 353 | 354 | 355 | This class makes it simple to automatically discover servers that are running on the local 356 | network. 357 | 358 | 359 | 360 | 361 | The NetClient we use to run the discovery service. 362 | 363 | 364 | 365 | 366 | The servers that we have discovered. 367 | 368 | 369 | 370 | 371 | Attempts to discover all running servers on the local network. DiscoveredLocalServers 372 | will contain the result; it may change over time. 373 | 374 | 375 | 376 | 377 | Clears out the list of discovered servers. 378 | 379 | 380 | 381 | 382 | Returns a list containing all servers that have been discovered thus far. 383 | 384 | 385 | 386 | 387 | Object that monitors the connection and disconnection of other computers. 388 | 389 | 390 | 391 | 392 | The given player has connected. 393 | 394 | 395 | 396 | 397 | The given player has disconnected. 398 | 399 | 400 | 401 | 402 | Common code for LobbyMember and LobbyHost. 403 | 404 | 405 | 406 | 407 | The network context that we use for core networking operations. 408 | 409 | 410 | 411 | 412 | Message handler used to determine if we've received a LobbyLaunchedNetworkMessage. 413 | 414 | 415 | 416 | 417 | Get all members of the lobby, including the host. 418 | 419 | 420 | 421 | 422 | Is the given player the host of the lobby? 423 | 424 | 425 | 426 | 427 | Dispose the lobby. 428 | 429 | 430 | 431 | 432 | Returns true if the lobby has launched. Make sure to dispose of the lobby. 433 | 434 | True if the lobby has launched, false if it hasn't. 435 | 436 | 437 | 438 | Try to launch the lobby. All players have to be ready in order to launch. 439 | 440 | 441 | You can also use HasLaunched to determine if the lobby has started. However, HasLaunched 442 | will not actually start the game and will only return the lobby launch status. 443 | 444 | True if the launch attempt was successful, false otherwise. 445 | 446 | 447 | 448 | Host a new lobby. 449 | 450 | The player that is creating the server. 451 | The settings to use for the lobby. 452 | A lobby host if successful. 453 | 454 | 455 | 456 | Change the map. 457 | 458 | 459 | 460 | 461 | Kick the given lobby member from the lobby. 462 | 463 | The member to kick. 464 | 465 | 466 | 467 | Return players that are not ready. 468 | 469 | 470 | 471 | 472 | Settings used for creating a lobby. 473 | 474 | 475 | 476 | 477 | The password required for entering the lobby. Use an empty string for "no" password. 478 | 479 | 480 | 481 | 482 | The serialized map that the lobby is hosting, ie, the data that lobby members will 483 | download. 484 | 485 | 486 | 487 | 488 | Map manager used to get hashes for serialized maps. 489 | 490 | 491 | 492 | 493 | The sending client is ready to launch the game. 494 | 495 | 496 | 497 | 498 | The sending client is not ready to launch the game. 499 | 500 | 501 | 502 | 503 | Handles network messages for determining if every player is ready to launch the game. 504 | 505 | 506 | 507 | 508 | Players that are ready to launch. 509 | 510 | 511 | 512 | 513 | Players that are not ready to launch. 514 | 515 | 516 | 517 | 518 | The networking context. 519 | 520 | 521 | 522 | 523 | Returns true if every player is ready. 524 | 525 | 526 | 527 | 528 | Network message sent when the lobby has been launched. 529 | 530 | 531 | 532 | 533 | Network message sent by the lobby server to verify that all clients have the given map. 534 | 535 | 536 | 537 | 538 | The hash code for the map, used to check to see if we need to download it. 539 | 540 | 541 | 542 | 543 | Network message sent by a lobby client to request a map download. 544 | 545 | 546 | 547 | 548 | Network message sent to lobby clients by the lobby server after the lobby server has 549 | received a LobbyMapDownloadedRequestedNetworkMessage. 550 | 551 | 552 | 553 | 554 | Processes map download request messages and also sends map verification messages to new 555 | clients. Supports changing the current map (which causes a rebroadcast for map 556 | verification) . 557 | 558 | 559 | 560 | 561 | Interface used to check if a map exists and optionally save a downloaded map if one does 562 | not. 563 | 564 | 565 | 566 | 567 | Map download handler for the lobby client. Receives map verification messages and map 568 | download messages. If the verification message fails, then a map download request message is 569 | sent to the server. 570 | 571 | 572 | 573 | 574 | A member of a lobby. 575 | 576 | 577 | 578 | 579 | Try to join the lobby at the given IP end point as the given player. 580 | 581 | The IP address that the lobby server is running at. 582 | The map manager that will be used to check to see if we have a 583 | map and to save a downloaded map. 584 | This player that will be used to uniquely identify 585 | ourselves. 586 | The password that the lobby host has set. 587 | 588 | 589 | 590 | The given player has joined the network. 591 | 592 | 593 | 594 | 595 | The given player has left the network. 596 | 597 | 598 | 599 | 600 | Specifies which computers an INetworkMessage should be delivered to. 601 | 602 | 603 | 604 | 605 | All computers process the message. Each computer will processes each message in the same 606 | order. That is, computer A sends message A, and computer B sends message B, both 607 | computers will process both messages in the same order (whether it be A then B or B then 608 | A is undefined, but both computers will select the same (a,b) or (b,a) group). 609 | 610 | 611 | In regards to implementation details, this message type requires that the message be 612 | sent to the server before any computer can process it (for ordering purposes). The 613 | server then rebroadcasts the message to every computer for execution. This is not 614 | particularly lightweight, but it does simplify networking logic. 615 | 616 | 617 | 618 | 619 | The message should be processed by *only* the server. This message type can only be sent 620 | by any computer in the network, whether it be a client or a server. 621 | 622 | 623 | 624 | 625 | The message should be processed by all clients but *not* the server. This message type 626 | can only be sent by the server. 627 | 628 | 629 | 630 | 631 | A network player is an abstraction over a network connection. 632 | 633 | 634 | 635 | 636 | The name that the player gave themselves. 637 | 638 | 639 | 640 | 641 | The GUID that uniquely identifies this player. This GUID can be per-session and does not 642 | need to be permanent. 643 | 644 | 645 | 646 | 647 | Determines whether the specified see cref="System.Object" }, is equal to this instance. 648 | 649 | The to compare with this 650 | instance. 651 | true if the specified is equal to this 652 | instance; otherwise, /c>. 653 | 654 | 655 | 656 | Returns a hash code for this instance. 657 | 658 | A hash code for this instance, suitable for use in hashing algorithms and data 659 | structures like a hash table. 660 | 661 | 662 | 663 | Base type that all INetworkMessageHandlers should extend from (for a simplified API). 664 | 665 | The type of message that this handler handles. 666 | 667 | 668 | 669 | Holds important information about the current network connection and additionally about 670 | INetworkMessage listeners. 671 | 672 | 673 | 674 | 675 | Enumerable container that merely contains LocalPlayer. 676 | 677 | 678 | 679 | 680 | If the context is a client, then this is the Lidgren.Network client object. 681 | 682 | 683 | 684 | 685 | If we're a server, then this is the password for the server. 686 | 687 | 688 | 689 | 690 | If we're a server, this is the list of objects which want to know when a client has 691 | connected or disconnected. 692 | 693 | 694 | 695 | 696 | Networking dispatcher that is used for sending messages. 697 | 698 | 699 | 700 | 701 | Private constructor for NetworkContext; NetworkContexts can only be created using the 702 | static helper methods. 703 | 704 | The local player 705 | 706 | 707 | 708 | Creates a new server. 709 | 710 | The player that is running this server. 711 | The password that clients have to have to connect. 712 | A network context for the created server. 713 | 714 | 715 | 716 | Tries to fetch all possible IPs that might be possible for clients to connect to the 717 | server with. This operation throws an exception if the context is not a server. 718 | 719 | 720 | 721 | 722 | Creates a new client connection connected to the given IP end point. This method blocks 723 | until we know if the client has either connected or disconnected. 724 | 725 | The IP to connect to. 726 | This computer's player. 727 | The password that the server is expecting. 728 | 729 | 730 | 731 | 732 | Returns true if the given Player is the server. 733 | 734 | The player to check. 735 | True if the player is the server, otherwise false. 736 | 737 | 738 | 739 | Kicks the given player. This function is only operable if the context is a server 740 | (otherwise an exception is thrown). 741 | 742 | The player to kick. 743 | 744 | 745 | 746 | Adds the given message handler to the network context. 747 | 748 | The network message handler to add. 749 | 750 | 751 | 752 | Removes the given message handler from the context. If the dispatcher was not previously 753 | contained in the context, then an exception is thrown. 754 | 755 | The network message handler to remove. 756 | 757 | 758 | 759 | Add a new connection monitor listener. This allows for client code to be notified when 760 | another player connects or disconnects from the network. 761 | 762 | The connection monitor to add. 763 | 764 | 765 | 766 | Remove a previously added connection monitor. If the monitor was not found when removing 767 | it, an exception is thrown. 768 | 769 | The connection monitor to remove. 770 | 771 | 772 | 773 | Update the network context; ie, invoke handlers for received network messages if we're a 774 | client or broadcast out received messages if we're a server. 775 | 776 | 777 | 778 | 779 | Send the given message to the given recipients. 780 | 781 | The computers that should receive the message. 782 | The message to send. 783 | 784 | 785 | 786 | Send the given message to only the specified recipient. 787 | 788 | The player that should receive the message. 789 | Who to send the message to. 790 | 791 | 792 | 793 | Creates an outgoing message with the given sender, message, broadcast state. 794 | 795 | The player who is sending this message. 796 | The message to send. 797 | If the server receives this message, should it broadcast it out 798 | to all clients? 799 | 800 | 801 | 802 | Helper method to lookup the network connection based on the given network player. 803 | 804 | 805 | 806 | 807 | If the context is a server, then this is the Lidgren.Network server object. 808 | 809 | 810 | 811 | 812 | Returns the internal NetPeer instance that represents the core connection. 813 | 814 | 815 | 816 | 817 | Returns true if this NetworkConext is acting as a server. 818 | 819 | 820 | 821 | 822 | Returns true if this NetworkContext is acting as a client. 823 | 824 | 825 | 826 | 827 | The local player. 828 | 829 | 830 | 831 | 832 | Message format for NetIncomingMessageType.Data 833 | 834 | 835 | 836 | 837 | Hail message format used when connecting to a server. 838 | 839 | 840 | 841 | 842 | The player connecting. 843 | 844 | 845 | 846 | 847 | The password to use when connecting. 848 | 849 | 850 | 851 | 852 | This class serves as a registry for INetworkMessageHandlers. It supports efficient lookup of 853 | message type to message handler responders. 854 | 855 | 856 | In the overall context of Forge.Network, this class serves a critical function as the core 857 | mechanism for the event-based message processing loop. The NetworkContext is the primary 858 | user of this type. NetworkContext receives and sends out INetworkMessages; when it receives 859 | an INetworkMessage, it checks its NetworkMessageDispatcher to see if there are any handlers 860 | that need to be invoked. 861 | 862 | 863 | 864 | 865 | The message handlers; the key is the type of message, and the value is the list of 866 | handlers that can respond to that message type. 867 | 868 | 869 | 870 | 871 | Create a new NetworkMessageDispatcher that has no registered message handlers. 872 | 873 | 874 | 875 | 876 | Helper method to get all message handlers that can respond to the given message type. 877 | 878 | 879 | 880 | 881 | Adds a message handler. 882 | 883 | The handler to add. 884 | 885 | 886 | 887 | Remove the message handler. Throws an exception if the handler was not previously added. 888 | 889 | The handler to remove. 890 | 891 | 892 | 893 | Invoke all registered INetworkMessageHandlers for the given message and sender. 894 | 895 | 896 | 897 | 898 | API for interacting with the pausing subsystem. 899 | 900 | 901 | 902 | 903 | Network context that we use to transmit pause messages. 904 | 905 | 906 | 907 | 908 | Message handler that processes the pause messages. 909 | 910 | 911 | 912 | 913 | Create a new PauseManager instance. 914 | 915 | The networking context to use. 916 | 917 | 918 | 919 | Cleans up resources that the PauseManager uses in the NetworkContext. 920 | 921 | 922 | 923 | 924 | Returns the current pause status for the game. Setting this value emits a network 925 | message that changes the pause status to the given value for all computers in the 926 | network. 927 | 928 | 929 | 930 | 931 | If the game is paused, then this returns who paused the game. If the game is not paused, 932 | then this returns nothing. 933 | 934 | 935 | 936 | 937 | Updates the pause status when SetPauseStatusNetworkMessages are received. 938 | 939 | 940 | 941 | 942 | Getter/setter for if the game is paused. 943 | 944 | 945 | 946 | 947 | Returns who paused the game if it is paused. 948 | 949 | 950 | 951 | 952 | Network message to set the current pause status for the game. 953 | 954 | 955 | 956 | 957 | -------------------------------------------------------------------------------- /XNA/DLLs/Forge.Utilities.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacobdufault/forge-sample/6b18d3fb32a7a5c11df830f934995d0becdd45be/XNA/DLLs/Forge.Utilities.dll -------------------------------------------------------------------------------- /XNA/DLLs/Forge.Utilities.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacobdufault/forge-sample/6b18d3fb32a7a5c11df830f934995d0becdd45be/XNA/DLLs/Forge.Utilities.pdb -------------------------------------------------------------------------------- /XNA/DLLs/Forge.Utilities.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Forge.Utilities 5 | 6 | 7 | 8 | 9 | Thread-safe activation trigger that only activates once. 10 | 11 | 12 | In a sense, this is equivalent to extending Interlocked to operate on booleans. 13 | 14 | 15 | 16 | 17 | An activated activation state 18 | 19 | 20 | 21 | 22 | A deactivated activation state. 23 | 24 | 25 | 26 | 27 | Have we been activated? 28 | 29 | 30 | 31 | 32 | Initializes a new instance of the AtomicActivation class in an unactivated state. 33 | 34 | 35 | 36 | 37 | Resets the activation state, so that Activate() will return true on then next call. 38 | 39 | 40 | 41 | 42 | Returns true if the activation state was previously unactivated. 43 | 44 | True if the activation activated for this call 45 | 46 | 47 | 48 | Returns true if the current activation state is activated. 49 | 50 | 51 | 52 | 53 | Returns true if this bound is either intersecting or colliding with the other bound. 54 | 55 | 56 | 57 | 58 | Returns true if the given point is contained within this bound. 59 | 60 | 61 | 62 | 63 | Returns true if the given point is contained within this bound. 64 | 65 | 66 | 67 | 68 | Provides methods which format a string without garbage allocation. 69 | 70 | 71 | The format strings only go from {0} to {9} and do not support any customizations. 72 | Backslashes are also not supported. 73 | 74 | 75 | 76 | 77 | Returns a random long from min (inclusive) to max (exclusive) 78 | 79 | The given random instance 80 | The inclusive minimum bound 81 | The exclusive maximum bound. Must be greater than min 82 | 83 | 84 | 85 | Returns a random long from 0 (inclusive) to max (exclusive) 86 | 87 | The given random instance 88 | The exclusive maximum bound. Must be greater than 0 89 | 90 | 91 | 92 | Returns a random long over all possible values of long (except long.MaxValue, similar to 93 | random.Next()) 94 | 95 | The given random instance 96 | 97 | 98 | 99 | Log messages. 100 | 101 | 102 | 103 | 104 | Get a logger for the given type. 105 | 106 | 107 | 108 | 109 | Log messages. 110 | 111 | The type that is sending the log message 112 | 113 | 114 | 115 | The log4net logger used to log messages. 116 | 117 | 118 | 119 | 120 | Helper for Maybe[T] by providing local type inference at Just and Empty call sites. 121 | 122 | 123 | 124 | 125 | Returns a new Maybe instance containing the given value. 126 | 127 | 128 | 129 | 130 | Returns a maybe instance that is empty. 131 | 132 | The type of the maybe instance. 133 | An empty Maybe[T] instance. 134 | 135 | 136 | 137 | Some common extensions for the maybe class. 138 | 139 | 140 | 141 | 142 | Lifts a maybe into another maybe using the given lifting function. If the given maybe is 143 | empty, then an empty maybe is returned. 144 | 145 | The type of the original maybe The 146 | type of the new maybe 147 | The maybe to transform 148 | The lifting function that will transform the maybe 149 | A new maybe created by the lifting function 150 | 151 | 152 | 153 | Lifts a maybe into another maybe using the given lifting function. If the given maybe is 154 | empty, then an empty maybe is returned.The returned maybe is never empty. 155 | 156 | The type of the original maybe The 157 | type of the new maybe 158 | The maybe to transform 159 | The lifting function that will transform the maybe 160 | A new maybe created by the lifting function 161 | 162 | 163 | 164 | C# has a limitation where non-reference generic types cannot be contravariant (the Maybe 165 | generic type should be contravariant). This function eases that limitation by providing 166 | automatic casting to a higher Maybe type. 167 | 168 | 169 | 170 | 171 | Maybe wraps another type and is used to signal to other code that it might not return a 172 | result. It performs the same function as null, but in a more type-safe manner that provides 173 | more clarity into the contract that function exhibits. 174 | 175 | The type of value stored in the Maybe instance 176 | 177 | 178 | 179 | The stored value in the maybe instance. Only contains interesting data if _hasValue is 180 | true (otherwise the data is garbage). 181 | 182 | 183 | 184 | 185 | True if the maybe instance is currently holding a value. 186 | 187 | 188 | 189 | 190 | Creates a new Maybe container that holds the given value. 191 | 192 | 193 | 194 | 195 | Internal constructor used to construct the maybe. Used primarily in construction of the 196 | Empty element. 197 | 198 | 199 | 200 | 201 | Default empty instance. 202 | 203 | 204 | 205 | 206 | Gets the underlying value. 207 | 208 | 209 | If IsEmpty returns true, then this method will throw an InvalidOperationException. 210 | 211 | 212 | 213 | 214 | Returns true if this Maybe has a value stored in it. 215 | 216 | 217 | 218 | 219 | Returns true if this Maybe is empty, it, it does not have a value stored in it. 220 | 221 | 222 | 223 | 224 | An object that can be used as a value in a GeneralStreamingContext instance. 225 | 226 | 227 | 228 | 229 | Object that implements the streaming context that all converters which expect a streaming 230 | context expect the streaming context to be a type of. 231 | 232 | 233 | 234 | 235 | The context objects 236 | 237 | 238 | 239 | 240 | Creates a new GeneralStreamingContext with the given initial objects. 241 | 242 | 243 | 244 | 245 | Returns the context object associated with the type T. 246 | 247 | 248 | 249 | 250 | Sets the context object of type T to an instance of new T(). 251 | 252 | 253 | 254 | 255 | Sets the context object of type T with the given value. 256 | 257 | 258 | 259 | 260 | Removes the context object associated with type T. 261 | 262 | 263 | 264 | 265 | Wraps the notification pattern, where something happens multiple times but the listeners 266 | should only be notified once. 267 | 268 | 269 | The Notifier API is thread-safe. 270 | 271 | The type of the parameter. 272 | 273 | 274 | 275 | Have we already notified the listeners? 276 | 277 | 278 | 279 | 280 | Parameter to notify listeners with. 281 | 282 | 283 | 284 | 285 | Initializes a new instance of the class. 286 | 287 | The parameter to notify listeners with. 288 | 289 | 290 | 291 | Resets this notifier so that it will notify listeners again. 292 | 293 | 294 | 295 | 296 | Notify the listeners if they have not already been notified. 297 | 298 | 299 | 300 | 301 | Allows objects to listen for notifications. If the notifier has already been triggered, 302 | then the added listener is immediately called. 303 | 304 | 305 | 306 | 307 | A PropertyMetadata describes a discovered property or field in a TypeMetadata. 308 | 309 | 310 | 311 | 312 | The cached name of the property/field. 313 | 314 | 315 | 316 | 317 | Writes a value to the property that this property metadata represents, using given 318 | object instance as the context. 319 | 320 | 321 | 322 | 323 | Reads a value from the property that this property metadata represents, using the given 324 | object instance as the context. 325 | 326 | 327 | 328 | 329 | The type of value that is stored inside of the property. For example, for an int field, 330 | StorageType will be typeof(int). 331 | 332 | 333 | 334 | 335 | Initializes a new instance of the PropertyMetadata class from a property member. 336 | 337 | 338 | 339 | 340 | Initializes a new instance of the PropertyMetadata class from a field member. 341 | 342 | 343 | 344 | 345 | Determines whether the specified object is equal to this one. 346 | 347 | 348 | 349 | 350 | Determines whether the specified object is equal to this one. 351 | 352 | 353 | 354 | 355 | Returns a hash code for this instance. 356 | 357 | A hash code for this instance, suitable for use in hashing algorithms and data 358 | structures like a hash table. 359 | 360 | 361 | 362 | The member info that we read to and write from. 363 | 364 | 365 | 366 | 367 | A Real value implements floating point operations on the CPU. It does not adhere any any 368 | IEEE standard, but has the extremely important attribute of providing identical semantics on 369 | every CPU which executes it. This is otherwise impossible to guarantee in the CLR, 370 | especially when 3rd party code is running and/or C++ DLL access is unavailable to set x87 371 | FPU rounding modes. 372 | 373 | 374 | 375 | 376 | Assuming this real has a base 10 representation, this shifts the decimal value to the 377 | left by count digits. 378 | 379 | 380 | 381 | 382 | Returns the number of digits in the given value. The negative sign is not considered a 383 | digit. 384 | 385 | 386 | 387 | 388 | Creates a real value with that is 0.number. For example, CreateDecimal(123) will create 389 | a real value that is equal to "0.123". 390 | 391 | 392 | CreateDecimal(1, 0005, 4) will create 1.0005 CreateDecimal(1, 5, 4) will create 1.0005 393 | 394 | 395 | 396 | 397 | 398 | Create a fixed-int number from parts. For example, to create 1.5 pass in 1 and 500. 399 | 400 | The number above the decimal. For 1.5, this would be 1. 401 | The number below the decimal, to three digits. For 1.5, this 402 | would be 500. For 1.005, this would be 5. 403 | A fixed-int representation of the number parts 404 | 405 | 406 | 407 | Serializes Real values to JSON and back as floats. Without using a converter, Reals 408 | would be serialized as an object ({}) which would create a lot of unnecessary bloat. 409 | 410 | 411 | 412 | 413 | Container type that holds a reference to another object. 414 | 415 | The type of object to store a reference to. 416 | 417 | 418 | 419 | Helper methods for Newtonsoft.JSON 420 | 421 | 422 | 423 | 424 | Returns the two arrays merged together. 425 | 426 | 427 | 428 | 429 | Helper method to create the JsonSerializerSettings that all of the serialization methods 430 | use. 431 | 432 | The converters to use in the settings. 433 | Context objects to use 434 | An appropriate JsonSerializerSettings instance. 435 | 436 | 437 | 438 | Returns a deep clone of the given object instance. 439 | 440 | The type of object to clone. 441 | The original object to clone. 442 | Specific JSON converters to use when deserializing the 443 | object. 444 | Initial context objects to use when deserializing 445 | An identical clone to the given instance. 446 | 447 | 448 | 449 | Returns a deep clone of the given object instance. 450 | 451 | The type of object to clone. 452 | The original object to clone. 453 | An identical clone to the given instance. 454 | 455 | 456 | 457 | Returns the serialized version of the given instance, optionally using the given 458 | converters during the serialization process. 459 | 460 | The type of object to serialize. 461 | The object instance itself to serialize. 462 | The converters to use during the serialization process. 463 | Context objects to use 464 | A serialized version of the given object. 465 | 466 | 467 | 468 | Returns the serialized version of the given instance, optionally using the given 469 | converters during the serialization process. 470 | 471 | The type of object to serialize. 472 | The object instance itself to serialize. 473 | A serialized version of the given object. 474 | 475 | 476 | 477 | Deserializes the given JSON data (hopefully created using Serialize for maximal 478 | compatibility) into an object instance of type T. 479 | 480 | The type of the object to deserialize. 481 | The serialized state of the object. 482 | Converters to use during the deserialization process. 483 | Context objects to use 484 | A deserialized object of type T (or a derived type) that was generated from the 485 | given JSON data. 486 | 487 | 488 | 489 | Deserializes the given JSON data (hopefully created using Serialize for maximal 490 | compatibility) into an object instance of type T. 491 | 492 | The type of the object to deserialize. 493 | The serialized state of the object. 494 | A deserialized object of type T (or a derived type) that was generated from the 495 | given JSON data. 496 | 497 | 498 | 499 | We completely override how Json.NET serializes types 500 | 501 | 502 | 503 | 504 | Discover types, even if they are not in the proper assembly. 505 | 506 | 507 | 508 | 509 | Singleton instance 510 | 511 | 512 | 513 | 514 | Caches type name to type lookups. Type lookups occur in all loaded assemblies. 515 | 516 | 517 | 518 | 519 | Cache from fully qualified type name to type instances. 520 | 521 | 522 | 523 | 524 | Cache from Type to the respective TypeMetadata. 525 | 526 | 527 | 528 | 529 | Assemblies indexed by their name. 530 | 531 | 532 | 533 | 534 | Does a direct lookup for the given type, ie, goes directly to the assembly identified by 535 | assembly name and finds it there. 536 | 537 | The assembly to find the type in. 538 | The name of the type. 539 | The found type. 540 | True if the type was found, false otherwise. 541 | 542 | 543 | 544 | Tries to do an indirect type lookup by scanning through every loaded assembly until the 545 | type is found in one of them. 546 | 547 | The name of the type. 548 | The found type. 549 | True if the type was found, false otherwise. 550 | 551 | 552 | 553 | Find a type with the given name. An exception is thrown if no type with the given name 554 | can be found. This method searches all currently loaded assemblies for the given type. 555 | 556 | The fully qualified name of the type. 557 | A hint for the assembly to start the search with 558 | 559 | 560 | 561 | Finds the associated TypeMetadata for the given type. 562 | 563 | The type to find the type metadata for. 564 | A TypeMetadata that models the given type. 565 | 566 | 567 | 568 | Extensions to the Type API. 569 | 570 | 571 | 572 | 573 | Searches for a particular implementation of the given interface type inside of the type. 574 | This is particularly useful if the interface type is an open type, ie, typeof(IFace[]), 575 | because this method will then return IFace[] but with appropriate type parameters 576 | inserted. 577 | 578 | The base type to search for interface 579 | The interface type to search for. Can be an open generic 580 | type. 581 | The actual interface type that the type contains, or null if there is no 582 | implementation of the given interfaceType on type. 583 | 584 | 585 | 586 | Returns true if the baseType is an implementation of the given interface type. The 587 | interface type can be generic. 588 | 589 | The type to search for an implementation of the given 590 | interface 591 | The interface type to search for 592 | 593 | 594 | 595 | 596 | Provides a view of an arbitrary type that unifies a number of discrete concepts in the CLR. 597 | Arrays and Collection types have special support, but their APIs are unified by the 598 | TypeMetadata so that they can be treated as if they were a regular type. 599 | 600 | 601 | 602 | 603 | Creates a new instance of the type that this metadata points back to. 604 | 605 | 606 | Activator.CreateInstance cannot be used because TypeMetadata can point to an Array. 607 | 608 | 609 | 610 | 611 | Hint that there will be size number of elements stored in the given collection. This 612 | method is completely optional, but if the collection is an array then it will improve 613 | the performance of AppendValue. 614 | 615 | The collection type. 616 | The size hint to use for the collection 617 | 618 | 619 | 620 | Appends a value to the end of the array or collection. If the collection is an array, 621 | then the item is added to array[indexHint]. If it is a collection, then the item is just 622 | appended to the end of the collection. 623 | 624 | 625 | 626 | 627 | Initializes a new instance of the TypeMetadata class from a type. Use TypeCache to get 628 | instances of TypeMetadata; do not use this constructor directly. 629 | 630 | 631 | 632 | 633 | Recursive method that adds all of the properties and fields from the given type into the 634 | given list. This method also fetches inherited properties by using the TypeCache to 635 | retrieve the TypeMetadata for the parent type. 636 | 637 | The type to process to collect properties from. 638 | The list of properties that should be appended to 639 | 640 | 641 | 642 | The cached Add method in ICollection[T]. This only contains a value if IsCollection is 643 | true. 644 | 645 | 646 | 647 | 648 | True if the base type is an array. If true, accessing Properties will throw an 649 | exception. IsCollection is also true if _isArray is true. 650 | 651 | 652 | 653 | 654 | Attempts to remove the property with the given name. 655 | 656 | The name of the property to remove. 657 | True if the property was removed, false if it was not found. 658 | 659 | 660 | 661 | The type that this metadata is modeling, ie, the type that the metadata was constructed 662 | off of. 663 | 664 | 665 | 666 | 667 | Iff this metadata maps back to a Collection or an Array type, then this is the type of 668 | element stored inside the array or collection. Otherwise, this method throws an 669 | exception. 670 | 671 | 672 | 673 | 674 | True if the base type is a collection. If true, accessing Properties will throw an 675 | exception. 676 | 677 | 678 | 679 | 680 | The properties on the type. This is used when importing/exporting a type that does not 681 | have a user-defined importer/exporter. 682 | 683 | 684 | 685 | 686 | Generates unique integers that are sequential. This class is thread-safe. 687 | 688 | 689 | 690 | 691 | The next integer to generate. 692 | 693 | 694 | 695 | 696 | Returns the next unique int. 697 | 698 | 699 | 700 | 701 | Notifies that UniqueIdGenerator that the given ID has already been consumed. Please note 702 | that this API is not thread-safe. 703 | 704 | 705 | 706 | 707 | Swaps two ref objects. 708 | 709 | The type of objects to swap. 710 | Object a 711 | Object b 712 | 713 | 714 | 715 | -------------------------------------------------------------------------------- /XNA/DLLs/Lidgren.Network.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacobdufault/forge-sample/6b18d3fb32a7a5c11df830f934995d0becdd45be/XNA/DLLs/Lidgren.Network.dll -------------------------------------------------------------------------------- /XNA/DLLs/Lidgren.Network.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacobdufault/forge-sample/6b18d3fb32a7a5c11df830f934995d0becdd45be/XNA/DLLs/Lidgren.Network.pdb -------------------------------------------------------------------------------- /XNA/DLLs/Newtonsoft.Json.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacobdufault/forge-sample/6b18d3fb32a7a5c11df830f934995d0becdd45be/XNA/DLLs/Newtonsoft.Json.dll -------------------------------------------------------------------------------- /XNA/DLLs/Newtonsoft.Json.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacobdufault/forge-sample/6b18d3fb32a7a5c11df830f934995d0becdd45be/XNA/DLLs/Newtonsoft.Json.pdb -------------------------------------------------------------------------------- /XNA/DLLs/log4net.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacobdufault/forge-sample/6b18d3fb32a7a5c11df830f934995d0becdd45be/XNA/DLLs/log4net.dll -------------------------------------------------------------------------------- /XNA/XNA/ExtendedSpriteBatch.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Xna.Framework; 2 | using Microsoft.Xna.Framework.Graphics; 3 | using System; 4 | 5 | namespace XNA.GameSample { 6 | /// 7 | /// An extended version of the SpriteBatch class that supports line and rectangle drawing. 8 | /// 9 | /// 10 | /// This class has been taken from http://stackoverflow.com/a/7863816 11 | /// 12 | public class ExtendedSpriteBatch : SpriteBatch { 13 | /// 14 | /// The texture used when drawing rectangles, lines and other primitives. This is a 1x1 15 | /// white texture created at runtime. 16 | /// 17 | public Texture2D WhiteTexture { get; protected set; } 18 | 19 | public ExtendedSpriteBatch(GraphicsDevice graphicsDevice) 20 | : base(graphicsDevice) { 21 | this.WhiteTexture = new Texture2D(this.GraphicsDevice, 1, 1); 22 | this.WhiteTexture.SetData(new Color[] { Color.White }); 23 | } 24 | 25 | /// 26 | /// Draw a line between the two supplied points. 27 | /// 28 | /// Starting point. 29 | /// End point. 30 | /// The draw color. 31 | public void DrawLine(Vector2 start, Vector2 end, Color color) { 32 | float length = (end - start).Length(); 33 | float rotation = (float)Math.Atan2(end.Y - start.Y, end.X - start.X); 34 | this.Draw(this.WhiteTexture, start, null, color, rotation, Vector2.Zero, new Vector2(length, 1), SpriteEffects.None, 0); 35 | } 36 | 37 | /// 38 | /// Draw a rectangle. 39 | /// 40 | /// The rectangle to draw. 41 | /// The draw color. 42 | public void DrawRectangle(Rectangle rectangle, Color color) { 43 | this.Draw(this.WhiteTexture, new Rectangle(rectangle.Left, rectangle.Top, rectangle.Width, 1), color); 44 | this.Draw(this.WhiteTexture, new Rectangle(rectangle.Left, rectangle.Bottom, rectangle.Width, 1), color); 45 | this.Draw(this.WhiteTexture, new Rectangle(rectangle.Left, rectangle.Top, 1, rectangle.Height), color); 46 | this.Draw(this.WhiteTexture, new Rectangle(rectangle.Right, rectangle.Top, 1, rectangle.Height + 1), color); 47 | } 48 | 49 | /// 50 | /// Fill a rectangle. 51 | /// 52 | /// The rectangle to fill. 53 | /// The fill color. 54 | public void FillRectangle(Rectangle rectangle, Color color) { 55 | this.Draw(this.WhiteTexture, rectangle, color); 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /XNA/XNA/Forge/DataRegistry.cs: -------------------------------------------------------------------------------- 1 | using Forge.Collections; 2 | using Forge.Entities; 3 | using System; 4 | using System.Collections.Generic; 5 | 6 | namespace Forge.XNA { 7 | /// 8 | /// Specifies that the given type should be used as a custom data renderer. 9 | /// 10 | public class CustomDataRegistryAttribute : Attribute { 11 | /// 12 | /// The type of data that the annotated type renders. 13 | /// 14 | public Type DataType; 15 | 16 | public CustomDataRegistryAttribute(Type dataType) { 17 | DataType = dataType; 18 | } 19 | } 20 | 21 | public static class DataRegistry { 22 | /// 23 | /// Returns all types that have a CustomDataRegistryAttribute attribute. 24 | /// 25 | private static IEnumerable> GetTypesWithAttribute() 26 | where AttributeType : Attribute { 27 | foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) { 28 | foreach (Type type in assembly.GetTypes()) { 29 | object[] attributes = type.GetCustomAttributes(typeof(AttributeType), true); 30 | if (attributes.Length > 0) { 31 | yield return Forge.Utilities.Tuple.Create(type, (AttributeType)attributes[0]); 32 | } 33 | if (attributes.Length > 1) { 34 | throw new InvalidOperationException("Too many satisfying attributes"); 35 | } 36 | } 37 | } 38 | } 39 | 40 | static DataRegistry() { 41 | foreach (var tuple in GetTypesWithAttribute()) { 42 | DataAccessor dataAccessor = new DataAccessor(tuple.Item2.DataType); 43 | int id = dataAccessor.Id; 44 | 45 | Type type = tuple.Item1; 46 | if (type.IsSubclassOf(typeof(DataRenderer))) { 47 | _renderers[id] = type; 48 | } 49 | } 50 | } 51 | 52 | /// 53 | /// Fast lookup from DataAccessor id to renderer type. 54 | /// 55 | private static SparseArray _renderers = new SparseArray(); 56 | 57 | /// 58 | /// Attempts to create a new DataRenderer instance for the given type. 59 | /// 60 | public static bool TryGetRenderer(DataAccessor dataType, out DataRenderer renderer) { 61 | int id = dataType.Id; 62 | 63 | if (_renderers.ContainsKey(id)) { 64 | Type rendererType = _renderers[id]; 65 | renderer = (DataRenderer)Activator.CreateInstance(rendererType); 66 | return true; 67 | } 68 | 69 | renderer = null; 70 | return false; 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /XNA/XNA/Forge/DataRenderer.cs: -------------------------------------------------------------------------------- 1 | using Forge.Collections; 2 | using Forge.Entities; 3 | using Forge.Utilities; 4 | using XNA.GameSample; 5 | 6 | namespace Forge.XNA { 7 | /// 8 | /// Base MonoBehavior type that can be used to implement custom data renderers. DataRenderers 9 | /// need to be annotated with a CustomDataRegistry attribute. 10 | /// 11 | public abstract class DataRenderer : IVisualizable { 12 | protected IQueryableEntity _entity; 13 | 14 | public void Initialize(IQueryableEntity entity) { 15 | _entity = entity; 16 | Visualizer.Instance.Add(this); 17 | 18 | OnInitialize(); 19 | } 20 | 21 | public void Dispose() { 22 | Visualizer.Instance.Remove(this); 23 | 24 | OnDisposed(); 25 | } 26 | 27 | /// 28 | /// Called when the renderer has been initialized. The entity that this renderer will 29 | /// operate on is populated under _entity. 30 | /// 31 | protected abstract void OnInitialize(); 32 | 33 | /// 34 | /// Called when the renderer has been destroyed. 35 | /// 36 | protected abstract void OnDisposed(); 37 | 38 | /// 39 | /// Called when the renderer should draw itself. 40 | /// 41 | public abstract void Draw(ExtendedSpriteBatch spriteBatch, float percentage); 42 | 43 | private UnorderedListMetadata _visualizationMetadata = new UnorderedListMetadata(); 44 | public UnorderedListMetadata VisualizationMetadata { 45 | get { return _visualizationMetadata; } 46 | } 47 | 48 | protected static Vector2r Interpolate(Vector2r start, Vector2r end, float percentage) { 49 | return new Vector2r( 50 | Interpolate(start.X, end.X, percentage), 51 | Interpolate(start.Z, end.Z, percentage)); 52 | } 53 | 54 | protected static Real Interpolate(Real start, Real end, float percentage) { 55 | Real delta = end - start; 56 | return start + (delta * percentage); 57 | 58 | //return (start * (1 - percentage)) + (end * percentage); 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /XNA/XNA/Forge/EntityContainerEventMonitor.cs: -------------------------------------------------------------------------------- 1 | using Forge.Collections; 2 | using Forge.Entities; 3 | using System; 4 | using System.Collections.Generic; 5 | 6 | namespace Forge.XNA { 7 | /// 8 | /// An IEventMonitor that manages the creation of EntityContainers and registering/removing data 9 | /// from those EntityContainers as the data state changes in entities. 10 | /// 11 | [EventMonitorAutomaticInstantiation] 12 | internal class EntityContainerEventMonitor : IEventMonitor { 13 | private SparseArray> _renderers = new SparseArray>(); 14 | 15 | private SparseArray GetRenderers(IEntity entity) { 16 | SparseArray renderers; 17 | 18 | if (_renderers.TryGetValue(entity.UniqueId, out renderers) == false) { 19 | renderers = new SparseArray(); 20 | _renderers[entity.UniqueId] = renderers; 21 | } 22 | 23 | return renderers; 24 | } 25 | 26 | private void OnDataAdded(AddedDataEvent addedData) { 27 | var accessor = new DataAccessor(addedData.AddedDataType); 28 | 29 | DataRenderer renderer; 30 | if (DataRegistry.TryGetRenderer(accessor, out renderer)) { 31 | SparseArray renderers = GetRenderers(addedData.Entity); 32 | renderer.Initialize(addedData.Entity); 33 | renderers[accessor.Id] = renderer; 34 | } 35 | } 36 | 37 | private void OnDataRemoved(RemovedDataEvent removedData) { 38 | SparseArray renderers; 39 | if (_renderers.TryGetValue(removedData.Entity.UniqueId, out renderers)) { 40 | var accessor = new DataAccessor(removedData.RemovedDataType); 41 | 42 | if (renderers.ContainsKey(accessor.Id)) { 43 | DataRenderer renderer = renderers[accessor.Id]; 44 | renderers.Remove(accessor.Id); 45 | 46 | renderer.Dispose(); 47 | } 48 | } 49 | } 50 | 51 | private void OnEntityCreated(IEntity entity) { 52 | _renderers[entity.UniqueId] = new SparseArray(); 53 | } 54 | 55 | private void OnEntityDestroyed(IEntity entity) { 56 | SparseArray renderers; 57 | if (_renderers.TryGetValue(entity.UniqueId, out renderers)) { 58 | 59 | foreach (KeyValuePair renderer in renderers) { 60 | renderer.Value.Dispose(); 61 | } 62 | } 63 | 64 | _renderers.Remove(entity.UniqueId); 65 | } 66 | 67 | public void Initialize(IEventNotifier notifier) { 68 | notifier.OnEvent(evnt => { 69 | OnEntityCreated(evnt.Entity); 70 | }); 71 | notifier.OnEvent(evnt => { 72 | OnEntityDestroyed(evnt.Entity); 73 | }); 74 | notifier.OnEvent(OnDataAdded); 75 | notifier.OnEvent(OnDataRemoved); 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /XNA/XNA/Forge/GameEngineManager.cs: -------------------------------------------------------------------------------- 1 | using Forge.Entities; 2 | using Forge.Networking.AutomaticTurnGame; 3 | using Forge.Networking.Core; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using XNA.GameSample; 8 | 9 | namespace Forge.XNA { 10 | public class GameEngineManager { 11 | private IGameEngine _gameEngine; 12 | public NetworkContext _networkContext; 13 | public AutomaticTurnGame _turnGame; 14 | 15 | public IGameEngine Engine { 16 | get { 17 | return _gameEngine; 18 | } 19 | } 20 | 21 | public GameEngineManager(string snapshotJson, string templateJson, int targetUpdatesPerSecond) { 22 | // allocate the engine 23 | // TODO: examine the maybe, make sure the game actually loaded 24 | _gameEngine = GameEngineFactory.CreateEngine(snapshotJson, templateJson).Value; 25 | 26 | // create the event monitors 27 | CreateEventMonitors(_gameEngine.EventNotifier); 28 | 29 | _networkContext = NetworkContext.CreateServer(new Player("test-player"), ""); 30 | _turnGame = new AutomaticTurnGame(_networkContext, targetUpdatesPerSecond); 31 | } 32 | 33 | public void SendCommand(IGameCommand command) { 34 | _turnGame.SendCommand(new List() { command }); 35 | } 36 | 37 | public void Update(float elapsedMilliseconds) { 38 | // update network and the turn game 39 | _networkContext.Update(); 40 | _turnGame.Update(elapsedMilliseconds); 41 | 42 | // try to update the game 43 | List commands; 44 | if (_turnGame.TryUpdate(out commands)) { 45 | _gameEngine.Update(commands.Cast()).Wait(); 46 | _gameEngine.SynchronizeState().Wait(); 47 | _gameEngine.DispatchEvents(); 48 | } 49 | } 50 | 51 | public void Draw(ExtendedSpriteBatch spriteBatch) { 52 | Visualizer.Instance.Draw(spriteBatch, _turnGame); 53 | } 54 | 55 | /// 56 | /// Discovers allocatable event monitors, allocates them, and then initializes them with the 57 | /// given event notifier. 58 | /// 59 | /// The event notifier to initialize the monitors with 60 | private static void CreateEventMonitors(IEventNotifier eventNotifier) { 61 | var monitors = 62 | from assembly in AppDomain.CurrentDomain.GetAssemblies() 63 | from type in assembly.GetTypes() 64 | where typeof(IEventMonitor).IsAssignableFrom(type) 65 | where type.IsAbstract == false 66 | where type.IsInterface == false 67 | where type.IsClass == true 68 | where Attribute.IsDefined(type, typeof(EventMonitorAutomaticInstantiationAttribute)) 69 | select (IEventMonitor)Activator.CreateInstance(type, /*nonPublic:*/ true); 70 | 71 | foreach (IEventMonitor monitor in monitors) { 72 | monitor.Initialize(eventNotifier); 73 | } 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /XNA/XNA/Forge/IEventMonitor.cs: -------------------------------------------------------------------------------- 1 | using Forge.Entities; 2 | using System; 3 | 4 | namespace Forge.XNA { 5 | /// 6 | /// Annotation required by types which implement IEventMonitor signifying that they should be 7 | /// automatically instantiated. 8 | /// 9 | /// 10 | /// This attribute is not really necessary; instead, it is used because it greatly increases 11 | /// code-reading clarity. 12 | /// 13 | public sealed class EventMonitorAutomaticInstantiationAttribute : Attribute { 14 | } 15 | 16 | /// 17 | /// A type that can monitor IEvents that are coming out of the game engine. These are 18 | /// automatically discovered and instantiated when a new GameEngine is created. 19 | /// 20 | public interface IEventMonitor { 21 | /// 22 | /// Initialize the event monitor. 23 | /// 24 | /// The event notifier to register the monitor with. 25 | void Initialize(IEventNotifier notifier); 26 | } 27 | } -------------------------------------------------------------------------------- /XNA/XNA/Forge/PrefabData.cs: -------------------------------------------------------------------------------- 1 | using Forge.Entities; 2 | using Newtonsoft.Json; 3 | 4 | // PrefabData must always be in namespace Forge to retain compatibility across rendering engines. 5 | namespace Forge { 6 | /// 7 | /// Data that specifies that an IEntity should use a prefab as its base GameObject instead of an 8 | /// empty one. 9 | /// 10 | [JsonObject(MemberSerialization.OptIn)] 11 | public class PrefabData : Data.NonVersioned { 12 | /// 13 | /// The prefab to use for getting the base GameObject that will render the IEntity instance 14 | /// that this data instance is attached to. 15 | /// 16 | [JsonProperty("PrefabResourcePath")] 17 | public string PrefabResourcePath; 18 | } 19 | } -------------------------------------------------------------------------------- /XNA/XNA/Forge/README.md: -------------------------------------------------------------------------------- 1 | ## Warning 2 | 3 | This file contains an early version of the future Forge XNA integration package. This code is still very unpolished. Sorry! -------------------------------------------------------------------------------- /XNA/XNA/Forge/Visualizer.cs: -------------------------------------------------------------------------------- 1 | using Forge.Collections; 2 | using Forge.Networking.AutomaticTurnGame; 3 | using XNA.GameSample; 4 | 5 | namespace Forge.XNA { 6 | public class Visualizer { 7 | public static Visualizer Instance = new Visualizer(); 8 | 9 | /// 10 | /// Should the visualizer interpolate between frames? 11 | /// 12 | public bool Interpolate = true; 13 | 14 | /// 15 | /// The list of items that need to be rendered (or rather, have their rendering states 16 | /// updated) . 17 | /// 18 | protected UnorderedList _visualizable = new UnorderedList(); 19 | 20 | /// 21 | /// Add the given item to the list of items which will receive visualization events. 22 | /// 23 | /// The visualized item. 24 | public void Add(IVisualizable visualizable) { 25 | _visualizable.Add(visualizable, visualizable.VisualizationMetadata); 26 | } 27 | 28 | /// 29 | /// Removes the given item from the list of items that receive visualization events. 30 | /// 31 | /// The visualized item. 32 | public void Remove(IVisualizable visualizable) { 33 | _visualizable.Remove(visualizable, visualizable.VisualizationMetadata); 34 | } 35 | 36 | /// 37 | /// Draws every visualizable element. 38 | /// 39 | public void Draw(ExtendedSpriteBatch spriteBatch, AutomaticTurnGame game) { 40 | float interpolate = 1.0f; 41 | if (Interpolate) { 42 | interpolate = game.InterpolationPercentage; 43 | } 44 | 45 | foreach (IVisualizable visualizable in _visualizable) { 46 | visualizable.Draw(spriteBatch, interpolate); 47 | } 48 | } 49 | } 50 | 51 | /// 52 | /// Interface for objects which should visualize themselves from the entity system. 53 | /// 54 | public interface IVisualizable { 55 | /// 56 | /// Used by the visualizer for fast removes. 57 | /// 58 | UnorderedListMetadata VisualizationMetadata { 59 | get; 60 | } 61 | 62 | /// 63 | /// Draw the object. 64 | /// 65 | /// How much to interpolate from the previous state to the current 66 | /// state (a value between [0, 1]). 67 | void Draw(ExtendedSpriteBatch spriteBatch, float percentage); 68 | } 69 | } -------------------------------------------------------------------------------- /XNA/XNA/Game.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacobdufault/forge-sample/6b18d3fb32a7a5c11df830f934995d0becdd45be/XNA/XNA/Game.ico -------------------------------------------------------------------------------- /XNA/XNA/GameThumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacobdufault/forge-sample/6b18d3fb32a7a5c11df830f934995d0becdd45be/XNA/XNA/GameThumbnail.png -------------------------------------------------------------------------------- /XNA/XNA/PositionRenderer.cs: -------------------------------------------------------------------------------- 1 | using Forge.Entities; 2 | using Forge.Utilities; 3 | using Forge.XNA; 4 | using GameSample; 5 | using Microsoft.Xna.Framework; 6 | 7 | namespace XNA.GameSample { 8 | /// 9 | /// Renders entities which have position data 10 | /// 11 | [CustomDataRegistry(typeof(PositionData))] 12 | internal class PositionRenderer : DataRenderer { 13 | protected override void OnInitialize() { 14 | } 15 | 16 | protected override void OnDisposed() { 17 | } 18 | 19 | public override void Draw(ExtendedSpriteBatch spriteBatch, float percentage) { 20 | Bound prev = _entity.Previous().Position; 21 | Bound curr = _entity.Current().Position; 22 | 23 | // some magic constants that center the rendering in the window; the sample doesn't 24 | // bother to properly setup a coordinate system 25 | Real scale = 25; 26 | Real zoffset = 250; 27 | Real xoffset = 350; 28 | 29 | int x = (Interpolate(prev.X, curr.X, percentage) * scale + xoffset).AsInt; 30 | int z = (Interpolate(-prev.Z, -curr.Z, percentage) * scale + zoffset).AsInt; 31 | int radius = (Interpolate(prev.Radius, curr.Radius, percentage) * scale).AsInt; 32 | 33 | Rectangle rectangle = new Rectangle(x - radius, z - radius, 2 * radius, 2 * radius); 34 | spriteBatch.DrawRectangle(rectangle, Color.BlanchedAlmond); 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /XNA/XNA/Program.cs: -------------------------------------------------------------------------------- 1 | 2 | namespace XNA.GameSample { 3 | #if WINDOWS || XBOX 4 | internal static class Program { 5 | /// 6 | /// The main entry point for the application. 7 | /// 8 | private static void Main(string[] args) { 9 | using (var game = new XnaGame()) { 10 | game.Run(); 11 | } 12 | } 13 | } 14 | #endif 15 | } -------------------------------------------------------------------------------- /XNA/XNA/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("XNA")] 9 | [assembly: AssemblyProduct("XNA")] 10 | [assembly: AssemblyDescription("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyCopyright("Copyright © 2014")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. Only Windows 19 | // assemblies support COM. 20 | [assembly: ComVisible(false)] 21 | 22 | // On Windows, the following GUID is for the ID of the typelib if this 23 | // project is exposed to COM. On other platforms, it unique identifies the 24 | // title storage container when deploying this assembly to the device. 25 | [assembly: Guid("1af6f0d8-c40e-4c78-8171-59bc34e65a43")] 26 | 27 | // Version information for an assembly consists of the following four values: 28 | // 29 | // Major Version 30 | // Minor Version 31 | // Build Number 32 | // Revision 33 | // 34 | [assembly: AssemblyVersion("1.0.0.0")] -------------------------------------------------------------------------------- /XNA/XNA/XNA.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | {55DEEFF6-2A0C-4454-823D-F2BCD8644C5D} 5 | {6D335F3A-9D43-41b4-9D22-F6F17C4BE596};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 6 | Debug 7 | x86 8 | WinExe 9 | Properties 10 | XNA 11 | XNA 12 | v4.0 13 | Client 14 | v4.0 15 | Windows 16 | Reach 17 | 1d8da9b6-9fa2-4be1-b3db-6bbf0df03f6a 18 | Game 19 | Game.ico 20 | GameThumbnail.png 21 | publish\ 22 | true 23 | Disk 24 | false 25 | Foreground 26 | 7 27 | Days 28 | false 29 | false 30 | true 31 | 0 32 | 1.0.0.%2a 33 | false 34 | false 35 | true 36 | 37 | 38 | true 39 | full 40 | false 41 | bin\x86\Debug 42 | DEBUG;TRACE;WINDOWS 43 | prompt 44 | 4 45 | true 46 | false 47 | x86 48 | false 49 | 50 | 51 | pdbonly 52 | true 53 | bin\x86\Release 54 | TRACE;WINDOWS 55 | prompt 56 | 4 57 | true 58 | false 59 | x86 60 | true 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | ..\DLLs\Forge.AllLibraries.dll 69 | 70 | 71 | ..\DLLs\Forge.Collections.dll 72 | 73 | 74 | ..\DLLs\Forge.Entities.dll 75 | 76 | 77 | ..\DLLs\Forge.Extensions.dll 78 | 79 | 80 | ..\DLLs\Forge.Networking.dll 81 | 82 | 83 | ..\DLLs\Forge.Utilities.dll 84 | 85 | 86 | ..\DLLs\Lidgren.Network.dll 87 | 88 | 89 | ..\DLLs\log4net.dll 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | ..\DLLs\Newtonsoft.Json.dll 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | true 123 | 124 | 125 | 126 | 127 | {a0314c4b-6cba-4d0f-b32f-24b450a0ddef} 128 | GameLogic 129 | 130 | 131 | XNAContent 132 | Content 133 | 134 | 135 | 136 | 137 | False 138 | Microsoft .NET Framework 4 Client Profile %28x86 and x64%29 139 | true 140 | 141 | 142 | False 143 | .NET Framework 3.5 SP1 Client Profile 144 | false 145 | 146 | 147 | False 148 | .NET Framework 3.5 SP1 149 | false 150 | 151 | 152 | False 153 | Windows Installer 3.1 154 | true 155 | 156 | 157 | False 158 | Microsoft XNA Framework Redistributable 4.0 159 | true 160 | 161 | 162 | 163 | 164 | 172 | -------------------------------------------------------------------------------- /XNA/XNA/XNA.csproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | en-US 11 | false 12 | 13 | -------------------------------------------------------------------------------- /XNA/XNA/XnaGame.cs: -------------------------------------------------------------------------------- 1 | using Forge.XNA; 2 | using GameSample; 3 | using Microsoft.Xna.Framework; 4 | using Microsoft.Xna.Framework.Graphics; 5 | using Microsoft.Xna.Framework.Input; 6 | using System.IO; 7 | using System.Reflection; 8 | 9 | namespace XNA.GameSample { 10 | public class XnaGame : Microsoft.Xna.Framework.Game { 11 | private ExtendedSpriteBatch _spriteBatch; 12 | private GameEngineManager _gameEngine; 13 | private GraphicsDeviceManager _graphics; 14 | 15 | public XnaGame() { 16 | Assembly.LoadFile(Path.GetFullPath("GameLogic.dll")); 17 | Content.RootDirectory = "Content"; 18 | 19 | _graphics = new GraphicsDeviceManager(this); 20 | } 21 | 22 | /// 23 | /// Allows the game to perform any initialization it needs to before starting to run. This 24 | /// is where it can query for any required services and load any non-graphic related 25 | /// content. Calling base.Initialize will enumerate through any components and initialize 26 | /// them as well. 27 | /// 28 | protected override void Initialize() { 29 | base.Initialize(); 30 | 31 | // get the JSON that the engine will be initialized with 32 | string snapshotJson = File.ReadAllText("../../../../../Assets/snapshot.json"); 33 | string templateJson = File.ReadAllText("../../../../../Assets/templates.json"); 34 | 35 | _gameEngine = new GameEngineManager(snapshotJson, templateJson, targetUpdatesPerSecond: 15); 36 | } 37 | 38 | /// 39 | /// LoadContent will be called once per game and is the place to load all of your content. 40 | /// 41 | protected override void LoadContent() { 42 | _spriteBatch = new ExtendedSpriteBatch(GraphicsDevice); 43 | } 44 | 45 | /// 46 | /// Allows the game to run logic such as updating the world, checking for collisions, 47 | /// gathering input, and playing audio. 48 | /// 49 | /// Provides a snapshot of timing values. 50 | protected override void Update(GameTime gameTime) { 51 | // Allows the game to exit 52 | if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) 53 | this.Exit(); 54 | 55 | if (Keyboard.GetState().IsKeyDown(Keys.D1)) { 56 | _gameEngine.SendCommand(new StartDestroyingInput()); 57 | } 58 | if (Keyboard.GetState().IsKeyDown(Keys.D2)) { 59 | _gameEngine.SendCommand(new StopDestroyingInput()); 60 | } 61 | 62 | // update with the elapsed seconds 63 | _gameEngine.Update(gameTime.ElapsedGameTime.Milliseconds); 64 | 65 | base.Update(gameTime); 66 | } 67 | 68 | /// 69 | /// This is called when the game should draw itself. 70 | /// 71 | /// Provides a snapshot of timing values. 72 | protected override void Draw(GameTime gameTime) { 73 | GraphicsDevice.Clear(Color.CornflowerBlue); 74 | 75 | _spriteBatch.Begin(); 76 | _gameEngine.Draw(_spriteBatch); 77 | _spriteBatch.End(); 78 | 79 | base.Draw(gameTime); 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /XNA/XNAContent/XNAContent.contentproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | {97E2A491-3907-46F5-A4D0-66781E1A1AC7} 5 | {96E2B04D-8817-42c6-938A-82C39BA4D311};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 6 | Debug 7 | x86 8 | Library 9 | Properties 10 | v4.0 11 | v4.0 12 | bin\$(Platform)\$(Configuration) 13 | Content 14 | 15 | 16 | x86 17 | 18 | 19 | x86 20 | 21 | 22 | XNAContent 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 40 | -------------------------------------------------------------------------------- /demo_unity.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacobdufault/forge-sample/6b18d3fb32a7a5c11df830f934995d0becdd45be/demo_unity.gif -------------------------------------------------------------------------------- /demo_xna.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacobdufault/forge-sample/6b18d3fb32a7a5c11df830f934995d0becdd45be/demo_xna.gif --------------------------------------------------------------------------------