Browse Source

interfaces; README

master
Robin Thoni 7 years ago
parent
commit
23cf0bb694

+ 39
- 0
README.md View File

1
+Aspirobot
2
+=========
3
+Aspirobot is a simple(r) AI agent that vaccums dust in your rooms but leaves your jewels.
4
+
5
+Build
6
+-----
7
+- Command line  
8
+`cd uqac-ia-aspirobot
9
+dotnet restore
10
+dotnet build
11
+dotnet run`
12
+
13
+- Visual Studio  
14
+Run VS, open solution, wait for package restore, click run (F5)
15
+
16
+- Rider  
17
+Run Rider, open solution, wait for package restore, click run (Shift + F10)
18
+
19
+Configuration
20
+-------------
21
+Some behaviors can be configured in Program.cs file:  
22
+- EnvConfig (Environment configuration)
23
+  - Height: Map height
24
+  - Width: Map width
25
+  - ActionPropability: Probability that an action occurs in the enviromnent, once per SleepTime (>=0, <=100)
26
+  - AddDustProbability: Probability that a dust is added on the map, only when an action is to be taken (>=0, <=100)
27
+  - AddJewelProbability: Probability that a jewel is added on the map, only when an action is to be taken, and AddDustProbability does not occur (>=0, <=100)
28
+  - RemoveJewelProbability: Probability that a jewel is removed from the map, only when an action is to be taken, and neither AddDustProbability nor AddJewelProbability occur (>=0, <=100)
29
+  - SleepTime: Time between each iteration in ms (>=0)
30
+  
31
+- AgConfig (Agent configuration)
32
+  - SleepTime: Time between each iteration in ms (>=0)
33
+  - StartX: Agent start X position (>=0, <EnvConfig.Width)
34
+  - StartY: Agent start Y position (>=0, <EnvConfig.Height)
35
+  - AutoAdjustThinkTimeInterval: Indicate if agent should try to auto adjust think time interval 
36
+  - ThinkTimeInterval: Default think time interval in ms (>=0). This variable controls how often the agent will re-evaluate the situation
37
+  
38
+How it works
39
+------------

+ 30
- 13
uqac-ia-aspirobot/Agent/AgAgent.cs View File

3
 using System.Threading;
3
 using System.Threading;
4
 using Microsoft.Extensions.DependencyInjection;
4
 using Microsoft.Extensions.DependencyInjection;
5
 using Microsoft.Extensions.Options;
5
 using Microsoft.Extensions.Options;
6
-using uqac_ia_aspirobot.Agent.Effectors;
6
+using uqac_ia_aspirobot.Agent.FakeEnv;
7
+using uqac_ia_aspirobot.Agent.FakeEnv.Effectors;
8
+using uqac_ia_aspirobot.Agent.FakeEnv.Sensors;
9
+using uqac_ia_aspirobot.Agent.Interfaces.Effectors;
10
+using uqac_ia_aspirobot.Agent.Interfaces.Sensors;
7
 using uqac_ia_aspirobot.Common;
11
 using uqac_ia_aspirobot.Common;
8
 using uqac_ia_aspirobot.Extensions;
12
 using uqac_ia_aspirobot.Extensions;
9
 using uqac_ia_aspirobot.Interfaces;
13
 using uqac_ia_aspirobot.Interfaces;
