OpenClonk
C4PropertyPath.cpp
Go to the documentation of this file.
1 /*
2 * OpenClonk, http://www.openclonk.org
3 *
4 * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
5 * Copyright (c) 2013, The OpenClonk Team and contributors
6 *
7 * Distributed under the terms of the ISC license; see accompanying file
8 * "COPYING" for details.
9 *
10 * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11 * See accompanying file "TRADEMARK" for details.
12 *
13 * To redistribute this file separately, substitute the full license texts
14 * for the above references.
15 */
16 
17 #include "C4Include.h"
18 #include "editor/C4PropertyPath.h"
19 #include "script/C4Value.h"
20 #include "object/C4Object.h"
21 #include "object/C4GameObjects.h"
22 #include "object/C4DefList.h"
23 #include "object/C4Def.h"
24 #include "script/C4Effect.h"
25 #include "script/C4AulExec.h"
26 #include "editor/C4Console.h"
27 
28 
29 /* Property path for property setting synchronization */
30 
31 C4PropertyPath::C4PropertyPath(C4PropList *target) : get_path_type(PPT_Root), set_path_type(PPT_Root)
32 {
33  // Build string to set target
34  if (target)
35  {
36  // Object target
37  C4Object *obj = target->GetObject();
38  C4PropListStatic *target_static;
39  if (obj)
40  {
41  get_path.Format("Object(%d)", (int)obj->Number);
42  root = get_path;
43  }
44  else if ((target_static = target->IsStatic()))
45  {
46  // Global static prop lists: Resolve name
47  get_path = target_static->GetDataString();
48  root = get_path;
49  }
50  else
51  {
52  // Otherwise leave empty. We do not want assignments into temporary values, etc.
53  }
54  }
55 }
56 
57 C4PropertyPath::C4PropertyPath(C4Effect *fx, C4Object *target_obj) : get_path_type(PPT_Root), set_path_type(PPT_Root)
58 {
59  // Effect property path: Represent as GetEffect("name", Object(%d), index) for object effects and GetEffect("name", nil, index) for global effects
60  if (!fx) return;
61  const char *name = fx->GetName();
62  int32_t index = 0;
63  for (C4Effect *ofx = target_obj ? target_obj->pEffects : ::ScriptEngine.pGlobalEffects; ofx; ofx = ofx->pNext)
64  if (ofx == fx) break; else if (!strcmp(ofx->GetName(), name)) ++index;
65  if (target_obj)
66  {
67  get_path.Format(R"(GetEffect("%s", Object(%d), %d))", name, (int)target_obj->Number, (int)index);
68  root.Format("Object(%d)", (int)target_obj->Number);
69  }
70  else
71  {
72  get_path.Format(R"(GetEffect("%s", nil, %d))", name, (int)index);
73  root = ::Strings.P[P_Global].GetData();
74  }
75 }
76 
77 C4PropertyPath::C4PropertyPath(const C4PropertyPath &parent, int32_t elem_index) : root(parent.root)
78 {
79  get_path.Format("%s[%d]", parent.GetGetPath(), (int)elem_index);
81 }
82 
83 C4PropertyPath::C4PropertyPath(const C4PropertyPath &parent, const char *child_property)
84  : get_path_type(PPT_Property), set_path_type(PPT_Property), root(parent.root)
85 {
86  get_path.Format("%s.%s", parent.GetGetPath(), child_property);
87 }
88 
89 void C4PropertyPath::SetSetPath(const C4PropertyPath &parent, const char *child_property, C4PropertyPath::PathType path_type)
90 {
91  set_path_type = path_type;
92  if (path_type == PPT_Property)
93  set_path.Format("%s.%s", parent.GetGetPath(), child_property);
94  else if (path_type == PPT_SetFunction)
95  set_path.Format("%s->%s", parent.GetGetPath(), child_property);
96  else if (path_type == PPT_GlobalSetFunction)
97  {
98  set_path.Copy(parent.GetGetPath());
99  argument.Copy(child_property);
100  }
101  else if (path_type == PPT_RootSetFunction)
102  {
103  set_path.Format("%s->%s", parent.GetRoot(), child_property);
104  }
105  else
106  {
107  assert(false);
108  }
109 }
110 
111 void C4PropertyPath::SetProperty(const char *set_string) const
112 {
113  // Compose script to update property
114  const char *set_path_c = GetSetPath();
115  StdStrBuf script;
117  script.Format("%s(%s)", set_path_c, set_string);
119  script.Format("%s(%s,%s)", argument.getData(), set_path_c, set_string);
120  else
121  script.Format("%s=%s", set_path_c, set_string);
122  // Execute synced scripted
124 }
125 
126 void C4PropertyPath::SetProperty(const C4Value &to_val, const C4PropListStatic *ignore_reference_parent) const
127 {
128  SetProperty(to_val.GetDataString(9999999, ignore_reference_parent).getData());
129 }
130 
132 {
133  if (!get_path.getLength()) return C4VNull;
134  return AulExec.DirectExec(::ScriptEngine.GetPropList(), get_path.getData(), "resolve property", false, nullptr);
135 }
136 
138 {
139  if (!root.getLength()) return C4VNull;
140  return AulExec.DirectExec(::ScriptEngine.GetPropList(), root.getData(), "resolve property root", false, nullptr);
141 }
142 
143 void C4PropertyPath::DoCall(const char *call_string) const
144 {
145  // Compose script call
146  StdStrBuf script;
147  script.Format(call_string, get_path.getData());
148  // Execute synced scripted
150 }
151 
152 
153 /* C4PropertyCollection */
154 
156 {
157  entries.clear();
158  checked_values.clear();
159 }
160 
161 bool C4PropertyCollection::CollectPropList(C4PropList *p, const C4PropertyPath &path, C4PropertyName prop, const C4Value &val, const char *base_name)
162 {
163  // Collect prop list if it matches the condition
164  C4Value cmp;
165  if (p->GetProperty(prop, &cmp))
166  {
167  if (cmp == val)
168  {
169  // Only stuff set in the game
170  if (!p->IsFrozen())
171  {
172  entries.emplace_back(path, C4VPropList(p), base_name);
173  return true;
174  }
175  }
176  }
177  return false;
178 }
179 
180 void C4PropertyCollection::CollectPropLists(C4ValueArray *target, const C4PropertyPath &target_path, C4PropertyName prop, const C4Value &val, const char *base_name)
181 {
182  // Avoid recursion
183  if (checked_values.find(target) != checked_values.end()) return;
184  checked_values.insert(target);
185  // Check all child elements
186  for (int32_t index = 0; index < target->GetSize(); ++index)
187  {
188  const C4Value &childval = target->GetItem(index);
189  switch (childval.GetType())
190  {
191  case C4V_Array:
192  CollectPropLists(childval._getArray(), C4PropertyPath(target_path, index), prop, val, base_name);
193  break;
194  case C4V_PropList:
195  CollectPropLists(childval._getPropList(), C4PropertyPath(target_path, index), prop, val, base_name);
196  break;
197  default:
198  // nada
199  break;
200  }
201  }
202 }
203 
204 void C4PropertyCollection::CollectPropLists(C4PropList *target, const C4PropertyPath &target_path, C4PropertyName prop, const C4Value &val, const char *base_name)
205 {
206  // Avoid recursion
207  if (checked_values.find(target) != checked_values.end()) return;
208  checked_values.insert(target);
209  // Check base itself
210  if (CollectPropList(target, target_path, prop, val, base_name))
211  {
212  // No need to check children then
213  return;
214  }
215  // Check all child properties
216  for (C4String *key : target->GetSortedLocalProperties(false))
217  {
218  C4Value childval;
219  target->GetPropertyByS(key, &childval);
220  switch (childval.GetType())
221  {
222  case C4V_Array:
223  CollectPropLists(childval._getArray(), C4PropertyPath(target_path, key->GetCStr()), prop, val, base_name);
224  break;
225  case C4V_PropList:
226  CollectPropLists(childval._getPropList(), C4PropertyPath(target_path, key->GetCStr()), prop, val, base_name);
227  break;
228  default:
229  // nada
230  break;
231  }
232  }
233 }
234 
235 void C4PropertyCollection::CollectPropLists(C4PropertyName prop, const C4Value &val)
236 {
237  Clear();
238  // Walk over game content and search for matching prop lists
239  // Walk in reverse because prop lists of more permanent objects are often assigned to temporary objects
240  for (C4Object *obj : ::Objects.reverse())
241  {
242  CollectPropLists(obj, C4PropertyPath(obj), prop, val, obj->GetName());
243  for (C4Effect *fx = obj->pEffects; fx; fx = fx->pNext)
244  {
245  CollectPropLists(fx, C4PropertyPath(fx, obj), prop, val, fx->GetName());
246  }
247  }
248  for (C4Effect *fx = ::ScriptEngine.pGlobalEffects; fx; fx = fx->pNext)
249  {
250  CollectPropLists(fx, C4PropertyPath(fx, nullptr), prop, val, fx->GetName());
251  }
252 }
253 
C4AulExec AulExec
Definition: C4AulExec.cpp:29
C4AulScriptEngine ScriptEngine
Definition: C4Globals.cpp:43
C4Console Console
Definition: C4Globals.cpp:45
C4GameObjects Objects
Definition: C4Globals.cpp:48
C4StringTable Strings
Definition: C4Globals.cpp:42
@ CID_Script
Definition: C4PacketBase.h:154
C4PropertyName
@ P_Global
const C4Value C4VNull
Definition: C4Value.cpp:30
@ C4V_PropList
Definition: C4Value.h:28
@ C4V_Array
Definition: C4Value.h:30
C4Value C4VPropList(C4PropList *p)
Definition: C4Value.h:242
C4Value DirectExec(C4PropList *p, const char *szScript, const char *szContext, bool fPassErrors=false, C4AulScriptContext *context=nullptr, bool parse_function=false)
Definition: C4AulExec.cpp:1012
C4PropListStatic * GetPropList()
Definition: C4Aul.h:151
C4Effect * pGlobalEffects
Definition: C4Aul.h:144
C4EditCursor EditCursor
Definition: C4Console.h:90
void EMControl(enum C4PacketType eCtrlType, class C4ControlPacket *pCtrl)
C4Effect * pNext
Definition: C4Effect.h:75
C4Effect * pEffects
Definition: C4Object.h:155
const ReverseView reverse() const
Definition: C4ObjectList.h:104
bool IsFrozen() const
Definition: C4PropList.h:135
virtual C4Object * GetObject()
Definition: C4PropList.cpp:636
virtual const char * GetName() const
Definition: C4PropList.cpp:618
virtual class C4PropListStatic * IsStatic()
Definition: C4PropList.h:89
virtual bool GetPropertyByS(const C4String *k, C4Value *pResult) const
Definition: C4PropList.cpp:726
std::vector< C4String * > GetSortedLocalProperties(bool add_prototype=true) const
Definition: C4PropList.cpp:545
bool GetProperty(C4PropertyName k, C4Value *pResult) const
Definition: C4PropList.h:105
StdStrBuf GetDataString() const
Definition: C4PropList.cpp:229
void SetProperty(const char *set_string) const
C4Value ResolveValue() const
C4Value ResolveRoot() const
enum C4PropertyPath::PathType set_path_type
const char * GetSetPath() const
enum C4PropertyPath::PathType get_path_type
const char * GetRoot() const
const char * GetGetPath() const
void SetSetPath(const C4PropertyPath &parent, const char *child_property, PathType path_type)
void DoCall(const char *call_string) const
StdStrBuf GetData() const
Definition: C4StringTable.h:50
C4String P[P_LAST]
const C4Value & GetItem(int32_t iElem) const
Definition: C4ValueArray.h:38
int32_t GetSize() const
Definition: C4ValueArray.h:36
StdStrBuf GetDataString(int depth=10, const class C4PropListStatic *ignore_reference_parent=nullptr) const
Definition: C4Value.cpp:131
C4PropList * _getPropList() const
Definition: C4Value.h:129
C4V_Type GetType() const
Definition: C4Value.h:161
C4ValueArray * _getArray() const
Definition: C4Value.h:127
const char * getData() const
Definition: StdBuf.h:442
void Copy()
Definition: StdBuf.h:467
size_t getLength() const
Definition: StdBuf.h:445
void Format(const char *szFmt,...) GNUC_FORMAT_ATTRIBUTE_O
Definition: StdBuf.cpp:174