Crossfire Server, Trunk
MessageFile.cpp
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 2022 the Crossfire Development Team
5  *
6  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
7  * welcome to redistribute it under certain conditions. For details, please
8  * see COPYING and LICENSE.
9  *
10  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
11  */
12 
13 #include <qiodevice.h>
14 #include <qfile.h>
15 #include <qscriptengine.h>
16 #include <QDebug>
17 
18 #include "MessageFile.h"
19 #include "quests/QuestWrapper.h"
20 
21 #include "global.h"
22 
24 {
25  myIsModified = false;
26 }
27 
28 MessageRule::MessageRule(const MessageRule& original) : QObject()
29 {
30  myIsModified = true;
31  myMatch = original.match();
32  myPreconditions = original.preconditions();
33  myMessages = original.messages();
34  myPostconditions = original.postconditions();
35  myReplies = original.replies();
36 }
37 
39 {
40 }
41 
42 const QString& MessageRule::comment() const
43 {
44  return myComment;
45 }
46 
47 void MessageRule::setComment(const QString& comment)
48 {
50 }
51 
52 const QStringList& MessageRule::match() const
53 {
54  return myMatch;
55 }
56 
57 QStringList& MessageRule::match()
58 {
59  return myMatch;
60 }
61 
62 void MessageRule::setMatch(const QStringList& match)
63 {
64  myMatch = match;
65 }
66 
67 const QList<QStringList>& MessageRule::preconditions() const
68 {
69  return myPreconditions;
70 }
71 
72 void MessageRule::setPreconditions(const QList<QStringList>& preconditions)
73 {
75 }
76 
77 const QList<QStringList>& MessageRule::postconditions() const
78 {
79  return myPostconditions;
80 }
81 
82 void MessageRule::setPostconditions(const QList<QStringList>& postconditions)
83 {
85 }
86 
87 const QStringList& MessageRule::messages() const
88 {
89  return myMessages;
90 }
91 
92 void MessageRule::setMessages(const QStringList& messages)
93 {
95 }
96 
97 const QStringList& MessageRule::include() const
98 {
99  return myInclude;
100 }
101 
102 void MessageRule::setInclude(const QStringList& include)
103 {
104  myInclude = include;
105 }
106 
107 const QList<QStringList>& MessageRule::replies() const
108 {
109  return myReplies;
110 }
111 
112 void MessageRule::setReplies(const QList<QStringList>& replies)
113 {
114  myReplies = replies;
115 }
116 
118 {
119  return myIsModified;
120 }
121 
122 void MessageRule::setModified(bool modified)
123 {
124  myIsModified = modified;
125 }
126 
127 MessageFile::MessageFile(AssetWrapper *parent, const QString& path) : AssetWrapper(parent, "Message") {
128  myPath = path;
129  myIsModified = false;
130 }
131 
133 {
134  qDeleteAll(myRules);
135 }
136 
138 {
139  MessageFile* copy = new MessageFile(nullptr, myPath);
140  copy->myLocation = myLocation;
141  for (auto rule : myRules)
142  copy->myRules.append(new MessageRule(*rule));
143  copy->myMaps = myMaps;
144  return copy;
145 }
146 
147 void MessageFile::copy(const MessageFile* other)
148 {
149  myPath = other->myPath;
150  myLocation = other->myLocation;
151  qDeleteAll(myRules);
152  myRules.clear();
153  for (auto rule : other->myRules)
154  myRules.append(new MessageRule(*rule));
155  myMaps = other->myMaps;
156 }
157 
158 const QString& MessageFile::location() const
159 {
160  return myLocation;
161 }
162 
163 const QString& MessageFile::path() const
164 {
165  return myPath;
166 }
167 
168 void MessageFile::setPath(const QString& path)
169 {
170  if (myPath != path)
171  {
172  myPath = path;
173  setModified();
174  }
175 }
176 
177 void MessageFile::setLocation(const QString& location)
178 {
179  if (myLocation != location)
180  {
182  setModified();
183  }
184 }
185 
186 void convert(QScriptValue& value, QList<QStringList>& list)
187 {
188  list.clear();
189  int length = value.property("length").toInt32();
190  for (int l = 0; l < length; l++)
191  {
192  QStringList items;
193  QScriptValue sub = value.property(l);
194 
195  int subl = sub.property("length").toInt32();
196  for (int s = 0; s < subl; s++)
197  items.append(sub.property(s).toString());
198 
199  list.append(items);
200  }
201 }
202 
204 {
205  QString full = QString("%1/%2/%3").arg(settings.datadir, settings.mapdir, myPath);
206  QFile file(full);
207  file.open(QIODevice::ReadOnly);
208 
209  QByteArray data = file.readAll();
210  if (data.size() == 0)
211  return false;
212  QString script = data;
213  if (!script.startsWith('['))
214  script = "[" + script + "]";
215 
216  QScriptValue value;
217  QScriptEngine engine;
218  value = engine.evaluate(script);
219  if (engine.hasUncaughtException())
220  {
221  qDebug() << "message file evaluate error" << myPath << engine.uncaughtException().toString();
222  return false;
223  }
224 
225  QScriptValue first = value.property(0);
226  myLocation = first.property("location").toString();
227 
228  QScriptValue rules = first.property("rules");
229  int length = rules.property("length").toInt32();
230  for (int r = 0; r < length; r++)
231  {
232  MessageRule* rule = new MessageRule();
233  myRules.append(rule);
234  QScriptValue v = rules.property(r);
235 
236  rule->setComment(v.property("comment").toString());
237 
238  QStringList items;
239  qScriptValueToSequence(v.property("match"), items);
240  rule->setMatch(items);
241 
242  QList<QStringList> lists;
243  QScriptValue p = v.property("pre");
244  convert(p, lists);
245  rule->setPreconditions(lists);
246 
247  p = v.property("post");
248  convert(p, lists);
249  rule->setPostconditions(lists);
250 
251  items.clear();
252  qScriptValueToSequence(v.property("include"), items);
253  rule->setInclude(items);
254 
255  items.clear();
256  qScriptValueToSequence(v.property("msg"), items);
257  rule->setMessages(items);
258 
259  p = v.property("replies");
260  convert(p, lists);
261  rule->setReplies(lists);
262  }
263  return true;
264 }
265 
266 QList<MessageRule*>& MessageFile::rules()
267 {
268  return myRules;
269 }
270 
271 QList<CREMapInformation*>& MessageFile::maps()
272 {
273  return myMaps;
274 }
275 
276 QString convert(const QString& text)
277 {
278  QString tmp(text);
279  return tmp.replace('"', "\\\"").replace('\n', "\\n");
280 }
281 
282 QString convert(const QStringList& list)
283 {
284  QStringList one;
285  foreach(const QString& line, list)
286  {
287  one.append("\"" + convert(line) + "\"");
288  }
289  return "[" + one.join(", ") + "]";
290 }
291 
292 QString convert(const QList<QStringList>& data)
293 {
294  QStringList lines;
295 
296  foreach(const QStringList& list, data)
297  {
298  lines.append(convert(list));
299  }
300 
301  return "[" + lines.join(", ") + "]";
302 }
303 
304 QString convert(const MessageRule* rule)
305 {
306  QString result;
307 
308  if (!rule->include().isEmpty())
309  {
310  result += "{\n \"include\" : " + convert(rule->include());
311  if (!rule->preconditions().isEmpty())
312  result += ",\n \"pre\" : " + convert(rule->preconditions());
313  result += "\n }";
314  return result;
315  }
316 
317  result += "{\n";
318 
319  if (!rule->comment().isEmpty())
320  {
321  result += " \"comment\" : \"";
322  result += convert(rule->comment());
323  result += "\",\n";
324  }
325 
326  result += " \"match\" : ";
327  result += convert(rule->match());
328 
329  result += ",\n \"pre\" : ";
330  result += convert(rule->preconditions());
331 
332  result += ",\n \"post\" : ";
333  result += convert(rule->postconditions());
334 
335  result += ",\n \"msg\" : ";
336  result += convert(rule->messages());
337 
338  if (!rule->replies().isEmpty())
339  {
340  result += ",\n \"replies\" : ";
341  result += convert(rule->replies());
342  }
343 
344  result += "\n }";
345 
346  return result;
347 }
348 
350 {
351  bool one = myIsModified;
352  foreach(MessageRule* rule, myRules)
353  {
354  if (rule->isModified())
355  {
356  one = true;
357  break;
358  }
359  }
360  if (!one)
361  return;
362 
363  qDebug() << "MessageFile saving" << myPath;
364 
365  QString data = "{\n";
366  if (!myLocation.isEmpty())
367  data += " \"location\" : \"" + myLocation + "\",\n";
368  data += " \"rules\": [\n ";
369 
370  QStringList rules;
371  foreach(MessageRule* rule, myRules)
372  {
373  rules.append(convert(rule));
374  rule->setModified(false);
375  }
376 
377  data += rules.join(", ");
378  data += "\n]}\n";
379 
380  QString full = QString("%1/%2/%3").arg(settings.datadir, settings.mapdir, myPath);
381  QFile file(full);
382  file.open(QIODevice::WriteOnly | QIODevice::Truncate);
383  file.write(data.toLatin1());
384  file.close();
385 
386  setModified(false);
387 }
388 
390 {
391  return myIsModified;
392 }
393 
394 void MessageFile::setModified(bool modified)
395 {
397 }
398 
399 AssetWrapper::PossibleUse MessageFile::uses(const AssetWrapper *asset, std::string &) const {
400  auto quest = dynamic_cast<const QuestWrapper *>(asset);
401  if (quest) {
402  foreach(const MessageRule* rule, myRules) {
403  QList<QStringList> conditions = rule->preconditions();
404  conditions.append(rule->postconditions());
405  foreach(QStringList list, conditions) {
406  if (list.size() > 1 && (list[0] == "quest" || list[0] == "questdone") && list[1] == quest->wrappedItem()->quest_code) {
407  return Uses;
408  }
409  }
410  }
411  return DoesntUse;
412  }
413  return DoesntUse;
414 }
MessageFile::duplicate
MessageFile * duplicate() const
Definition: MessageFile.cpp:137
MessageFile.h
QuestWrapper.h
global.h
line
Install Bug reporting Credits so make sure you have version or later There are files involved in the automatic convert convertall and filelist py GuildList has the list of guilds for the server GuildLocations is what is used by the install script for setting up the maps It has columns in the first is the name of the no spaces The second is the region of the the third is the destination folder for the the fourth is the exit the fifth and sixth are the x and y coords within the exit the seventh eighth and ninth are the exit location for the storage hall If field seven is then it uses the same exit map as for the guild hall itself filelist py has a list of which files to process for each guild hall convert py takes all the files in filelist py and customises them to the specific guild then outputs them into a in the same order that they are listed in GuildLocations convertall py reads the lines from GuildLocations and runs line by line
Definition: README.txt:12
MessageFile::setModified
void setModified(bool modified=true)
Definition: MessageFile.cpp:394
settings
struct Settings settings
Definition: init.cpp:139
banquet.l
l
Definition: banquet.py:164
MessageFile::rules
QList< MessageRule * > & rules()
Definition: MessageFile.cpp:266
MessageRule::replies
const QList< QStringList > & replies() const
Definition: MessageFile.cpp:107
AssetWrapper::modified
void modified()
MessageRule::setMessages
void setMessages(const QStringList &messages)
Definition: MessageFile.cpp:92
MessageRule::myInclude
QStringList myInclude
Definition: MessageFile.h:60
MessageFile::setPath
void setPath(const QString &path)
Definition: MessageFile.cpp:168
guildoracle.list
list
Definition: guildoracle.py:87
mad_mage_user.file
file
Definition: mad_mage_user.py:15
Ice.tmp
int tmp
Definition: Ice.py:207
QuestWrapper
Definition: QuestWrapper.h:66
MessageRule::comment
const QString & comment() const
Definition: MessageFile.cpp:42
MessageRule::~MessageRule
virtual ~MessageRule()
Definition: MessageFile.cpp:38
MessageRule::myPreconditions
QList< QStringList > myPreconditions
Definition: MessageFile.h:57
AssetWrapper
Definition: AssetWrapper.h:25
npc_dialog.replies
replies
Definition: npc_dialog.py:105
quest
Definition: quest.py:1
MessageFile::myPath
QString myPath
Definition: MessageFile.h:111
MessageFile::parseFile
bool parseFile()
Definition: MessageFile.cpp:203
rotate-tower.result
bool result
Definition: rotate-tower.py:13
MessageRule::postconditions
const QList< QStringList > & postconditions() const
Definition: MessageFile.cpp:77
MessageFile::save
void save()
Definition: MessageFile.cpp:349
location
Install Bug reporting Credits so make sure you have version or later There are files involved in the automatic convert convertall and filelist py GuildList has the list of guilds for the server GuildLocations is what is used by the install script for setting up the maps It has columns in the first is the name of the no spaces The second is the region of the the third is the destination folder for the the fourth is the exit location(usually the world map)
script
Install Bug reporting Credits but rather whatever guild name you are using *With the current map and server there are three they and GreenGoblin *Whatever name you give the folder should but it will still use GUILD_TEMPLATE *You can change what guild it uses by editing the map files Modify Map or objects if you want to use the optional Python based Guild Storage hall The first three are on the main the next two are in the guild_hq and the final one is in hallofjoining Withe the Storage three objects are found on the main floor and the last two are in the basement It s not that but you will need a map editor You find the object that has the script
Definition: README.txt:19
navar-midane_time.data
data
Definition: navar-midane_time.py:11
MessageRule::setModified
void setModified(bool modified=true)
Definition: MessageFile.cpp:122
MessageFile::~MessageFile
virtual ~MessageFile()
Definition: MessageFile.cpp:132
MessageFile::myIsModified
bool myIsModified
Definition: MessageFile.h:110
MessageRule::myComment
QString myComment
Definition: MessageFile.h:55
MessageFile::path
QString path
Definition: MessageFile.h:71
push.match
bool match
Definition: push.py:61
MessageRule::setMatch
void setMatch(const QStringList &match)
Definition: MessageFile.cpp:62
AssetWrapper::PossibleUse
PossibleUse
Definition: AssetWrapper.h:32
MessageRule::preconditions
const QList< QStringList > & preconditions() const
Definition: MessageFile.cpp:67
MessageFile::maps
QList< CREMapInformation * > & maps()
Definition: MessageFile.cpp:271
MessageRule::setPreconditions
void setPreconditions(const QList< QStringList > &preconditions)
Definition: MessageFile.cpp:72
path
pluglist shows those as well as a short text describing each the list will simply appear empty The keyword for the Python plugin is Python plugout< keyword > Unloads a given identified by its _keyword_ So if you want to unload the Python you need to do plugout Python plugin< libname > Loads a given whose _filename_ is libname So in the case of you d have to do a plugin cfpython so Note that all filenames are relative to the default plugin path(SHARE/plugins). Console messages. ----------------- When Crossfire starts
MessageFile::uses
virtual PossibleUse uses(const AssetWrapper *asset, std::string &) const override
Definition: MessageFile.cpp:399
navar-midane_apply.messages
list messages
Definition: navar-midane_apply.py:8
AssetWrapper::Uses
@ Uses
Definition: AssetWrapper.h:32
MessageFile::myMaps
QList< CREMapInformation * > myMaps
Definition: MessageFile.h:114
convert
void convert(QScriptValue &value, QList< QStringList > &list)
Definition: MessageFile.cpp:186
MessageFile::myLocation
QString myLocation
Definition: MessageFile.h:112
MessageRule::setComment
void setComment(const QString &comment)
Definition: MessageFile.cpp:47
MessageRule::setInclude
void setInclude(const QStringList &include)
Definition: MessageFile.cpp:102
MessageFile::MessageFile
MessageFile(AssetWrapper *parent, const QString &path)
Definition: MessageFile.cpp:127
MessageRule::myReplies
QList< QStringList > myReplies
Definition: MessageFile.h:61
MessageRule::myMessages
QStringList myMessages
Definition: MessageFile.h:59
MessageFile::location
QString location
Definition: MessageFile.h:72
MessageRule::setPostconditions
void setPostconditions(const QList< QStringList > &postconditions)
Definition: MessageFile.cpp:82
autojail.value
value
Definition: autojail.py:6
MessageFile
Definition: MessageFile.h:68
MessageRule::isModified
bool isModified() const
Definition: MessageFile.cpp:117
MessageFile::setLocation
void setLocation(const QString &location)
Definition: MessageFile.cpp:177
MessageRule::match
const QStringList & match() const
Definition: MessageFile.cpp:52
MessageRule::setReplies
void setReplies(const QList< QStringList > &replies)
Definition: MessageFile.cpp:112
lists
Crossfire Protocol most of the time after the actual code was already omit certain important and possibly make life miserable any new developer or curious player should be able to find most of the relevant information here If inconsistencies are found or this documentation proves to be consider the latest server side protocol code in the public source code repository as the authoritative reference Introduction If you were ever curious enough to telnet or netcat to a Crossfire chances are you were sorely disappointed While the protocol may seem to use plain text at it actually uses a mix of ASCII and binary data This handbook attempts to document various aspects of the Crossfire protocol As consult the README file to find out how to get in touch with helpful people via mailing lists
Definition: protocol.txt:24
MessageRule::myPostconditions
QList< QStringList > myPostconditions
Definition: MessageFile.h:58
Settings::mapdir
const char * mapdir
Definition: global.h:251
MessageFile::myRules
QList< MessageRule * > myRules
Definition: MessageFile.h:113
Settings::datadir
const char * datadir
Definition: global.h:248
first
Crossfire Protocol most of the time after the actual code was already omit certain important and possibly make life miserable any new developer or curious player should be able to find most of the relevant information here If inconsistencies are found or this documentation proves to be consider the latest server side protocol code in the public source code repository as the authoritative reference Introduction If you were ever curious enough to telnet or netcat to a Crossfire chances are you were sorely disappointed While the protocol may seem to use plain text at first
Definition: protocol.txt:20
MessageRule::MessageRule
MessageRule()
Definition: MessageFile.cpp:23
MessageRule
Definition: MessageFile.h:25
AssetWrapper::DoesntUse
@ DoesntUse
Definition: AssetWrapper.h:32
MessageFile::copy
void copy(const MessageFile *other)
Definition: MessageFile.cpp:147
MessageRule::include
const QStringList & include() const
Definition: MessageFile.cpp:97
MessageRule::myIsModified
bool myIsModified
Definition: MessageFile.h:54
npc_dialog.rule
rule
Definition: npc_dialog.py:108
MessageFile::isModified
bool isModified() const
Definition: MessageFile.cpp:389
text
Crossfire Protocol most of the time after the actual code was already omit certain important and possibly make life miserable any new developer or curious player should be able to find most of the relevant information here If inconsistencies are found or this documentation proves to be consider the latest server side protocol code in the public source code repository as the authoritative reference Introduction If you were ever curious enough to telnet or netcat to a Crossfire chances are you were sorely disappointed While the protocol may seem to use plain text at it actually uses a mix of ASCII and binary data This handbook attempts to document various aspects of the Crossfire protocol As consult the README file to find out how to get in touch with helpful people via mailing and more History the communications plan was set to be a text based system It was up to the server and client to parse these messages and determine what to do These messages were assumed to be line per message At a reasonably early stage of Eric Anderson wrote a then the data itself you could send many data and after the other end could decode these commands This works fairly but I think the creation of numerous sub packets has some performance hit the eutl was not especially well so writing a client for a different platform became more Eric left to work on other products shortly after writing his which didn t really leave anyone with a full understanding of the socket code I have decided to remove the eutl dependency At least one advantage is that having this network related code directly in the client and server makes error handling a bit easier cleaner Packet Format the outside packet method the byte size for the size information is not included here Eutl originally used bytes for the size to bytes seems it makes a least some sense The actual data is something of the nature of the commands listed below It is a text followed by possible other data The remaining data can be binary it is up to the client and server to decode what it sent The commands as described below is just the data portion of the packet If writing a new remember that you must take into account the size of the packet There is no termination of other than knowing how long it should be For most everything that is sent is text This is more or less how things worked under except it packed the ints into bytes in a known order In some we handle ints as in they are sent as binary information How any command handles it is detailed below in the command description The S and C represent the direction of the we use MSB as well as any ints or shorts that get sent inside the packets All packets are defined to have at least one word of text
Definition: protocol.txt:84
MessageRule::messages
const QStringList & messages() const
Definition: MessageFile.cpp:87
ring_occidental_mages.r
r
Definition: ring_occidental_mages.py:6
MessageRule::myMatch
QStringList myMatch
Definition: MessageFile.h:56