13
 {
17
 {
14
     public class AgAgent
18
     public class AgAgent
15
     {
19
     {
16
-        private readonly AgDustSensor _agDustSensor;
20
+        private readonly IAgDustSensor _agDustSensor;
21
+        private readonly IAgBatterySensor _agBatterySensor;
22
+        private readonly IAgPickedSensor _agPickedSensor;
23
+        private readonly IAgVaccumSensor _agVaccumSensor;
17
 
24
 
18
-        private readonly AgEngineEffector _engineEffector;
25
+        private readonly IAgEngineEffector _engineEffector;
19
 
26
 
20
-        private readonly AgVaccumEffector _vaccumEffector;
27
+        private readonly IAgVaccumEffector _vaccumEffector;
21
 
28
 
22
         private readonly IEnvironment _environment;
29
         private readonly IEnvironment _environment;
23
 
30
 
36
             agServices.AddSingleton<AgAgent>();
43
             agServices.AddSingleton<AgAgent>();
37
             agServices.AddSingleton<ArClient>();
44
             agServices.AddSingleton<ArClient>();
38
 
45
 
39
-            agServices.AddSingleton<AgDustSensor>();
40
-            agServices.AddSingleton<AgBatterySensor>();
41
-            agServices.AddSingleton<AgVaccumSensor>();
42
-            agServices.AddSingleton<AgPickedSensor>();
46
+            agServices.AddSingleton<IAgDustSensor, AgDustSensor>();
47
+            agServices.AddSingleton<IAgBatterySensor, AgBatterySensor>();
48
+            agServices.AddSingleton<IAgVaccumSensor, AgVaccumSensor>();
49
+            agServices.AddSingleton<IAgPickedSensor, AgPickedSensor>();
43
 
50
 
44
-            agServices.AddSingleton<AgVaccumEffector>();
45
-            agServices.AddSingleton<AgEngineEffector>();
51
+            agServices.AddSingleton<IAgVaccumEffector, AgVaccumEffector>();
52
+            agServices.AddSingleton<IAgEngineEffector, AgEngineEffector>();
46
 
53
 
47
             agServices.AddSingleton<IUi, UiConsole>();
54
             agServices.AddSingleton<IUi, UiConsole>();
48
             agServices.AddSingleton<IEnvironment, AgEnvironment>();
55
             agServices.AddSingleton<IEnvironment, AgEnvironment>();
63
             _thread.Join();
70
             _thread.Join();
64
         }
71
         }
65
 
72
 
66
-        public AgAgent(IEnvironment environment, IOptions<AgConfig> options, AgState state, IUi ui,
67
-            AgDustSensor agDustSensor,
68
-            AgEngineEffector engineEffector, AgVaccumEffector vaccumEffector)
73
+        public AgAgent(IOptions<AgConfig> options,
74
+            IEnvironment environment, AgState state, IUi ui,
75
+            IAgDustSensor agDustSensor, IAgBatterySensor agBatterySensor, IAgPickedSensor agPickedSensor, IAgVaccumSensor agVaccumSensor,
76
+            IAgEngineEffector engineEffector, IAgVaccumEffector vaccumEffector)
69
         {
77
         {
70
             _agDustSensor = agDustSensor;
78
             _agDustSensor = agDustSensor;
79
+            _agBatterySensor = agBatterySensor;
80
+            _agPickedSensor = agPickedSensor;
81
+            _agVaccumSensor = agVaccumSensor;
82
+
71
             _engineEffector = engineEffector;
83
             _engineEffector = engineEffector;
72
             _vaccumEffector = vaccumEffector;
84
             _vaccumEffector = vaccumEffector;
85
+
73
             _environment = environment;
86
             _environment = environment;
74
             _state = state;
87
             _state = state;
75
             _ui = ui;
88
             _ui = ui;
89
+
76
             _options = options.Value;
90
             _options = options.Value;
77
             _state.LastThinkTime = DateTime.MinValue;
91
             _state.LastThinkTime = DateTime.MinValue;
78
             _state.ThinkTimeInterval = _options.ThinkTimeInterval;
92
             _state.ThinkTimeInterval = _options.ThinkTimeInterval;
102
         public void UpdateSensors()
116
         public void UpdateSensors()
103
         {
117
         {
104
             _agDustSensor.Update();
118
             _agDustSensor.Update();
119
+            _agBatterySensor.Update();
120
+            _agPickedSensor.Update();
121
+            _agVaccumSensor.Update();
105
         }
122
         }
106
 
123
 
107
         public void UpdateState()
124
         public void UpdateState()

uqac-ia-aspirobot/Agent/AgEnvironment.cs → uqac-ia-aspirobot/Agent/FakeEnv/AgEnvironment.cs View File

5
 using uqac_ia_aspirobot.Extensions;
5
 using uqac_ia_aspirobot.Extensions;
6
 using uqac_ia_aspirobot.Interfaces;
6
 using uqac_ia_aspirobot.Interfaces;
7
 
7
 
8
-namespace uqac_ia_aspirobot.Agent
8
+namespace uqac_ia_aspirobot.Agent.FakeEnv
9
 {
9
 {
10
     public class AgEnvironment : IEnvironment
10
     public class AgEnvironment : IEnvironment
11
     {
11
     {

uqac-ia-aspirobot/Agent/AgRoom.cs → uqac-ia-aspirobot/Agent/FakeEnv/AgRoom.cs View File

2
 using uqac_ia_aspirobot.Extensions;
2
 using uqac_ia_aspirobot.Extensions;
3
 using uqac_ia_aspirobot.Interfaces;
3
 using uqac_ia_aspirobot.Interfaces;
4
 
4
 
5
-namespace uqac_ia_aspirobot.Agent
5
+namespace uqac_ia_aspirobot.Agent.FakeEnv
6
 {
6
 {
7
     public class AgRoom : IRoom
7
     public class AgRoom : IRoom
8
     {
8
     {

uqac-ia-aspirobot/Agent/Effectors/AgEngineEffector.cs → uqac-ia-aspirobot/Agent/FakeEnv/Effectors/AgEngineEffector.cs View File

1
 using Microsoft.Extensions.Options;
1
 using Microsoft.Extensions.Options;
2
+using uqac_ia_aspirobot.Agent.Interfaces.Effectors;
3
+using uqac_ia_aspirobot.Agent.Interfaces.Sensors;
2
 using uqac_ia_aspirobot.Extensions;
4
 using uqac_ia_aspirobot.Extensions;
3
 
5
 
4
-namespace uqac_ia_aspirobot.Agent.Effectors
6
+namespace uqac_ia_aspirobot.Agent.FakeEnv.Effectors
5
 {
7
 {
6
-    public class AgEngineEffector
8
+    public class AgEngineEffector : IAgEngineEffector
7
     {
9
     {
8
-        private readonly AgBatterySensor _agBatterySensor;
10
+        private readonly IAgBatterySensor _agBatterySensor;
9
 
11
 
10
         private readonly AgConfig _options;
12
         private readonly AgConfig _options;
11
 
13
 
13
 
15
 
14
         public int Y { get; protected set; }
16
         public int Y { get; protected set; }
15
 
17
 
16
-        public AgEngineEffector(IOptions<AgConfig> options, AgBatterySensor agBatterySensor)
18
+        public AgEngineEffector(IOptions<AgConfig> options, IAgBatterySensor agBatterySensor)
17
         {
19
         {
18
             _agBatterySensor = agBatterySensor;
20
             _agBatterySensor = agBatterySensor;
19
             _options = options.Value;
21
             _options = options.Value;

uqac-ia-aspirobot/Agent/Effectors/AgVaccumEffector.cs → uqac-ia-aspirobot/Agent/FakeEnv/Effectors/AgVaccumEffector.cs View File

1
-using uqac_ia_aspirobot.Common;
1
+using uqac_ia_aspirobot.Agent.Interfaces.Effectors;
2
+using uqac_ia_aspirobot.Agent.Interfaces.Sensors;
3
+using uqac_ia_aspirobot.Common;
2
 using uqac_ia_aspirobot.Extensions;
4
 using uqac_ia_aspirobot.Extensions;
3
 using uqac_ia_aspirobot.Interfaces;
5
 using uqac_ia_aspirobot.Interfaces;
4
 
6
 
5
-namespace uqac_ia_aspirobot.Agent.Effectors
7
+namespace uqac_ia_aspirobot.Agent.FakeEnv.Effectors
6
 {
8
 {
7
-    public class AgVaccumEffector
9
+    public class AgVaccumEffector : IAgVaccumEffector
8
     {
10
     {
9
-        private readonly AgEngineEffector _engineEffector;
11
+        private readonly IAgEngineEffector _engineEffector;
10
         private readonly ArClient _arClient;
12
         private readonly ArClient _arClient;
11
         private readonly IEnvironment _environment;
13
         private readonly IEnvironment _environment;
12
-        private readonly AgBatterySensor _agBatterySensor;
13
-        private readonly AgVaccumSensor _agVaccumSensor;
14
-        private readonly AgPickedSensor _agPickedSensor;
14
+        private readonly IAgBatterySensor _agBatterySensor;
15
+        private readonly IAgVaccumSensor _agVaccumSensor;
16
+        private readonly IAgPickedSensor _agPickedSensor;
15
 
17
 
16
-        public AgVaccumEffector(AgEngineEffector engineEffector, ArClient arClient, IEnvironment environment,
17
-            AgBatterySensor agBatterySensor, AgVaccumSensor agVaccumSensor, AgPickedSensor agPickedSensor)
18
+        public AgVaccumEffector(IAgEngineEffector engineEffector, ArClient arClient, IEnvironment environment,
19
+            IAgBatterySensor agBatterySensor, IAgVaccumSensor agVaccumSensor, IAgPickedSensor agPickedSensor)
18
         {
20
         {
19
             _engineEffector = engineEffector;
21
             _engineEffector = engineEffector;
20
             _arClient = arClient;
22
             _arClient = arClient;

+ 21
- 0
uqac-ia-aspirobot/Agent/FakeEnv/Sensors/AgBatterySensor.cs View File

1
+using uqac_ia_aspirobot.Agent.Interfaces.Sensors;
2
+
3
+namespace uqac_ia_aspirobot.Agent.FakeEnv.Sensors
4
+{
5
+    public class AgBatterySensor : IAgBatterySensor
6
+    {
7
+        public int Spent { get; protected set; }
8
+
9
+        public void Add(int v)
10
+        {
11
+            if (v > 0)
12
+            {
13
+                Spent += v;
14
+            }
15
+        }
16
+
17
+        public void Update()
18
+        {
19
+        }
20
+    }
21
+}

uqac-ia-aspirobot/Agent/Sensors/AgDustSensor.cs → uqac-ia-aspirobot/Agent/FakeEnv/Sensors/AgDustSensor.cs View File

1
-using uqac_ia_aspirobot.Interfaces;
1
+using uqac_ia_aspirobot.Agent.Interfaces.Sensors;
2
+using uqac_ia_aspirobot.Interfaces;
2
 
3
 
3
-namespace uqac_ia_aspirobot.Agent
4
+namespace uqac_ia_aspirobot.Agent.FakeEnv.Sensors
4
 {
5
 {
5
-    public class AgDustSensor
6
+    public class AgDustSensor : IAgDustSensor
6
     {
7
     {
7
         private readonly AgEnvironment _environment;
8
         private readonly AgEnvironment _environment;
8
 
9
 

+ 18
- 0
uqac-ia-aspirobot/Agent/FakeEnv/Sensors/AgPickedSensor.cs View File

1
+using uqac_ia_aspirobot.Agent.Interfaces.Sensors;
2
+
3
+namespace uqac_ia_aspirobot.Agent.FakeEnv.Sensors
4
+{
5
+    public class AgPickedSensor : IAgPickedSensor
6
+    {
7
+        public int Picked { get; protected set; }
8
+
9
+        public void Increase()
10
+        {
11
+            ++Picked;
12
+        }
13
+
14
+        public void Update()
15
+        {
16
+        }
17
+    }
18
+}

+ 18
- 0
uqac-ia-aspirobot/Agent/FakeEnv/Sensors/AgVaccumSensor.cs View File

1
+using uqac_ia_aspirobot.Agent.Interfaces.Sensors;
2
+
3
+namespace uqac_ia_aspirobot.Agent.FakeEnv.Sensors
4
+{
5
+    public class AgVaccumSensor : IAgVaccumSensor
6
+    {
7
+        public int Vaccumed { get; protected set; }
8
+
9
+        public void Increase()
10
+        {
11
+            ++Vaccumed;
12
+        }
13
+
14
+        public void Update()
15
+        {
16
+        }
17
+    }
18
+}

+ 12
- 0
uqac-ia-aspirobot/Agent/Interfaces/Effectors/IAgEngineEffector.cs View File

1
+namespace uqac_ia_aspirobot.Agent.Interfaces.Effectors
2
+{
3
+    public interface IAgEngineEffector
4
+    {
5
+
6
+        int X { get; }
7
+
8
+        int Y { get; }
9
+
10
+        void MoveTo(int x, int y);
11
+    }
12
+}

+ 8
- 0
uqac-ia-aspirobot/Agent/Interfaces/Effectors/IAgVaccumEffector.cs View File

1
+namespace uqac_ia_aspirobot.Agent.Interfaces.Effectors
2
+{
3
+    public interface IAgVaccumEffector
4
+    {
5
+        void Vaccum();
6
+        void Pick();
7
+    }
8
+}

+ 9
- 0
uqac-ia-aspirobot/Agent/Interfaces/Sensors/IAgBatterySensor.cs View File

1
+namespace uqac_ia_aspirobot.Agent.Interfaces.Sensors
2
+{
3
+    public interface IAgBatterySensor : ISensor
4
+    {
5
+        int Spent { get; }
6
+
7
+        void Add(int v);
8
+    }
9
+}

+ 6
- 0
uqac-ia-aspirobot/Agent/Interfaces/Sensors/IAgDustSensor.cs View File

1
+namespace uqac_ia_aspirobot.Agent.Interfaces.Sensors
2
+{
3
+    public interface IAgDustSensor : ISensor
4
+    {
5
+    }
6
+}

+ 9
- 0
uqac-ia-aspirobot/Agent/Interfaces/Sensors/IAgPickedSensor.cs View File

1
+namespace uqac_ia_aspirobot.Agent.Interfaces.Sensors
2
+{
3
+    public interface IAgPickedSensor : ISensor
4
+    {
5
+        int Picked { get; }
6
+
7
+        void Increase();
8
+    }
9
+}

+ 9
- 0
uqac-ia-aspirobot/Agent/Interfaces/Sensors/IAgVaccumSensor.cs View File

1
+namespace uqac_ia_aspirobot.Agent.Interfaces.Sensors
2
+{
3
+    public interface IAgVaccumSensor : ISensor
4
+    {
5
+        int Vaccumed { get; }
6
+
7
+        void Increase();
8
+    }
9
+}

+ 7
- 0
uqac-ia-aspirobot/Agent/Interfaces/Sensors/ISensor.cs View File

1
+namespace uqac_ia_aspirobot.Agent.Interfaces.Sensors
2
+{
3
+    public interface ISensor
4
+    {
5
+        void Update();
6
+    }
7
+}

+ 0
- 15
uqac-ia-aspirobot/Agent/Sensors/AgBatterySensor.cs View File

1
-namespace uqac_ia_aspirobot.Agent
2
-{
3
-    public class AgBatterySensor
4
-    {
5
-        public int Spent { get; protected set; }
6
-
7
-        public void Add(int v)
8
-        {
9
-            if (v > 0)
10
-            {
11
-                Spent += v;
12
-            }
13
-        }
14
-    }
15
-}

+ 0
- 12
uqac-ia-aspirobot/Agent/Sensors/AgPickedSensor.cs View File

1
-namespace uqac_ia_aspirobot.Agent
2
-{
3
-    public class AgPickedSensor
4
-    {
5
-        public int Picked { get; protected set; }
6
-
7
-        public void Increase()
8
-        {
9
-            ++Picked;
10
-        }
11
-    }
12
-}

+ 0
- 12
uqac-ia-aspirobot/Agent/Sensors/AgVaccumSensor.cs View File

1
-namespace uqac_ia_aspirobot.Agent
2
-{
3
-    public class AgVaccumSensor
4
-    {
5
-        public int Vaccumed { get; protected set; }
6
-
7
-        public void Increase()
8
-        {
9
-            ++Vaccumed;
10
-        }
11
-    }
12
-}

+ 7
- 9
uqac-ia-aspirobot/Extensions/Extensions.cs View File

1
 using System;
1
 using System;
2
 using System.Collections.Generic;
2
 using System.Collections.Generic;
3
-using System.Linq;
4
-using uqac_ia_aspirobot.Agent;
5
-using uqac_ia_aspirobot.Agent.Effectors;
3
+using uqac_ia_aspirobot.Agent.Interfaces.Effectors;
6
 using uqac_ia_aspirobot.Common;
4
 using uqac_ia_aspirobot.Common;
7
 using uqac_ia_aspirobot.Interfaces;
5
 using uqac_ia_aspirobot.Interfaces;
8
 
6
 
116
             return Math.Abs(room.X - x) + Math.Abs(room.Y - y);
114
             return Math.Abs(room.X - x) + Math.Abs(room.Y - y);
117
         }
115
         }
118
 
116
 
119
-        public static int Distance(this IRoom room, AgEngineEffector effector)
117
+        public static int Distance(this IRoom room, IAgEngineEffector effector)
120
         {
118
         {
121
             return room.Distance(effector.X, effector.Y);
119
             return room.Distance(effector.X, effector.Y);
122
         }
120
         }
123
 
121
 
124
-        public static int Distance(this AgEngineEffector effector, int x, int y)
122
+        public static int Distance(this IAgEngineEffector effector, int x, int y)
125
         {
123
         {
126
             return Math.Abs(effector.X - x) + Math.Abs(effector.Y - y);
124
             return Math.Abs(effector.X - x) + Math.Abs(effector.Y - y);
127
         }
125
         }
128
 
126
 
129
-        public static int Distance(this AgEngineEffector effector, IRoom room)
127
+        public static int Distance(this IAgEngineEffector effector, IRoom room)
130
         {
128
         {
131
             return effector.Distance(room.X, room.Y);
129
             return effector.Distance(room.X, room.Y);
132
         }
130
         }
136
             return state.HasFlag(RoomState.Dust) && !state.HasFlag(RoomState.Jewel);
134
             return state.HasFlag(RoomState.Dust) && !state.HasFlag(RoomState.Jewel);
137
         }
135
         }
138
 
136
 
139
-        public static bool IsInPosition(this AgEngineEffector engine, int x, int y)
137
+        public static bool IsInPosition(this IAgEngineEffector engine, int x, int y)
140
         {
138
         {
141
             return engine.X == x && engine.Y == y;
139
             return engine.X == x && engine.Y == y;
142
         }
140
         }
146
             return room.X == x && room.Y == y;
144
             return room.X == x && room.Y == y;
147
         }
145
         }
148
 
146
 
149
-        public static bool IsInRoom(this AgEngineEffector engine, IRoom room)
147
+        public static bool IsInRoom(this IAgEngineEffector engine, IRoom room)
150
         {
148
         {
151
             return engine.IsInPosition(room.X, room.Y);
149
             return engine.IsInPosition(room.X, room.Y);
152
         }
150
         }
153
 
151
 
154
-        public static void Move(this AgEngineEffector engine, int dx, int dy)
152
+        public static void Move(this IAgEngineEffector engine, int dx, int dy)
155
         {
153
         {
156
             engine.MoveTo(engine.X + dx, engine.Y + dy);
154
             engine.MoveTo(engine.X + dx, engine.Y + dy);
157
         }
155
         }

+ 8
- 7
uqac-ia-aspirobot/UI/UiConsole.cs View File

1
 using System;
1
 using System;
2
 using System.Runtime.InteropServices;
2
 using System.Runtime.InteropServices;
3
 using uqac_ia_aspirobot.Agent;
3
 using uqac_ia_aspirobot.Agent;
4
-using uqac_ia_aspirobot.Agent.Effectors;
4
+using uqac_ia_aspirobot.Agent.Interfaces.Effectors;
5
+using uqac_ia_aspirobot.Agent.Interfaces.Sensors;
5
 using uqac_ia_aspirobot.Extensions;
6
 using uqac_ia_aspirobot.Extensions;
6
 using uqac_ia_aspirobot.Interfaces;
7
 using uqac_ia_aspirobot.Interfaces;
7
 
8
 
10
     public class UiConsole : IUi
11
     public class UiConsole : IUi
11
     {
12
     {
12
         private readonly IEnvironment _environment;
13
         private readonly IEnvironment _environment;
13
-        private readonly AgEngineEffector _agEngineEffector;
14
-        private readonly AgPickedSensor _agPickedSensor;
15
-        private readonly AgBatterySensor _agBatterySensor;
16
-        private readonly AgVaccumSensor _agVaccumSensor;
14
+        private readonly IAgEngineEffector _agEngineEffector;
15
+        private readonly IAgPickedSensor _agPickedSensor;
16
+        private readonly IAgBatterySensor _agBatterySensor;
17
+        private readonly IAgVaccumSensor _agVaccumSensor;
17
         private readonly AgState _agState;
18
         private readonly AgState _agState;
18
 
19
 
19
-        public UiConsole(IEnvironment environment, AgEngineEffector agEngineEffector, AgPickedSensor agPickedSensor,
20
-            AgBatterySensor agBatterySensor, AgVaccumSensor agVaccumSensor, AgState agState)
20
+        public UiConsole(IEnvironment environment, IAgEngineEffector agEngineEffector, IAgPickedSensor agPickedSensor,
21
+            IAgBatterySensor agBatterySensor, IAgVaccumSensor agVaccumSensor, AgState agState)
21
         {
22
         {
22
             _environment = environment;
23
             _environment = environment;
23
             _agEngineEffector = agEngineEffector;
24
             _agEngineEffector = agEngineEffector;

Loading…
Cancel
Save