├── Core
├── BotActions.cs
├── BotControl.cs
├── BotPerception.cs
└── IBotDeliberator.cs
├── LICENSE
├── README.md
└── SideComponents
├── ArgsList.cs
├── SmartObjects.cs
└── StateBook.cs
/Core/BotActions.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System.Collections;
3 | using System;
4 | using System.Collections.Generic;
5 |
6 | ///
7 | /// This class is an action interface for the BotControl.
8 | ///
9 | ///
10 | /// The action must be registerd in this class through the RegisterNewAction
11 | /// function.
12 | ///
13 | /// These actions can be invoked by BotControl.
14 | ///
15 | /// \author Davide Aversa
16 | /// \version 2.0
17 | /// \date 2013
18 | /// \pre This class needs an instance BotControl.
19 | [RequireComponent(typeof(BotControl))]
20 | public class BotActions : MonoBehaviour
21 | {
22 |
23 | ///
24 | /// Dictionary that map commands strings to actions.
25 | ///
26 | private Dictionary> actions;
27 |
28 | ///
29 | /// The abort action.
30 | ///
31 | private Action abortAction;
32 |
33 | ///
34 | /// True if the last action is completed.
35 | ///
36 | private bool actionComplete = true;
37 |
38 | ///
39 | /// True if the last action is completed successfully.
40 | ///
41 | private bool actionSuccess = true;
42 |
43 | ///
44 | /// A reference to a BotControl instance.
45 | ///
46 | private BotControl parentControl;
47 |
48 | void Awake ()
49 | {
50 | parentControl = gameObject.GetComponent ();
51 | actions = new Dictionary> ();
52 | }
53 |
54 | ///
55 | /// Registers an action to the BotActions component.
56 | ///
57 | ///
58 | /// This operation is needed in order to execute the desired action.
59 | ///
60 | ///
61 | /// The command associated to the action.
62 | ///
63 | ///
64 | /// A function that execute the desired action.
65 | ///
66 | public void RegisterNewAction (string command, Action action)
67 | {
68 | Debug.Log ("BotACTIONS: Registering " + command + " command");
69 | actions [command] = action;
70 | }
71 |
72 | ///
73 | /// Register the action that has to be executed to block every other action
74 | /// in progress.
75 | ///
76 | ///
77 | /// The "stop" action function.
78 | ///
79 | public void RegisterAbortAction (Action abortAction)
80 | {
81 | this.abortAction = abortAction;
82 | }
83 |
84 | ///
85 | /// Perform the given action (if exists).
86 | ///
87 | ///
88 | /// True if the action can be executed. False otherwise.
89 | ///
90 | ///
91 | /// The action that must be executed.
92 | ///
93 | public bool DoAction (string fullCommand)
94 | {
95 | Debug.Log ("Action Received: " + fullCommand);
96 | string[] commands = fullCommand.Split (' ');
97 | if (fullCommand == "stop") {
98 | abortAction.Invoke ();
99 | return true;
100 | }
101 | if (actionComplete && actions.ContainsKey (commands [0])) {
102 | actionComplete = false;
103 | actionSuccess = false;
104 | actions [commands [0]].Invoke (commands);
105 | }
106 | return false;
107 | }
108 |
109 | ///
110 | /// Check if the lasts the action is complete.
111 | ///
112 | ///
113 | /// True if the last action is completed. False otherwise.
114 | ///
115 | public bool LastActionComplete ()
116 | {
117 | return actionComplete;
118 | }
119 |
120 | ///
121 | /// Check if the last action is completed succesfully.
122 | ///
123 | ///
124 | /// True if the last action is completed succesfully. False otherwise.
125 | ///
126 | public bool LastActionCompletedSuccessfully ()
127 | {
128 | return actionComplete && actionSuccess;
129 | }
130 |
131 | ///
132 | /// Notify to BotAction that the action is complete.
133 | ///
134 | public void NotifyActionComplete (string action)
135 | {
136 | actionComplete = true;
137 | NotifyAction(action);
138 | }
139 |
140 | ///
141 | /// Notify to BotAction that the action is completed succesfully.
142 | ///
143 | public void NotifyActionSuccess ()
144 | {
145 | actionSuccess = true;
146 | }
147 |
148 | ///
149 | /// Notify the action to the BotController.
150 | ///
151 | ///
152 | /// The name of action succesfully completed.
153 | /// (
154 | private void NotifyAction (string action)
155 | {
156 | parentControl.NotifyAction (action);
157 | }
158 |
159 | }
160 |
--------------------------------------------------------------------------------
/Core/BotControl.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System;
3 | using System.Collections;
4 | using System.Collections.Generic;
5 |
6 | /**
7 | * The main brain of a Bot.
8 | *
9 | * The Bot Controller class is the core of the Bot AI. It is the nexus between all the AI elements
10 | * like perception, action and planning/behavior components.
11 | *
12 | * \author Davide Aversa
13 | * \version 1.0
14 | * \date 2013
15 | */
16 | public class BotControl : MonoBehaviour
17 | {
18 |
19 | // CONTROL INSPECTOR PARAMETERS
20 | public bool onDemand = false; //If true the think loop must be executed on demand.
21 | public float thinkTick = 1; //Time interval between a think cicle.
22 | public string deliberatorName; //Name of the IBotDeliberator implementation.
23 |
24 | private BotActions botActions; //Reference to the BotAction component.
25 | private IBotDeliberator deliberator; //Reference to a IBotDeliberator interface.
26 |
27 | private List objectInFov; // Contains the list of object in the FOV.
28 |
29 | // STATE
30 | private enum Status { IDLE, EXECUTING };
31 | private Status controlStatus; // Controller Status.
32 |
33 | //public StateBook internalKnowledge;
34 |
35 | // Use this for initialization
36 | protected void Awake()
37 | {
38 | controlStatus = Status.IDLE;
39 | objectInFov = new List();
40 | botActions = gameObject.GetComponent();
41 | deliberator = gameObject.GetComponent(deliberatorName) as IBotDeliberator;
42 | // Run Thread Function Every `n` second
43 | if (!onDemand) {
44 | InvokeRepeating("ThinkLoop", 0, thinkTick);
45 | }
46 | }
47 |
48 | /**
49 | * CheckCondition parse a condition formula and return a single boolean value.
50 | *
51 | * TODO: Define formula syntax.
52 | *
53 | * \param condition The input condition.
54 | * \return The thruth value for the condition formula.
55 | */
56 | public bool CheckCondition(string condition) {
57 | // PARSE AND
58 | string[] andConditions = condition.Split('&');
59 | if (andConditions.Length > 1) {
60 | foreach (string c in andConditions) {
61 | if (!CheckCondition(c)) return false;
62 | }
63 | return true;
64 | }
65 | // PARSE OR
66 | string[] orConditions = condition.Split('|');
67 | if (orConditions.Length > 1) {
68 | foreach (string c in orConditions) {
69 | if (CheckCondition(c)) return true;
70 | }
71 | return false;
72 | }
73 | // PARSE CONDITION
74 | bool not = condition.StartsWith("!");
75 | if (not) condition = condition.Substring(1);
76 | switch (condition) {
77 | default :
78 | return false; //TODO: Default true or default false?
79 | }
80 | }
81 |
82 | // TODO: ThinkLoop
83 | public void ThinkLoop() {
84 | if (controlStatus == Status.IDLE) {
85 | string nextaction = deliberator.GetNextAction();
86 | Debug.Log("NEXT ACTION: " + nextaction);
87 | if (nextaction != "")
88 | {
89 | controlStatus = Status.EXECUTING;
90 | botActions.DoAction(nextaction);
91 | }
92 | }
93 | }
94 |
95 | public void DoAction(string command)
96 | {
97 | botActions.DoAction(command);
98 | }
99 |
100 | /**
101 | * Used by BotAction to notify the controller about the success of the given action.
102 | *
103 | * \param action The action notification string (TODO: to be defined).
104 | */
105 | public void NotifyAction(string action) {
106 | controlStatus = Status.IDLE;
107 | switch (action)
108 | {
109 | case "grab":
110 | Debug.Log("Grab Completed");
111 | break;
112 | default:
113 | break;
114 | }
115 | }
116 |
117 | /**
118 | * Notification callback for an object in the FOV which are changing its state.
119 | *
120 | * \param The changing object.
121 | */
122 | public void NotifyObjectChange(GameObject obj)
123 | {
124 | if (System.Array.IndexOf(deliberator.interestType,obj.tag) != -1)
125 | {
126 | deliberator.NotifyObjectChange(obj);
127 | }
128 | }
129 |
130 | public void NotifyObjectChange(GameObject obj, bool isLeaving)
131 | {
132 | if (System.Array.IndexOf(deliberator.interestType,obj.tag) != -1)
133 | {
134 | deliberator.NotifyObjectChange(obj, isLeaving);
135 | }
136 | }
137 |
138 | }
139 |
--------------------------------------------------------------------------------
/Core/BotPerception.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 |
5 | ///
6 | /// Implement a perception by collision system for the attached object.
7 | ///
8 | /// \author Davide Aversa
9 | /// \version 1.0
10 | /// \date 2013
11 | /// \pre This component must be attached to a *perception mesh* attached to the bot.
12 | /// The bot must have a BotControl instance attached to itself.
13 | [RequireComponent (typeof(Collider))]
14 | public class BotPerception : MonoBehaviour
15 | {
16 |
17 | ///
18 | /// Eanble the built-in deep test for the entering object.
19 | ///
20 | public bool raycastTest = true;
21 |
22 | public string interestType;
23 |
24 | ///
25 | /// A reference to the IBotControl instance attache to the bot.
26 | /// (
27 | private BotControl parentControl;
28 |
29 | ///
30 | /// List of the object inside the perception mesh.
31 | ///
32 | private List objectInMesh;
33 |
34 | protected void Awake ()
35 | {
36 | // Extract the controller component from the parent object.
37 | parentControl = gameObject.transform.parent.gameObject.GetComponent ();
38 | objectInMesh = new List ();
39 | }
40 |
41 | // Update is called once per frame
42 | // TODO: Remove.
43 | void Update ()
44 | {
45 |
46 | }
47 |
48 | ///
49 | /// Raises the trigger enter event.
50 | ///
51 | ///
52 | /// The object which is entering the perception mesh.
53 | ///
54 | void OnTriggerEnter (Collider other)
55 | {
56 | GameObject obj = other.gameObject; // Reference to the entering object.
57 | if (interestType != "" && obj.tag != interestType) return;
58 | if (raycastTest) {
59 | GameObject bot = gameObject.transform.parent.gameObject; // Reference to the bot object.
60 | if (!RayCastVisibility (obj, bot)) {
61 | return;
62 | }
63 | }
64 | SmartObjects so = obj.GetComponent ();
65 | if (so != null) {
66 | so.AddObserver (this);
67 | }
68 | // Add to the object list.
69 | objectInMesh.Add (obj);
70 | // Notify ingress to the controller.
71 | parentControl.NotifyObjectChange(obj);
72 | }
73 |
74 | ///
75 | /// Raises the trigger exit event.
76 | ///
77 | ///
78 | /// The object which is leaving the perception mesh.
79 | ///
80 | void OnTriggerExit (Collider other)
81 | {
82 | GameObject obj = other.gameObject;
83 | SmartObjects so = obj.GetComponent ();
84 | if (so != null) {
85 | so.RemoveObserver (this);
86 | }
87 | // Add to the object list.
88 | objectInMesh.Remove (obj);
89 | // Notify ingress to the controller.
90 | parentControl.NotifyObjectChange(obj,true);
91 | }
92 |
93 | ///
94 | /// Notifies the object change.
95 | ///
96 | ///
97 | /// The changing game object.
98 | ///
99 | ///
100 | /// The object type.
101 | ///
102 | public void NotifyObjectChange (GameObject go, string type)
103 | {
104 | parentControl.NotifyObjectChange(go);
105 | }
106 |
107 | ///
108 | /// Check for raycast visibility.
109 | ///
110 | ///
111 | /// True if the object is visible from the bot. False otherwise.
112 | ///
113 | ///
114 | /// The target object.
115 | ///
116 | ///
117 | /// The bot object.
118 | ///
119 | private bool RayCastVisibility (GameObject obj, GameObject bot)
120 | {
121 | RaycastHit hit = new RaycastHit ();
122 | Vector3 offset = new Vector3 (0, 1, 0);
123 | // Direction between obj and other.
124 | Vector3 direction = (obj.transform.position - (bot.transform.position + offset)).normalized;
125 | Physics.Raycast (bot.transform.position + offset, direction, out hit);
126 | return hit.transform.gameObject.Equals (obj);
127 | }
128 |
129 | }
130 |
--------------------------------------------------------------------------------
/Core/IBotDeliberator.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System.Collections;
3 |
4 | ///
5 | /// A public interface for the bot higher level.
6 | ///
7 | ///
8 | /// IBotDeliberator offers a communication interface between BotControl
9 | /// and the higher decisional level.
10 | ///
11 | /// \author Davide Aversa
12 | /// \version 1.0
13 | /// \date 2013
14 | public interface IBotDeliberator {
15 |
16 | ///
17 | /// Return the next bot action.
18 | ///
19 | ///
20 | /// The action is computed by the deliberator according to the information
21 | /// available in BotController.
22 | ///
23 | ///
24 | /// The next valid (?) bot action.
25 | ///
26 | string GetNextAction();
27 |
28 | ///
29 | /// Notifies the object change.
30 | ///
31 | ///
32 | /// The changing object.
33 | ///
34 | ///
35 | /// The object type.
36 | ///
37 | ///
38 | /// Set this to true if the notification comes from a leaving object.
39 | ///
40 | void NotifyObjectChange(GameObject obj, bool isLeaving = false);
41 |
42 | ///
43 | /// List of the interesting object types for the deliberator.
44 | ///
45 | ///
46 | /// The type of the interest for the deliberator.
47 | ///
48 | string[] interestType { get; }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Davide Aversa
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Unity-CogBot
2 |
3 | ## What is?
4 |
5 | **Unity-CogBot** is a free implementation of the CogBot NPC architecture for the popular 3D game engine [Unity3D][1].
6 |
7 | CogBot is a modular architecture for NPC development that ensures *modularity* and *reusability* of the code.
8 |
9 | It is based on the standard cognitive AI agents components: **perception**, **control**, **deliberation** and **action**.
10 |
11 | [1]: http://unity3d.com/
--------------------------------------------------------------------------------
/SideComponents/ArgsList.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System.Collections;
3 |
4 | /*!
5 | * ArgsList stores an ordered list of arguments in an efficient way.
6 | */
7 | public class ArgsList {
8 |
9 | private string[] args;
10 |
11 | // INDEXER. See http://msdn.microsoft.com/en-us/library/6x16t2tx.aspx for
12 | // more information.
13 | /*!
14 | * Indexer for the ArgsList class.
15 | */
16 | public string this[int i]
17 | {
18 | get
19 | {
20 | return args[i];
21 | }
22 |
23 | set
24 | {
25 | throw new System.InvalidOperationException("ArgsList are immutable!");
26 | }
27 | }
28 |
29 | /*!
30 | * Return the number of arguments in the list.
31 | */
32 | public int Length
33 | {
34 | get { return args.Length; }
35 | }
36 |
37 | /*!
38 | * Constructor.
39 | *
40 | * Build an ArgsList from a list of strings.
41 | */
42 | public ArgsList(params string[] args)
43 | {
44 | this.args = args;
45 | }
46 |
47 | /*!
48 | * Constructor.
49 | *
50 | * Build an ArgsList from a single string.
51 | *
52 | * @param args The input string.
53 | * @param separator The separator character between the arguments.
54 | */
55 | public ArgsList(string args, char separator = ' ')
56 | {
57 | this.args = args.Split(separator);
58 | }
59 |
60 | public string[] ToStringArray()
61 | {
62 | return args.Clone() as string[];
63 | }
64 |
65 | public override bool Equals(object obj)
66 | {
67 | // If parameter is null return false.
68 | if (obj == null)
69 | {
70 | return false;
71 | }
72 |
73 | // If parameter cannot be cast to ArgsList return false.
74 | ArgsList otherList = obj as ArgsList;
75 | if ((System.Object)otherList == null)
76 | {
77 | return false;
78 | }
79 |
80 | // Return true if other have the same elements in the same order.
81 | if (otherList.Length != this.Length) return false;
82 | for (int i = 0; i < this.Length; ++i)
83 | {
84 | if (otherList[i] != this[i]) return false;
85 | }
86 | return true;
87 | }
88 |
89 | public override int GetHashCode()
90 | {
91 | int prime = 31;
92 | int result = 1;
93 | foreach (string s in args)
94 | {
95 | result = prime * result + s.GetHashCode();
96 | }
97 | return result;
98 | }
99 |
100 |
101 | }
102 |
--------------------------------------------------------------------------------
/SideComponents/SmartObjects.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 |
5 | ///
6 | /// A Smart Object component is used to handle stateful objects in the BotPerception
7 | /// component.
8 | ///
9 | /// \author Davide Aversa
10 | /// \version 2.0
11 | /// \date 2013
12 | public class SmartObjects : MonoBehaviour {
13 |
14 | ///
15 | /// The list of observers.
16 | ///
17 | private List observers;
18 |
19 | // Use this for initialization
20 | void Awake () {
21 | observers = new List();
22 | }
23 |
24 | ///
25 | /// Add an observer to the object.
26 | ///
27 | ///
28 | /// The observer perception component.
29 | ///
30 | public void AddObserver(BotPerception obs)
31 | {
32 | observers.Add(obs);
33 | }
34 |
35 | ///
36 | /// Remove an observer from the object.
37 | ///
38 | ///
39 | /// The observer perception component.
40 | ///
41 | public void RemoveObserver(BotPerception obs)
42 | {
43 | observers.Remove(obs);
44 | }
45 |
46 | ///
47 | /// Notifies the state change.
48 | ///
49 | public void NotifyStateChange()
50 | {
51 | foreach (BotPerception bp in observers)
52 | {
53 | bp.NotifyObjectChange(gameObject, gameObject.tag);
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/SideComponents/StateBook.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 |
6 | /*!
7 | * StateBook stores informations about predicative conditions.
8 | *
9 | * For example StateBook can store predicates like `Location(2,3,bot1)` or
10 | * `Hold(gun)` usefull in deliberative algorithm and tecniques like planning
11 | * or FSM.
12 | *
13 | * Statebook class is easy to use. To add a conditions you just have to
14 | *
15 | * statebook["name:arg1 arg2 arg3"] = true;
16 | *
17 | * In the same way we can check the validity of a given conditions with
18 | *
19 | * statebook["name:arg1 arg2 arg3"];
20 | *
21 | * Statebook use the Closed-World Assumption.
22 | */
23 | public class StateBook : MonoBehaviour {
24 |
25 | private Dictionary> conditionsDB;
26 | private Dictionary predicatesArity;
27 |
28 | // Use this for initialization
29 | void Start () {
30 | conditionsDB = new Dictionary>();
31 | predicatesArity = new Dictionary();
32 |
33 | /* TEST */
34 | this["bob:1 2 cane"] = true;
35 | this["bob:1 3 pollo"] = true;
36 | this["bob:3 5 cane"] = true;
37 | foreach (string[] ss in this.GetEnumerator("bob", "$1 $2 cane"))
38 | {
39 | Debug.Log(ss[0] + " " + ss[1]);
40 | }
41 | }
42 |
43 | // Update is called once per frame
44 | void Update () {
45 |
46 | }
47 |
48 | /*!
49 | * Query the database for the validity of a given expression.
50 | *
51 | * \param name The predicate name.
52 | * \param args The list of arguments of the predicate.
53 | * \retval true If the query is valid in the DB.
54 | * \retvale false Otherwise.
55 | */
56 | public bool Query(string name, string[] args)
57 | {
58 | if (!conditionsDB.ContainsKey(name)) return false;
59 | return conditionsDB[name].Contains(new ArgsList(args));
60 | }
61 |
62 | /*!
63 | * Query the database for the validity of a given expression.
64 | *
65 | * \param name The predicate name.
66 | * \param args The list of arguments of the predicate separated by spaces.7
67 | * \retval true If the query is valid in the DB.
68 | * \retvale false Otherwise.
69 | */
70 | public bool Query(string name, string args)
71 | {
72 | if (!conditionsDB.ContainsKey(name)) return false;
73 | return conditionsDB[name].Contains(new ArgsList(args));
74 | }
75 |
76 | /*!
77 | * Query the database for the validity of a given expression.
78 | *
79 | * \param query The query string. The format is "name:arg1 arg2 ...".
80 | * \retval true If the query is valid in the DB.
81 | * \retvale false Otherwise.
82 | */
83 | public bool Query(string query)
84 | {
85 | string[] splitted = query.Split(':');
86 | return this.Query(splitted[0], splitted[1]);
87 | }
88 |
89 | /*!
90 | * Set the given query with the given value.
91 | *
92 | * \param query The input query string.
93 | * \param value The desired value.
94 | */
95 | public void SetValue(string query, bool value)
96 | {
97 | Debug.Log(query);
98 | string[] splitted = query.Split(':');
99 | string theName = splitted[0];
100 | string args = splitted[1];
101 | int argsNum = args.Split(' ').Length;
102 | // If true add the arglist to the list. If false remove it.
103 | if (value == true)
104 | {
105 | // If the condition do not exist, create it.
106 | if (!conditionsDB.ContainsKey(theName))
107 | {
108 | conditionsDB.Add(theName, new HashSet());
109 | predicatesArity.Add(theName, argsNum);
110 | }
111 | // You cannot add an arglist with different number of arguments for
112 | // an existent condition.
113 | if (argsNum != predicatesArity[theName])
114 | {
115 | throw new System.InvalidOperationException("Invalid arguments number!");
116 | }
117 | conditionsDB[theName].Add(new ArgsList(args));
118 | }
119 | else
120 | {
121 | // If you set a false condition you are removing a positive condition
122 | // in the DB (if any).
123 | if (!conditionsDB.ContainsKey(theName))
124 | return;
125 | conditionsDB[theName].Remove(new ArgsList(args));
126 | }
127 | }
128 |
129 | // ENUMERATORS
130 | /*!
131 | * Enumerator for the properties name in the database.
132 | */
133 | public System.Collections.IEnumerable GetConditionsEnumerator()
134 | {
135 | foreach (KeyValuePair> entry in conditionsDB)
136 | {
137 | yield return entry.Key;
138 | }
139 | }
140 |
141 | /*!
142 | * Enumerator for a given property.
143 | *
144 | * This enumerator return all the argument tuple associated to a given
145 | * condition.
146 | *
147 | * /param name The condition name.
148 | */
149 | public System.Collections.IEnumerable GetEnumerator(string name)
150 | {
151 | foreach (ArgsList al in conditionsDB[name])
152 | {
153 | yield return al.ToStringArray();
154 | }
155 | }
156 |
157 | /*
158 | * Enumerator for selective query.
159 | *
160 | * This enumerator return all the argument tuple associated to a given
161 | * condition that match the given template.
162 | *
163 | * A template is a string of the form "$var1 fixed1 fixed2 $var2 ..." where
164 | * the element starting with the $ symbol are variable and the fixed
165 | * ones must match the database argument.
166 | *
167 | * \param name The property name.
168 | * \param template The template string. *
169 | */
170 | public System.Collections.IEnumerable GetEnumerator(string name, string template)
171 | {
172 | if (conditionsDB.ContainsKey(name))
173 | {
174 | int unknow = 0;
175 | string[] splitted = template.Split(' ');
176 | foreach (string s in splitted)
177 | {
178 | if (s.StartsWith("$"))
179 | {
180 | unknow++;
181 | }
182 | }
183 | foreach (ArgsList al in conditionsDB[name])
184 | {
185 | string[] result = new string[unknow];
186 | int idx = 0;
187 | bool iPickThis = true;
188 | for (int i = 0; i < al.Length; ++i)
189 | {
190 | if (splitted[i].StartsWith("$"))
191 | {
192 | result[idx] = al[i];
193 | idx++;
194 | }
195 | else
196 | {
197 | // If one item is
198 | iPickThis = iPickThis && (splitted[i] == al[i]);
199 | if (!iPickThis) break;
200 | }
201 | }
202 | if (iPickThis) yield return result;
203 | }
204 | }
205 | }
206 |
207 | // INDEXERS
208 | // Query string is in the form: "condition_name:arg1 arg2 arg3 ..."
209 | public bool this[string query]
210 | {
211 | get
212 | {
213 | return Query(query);
214 | }
215 |
216 | set
217 | {
218 | SetValue(query, value);
219 | }
220 | }
221 | }
222 |
--------------------------------------------------------------------------------