1 /*
2
3 *************************************************************************
4
5 ArmageTron -- Just another Tron Lightcycle Game in 3D.
6 Copyright (C) 2000 Manuel Moos (manuel@moosnet.de)
7
8 **************************************************************************
9
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License
12 as published by the Free Software Foundation; either version 2
13 of the License, or (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
24 ***************************************************************************
25
26 */
27
28 #include "nConfig.h"
29 #include "nNetObject.h"
30 #include "tConsole.h"
31 #include "tSysTime.h"
32 #include <set>
33 #include <string.h>
34
nConfItemBase()35 nConfItemBase::nConfItemBase()
36 :tConfItemBase(""), lastChangeTime_(-10000), lastChangeMessage_(0), watcher_(0){}
37
38 //nConfItemBase::nConfItemBase(const char *title,const char *help)
39 // :tConfItemBase(title, help){}
40
nConfItemBase(const char * title)41 nConfItemBase::nConfItemBase(const char *title)
42 :tConfItemBase(title), lastChangeTime_(-10000), lastChangeMessage_(0), watcher_(0){}
43
~nConfItemBase()44 nConfItemBase::~nConfItemBase(){}
45
s_GetConfigMessage(nMessage & m)46 void nConfItemBase::s_GetConfigMessage(nMessage &m){
47 if (sn_GetNetState()==nSERVER){
48 nReadError(); // never accept config messages from the clients
49 }
50 else{
51 tString name;
52 m >> name;
53
54 //con << "got conf message for " << name << "\n";
55
56 tConfItemMap & confmap = ConfItemMap();
57 tConfItemMap::iterator iter = confmap.find( name );
58 if ( iter != confmap.end() )
59 {
60 tConfItemBase * item = (*iter).second;
61 nConfItemBase *netitem = dynamic_cast<nConfItemBase*> (item);
62 if (netitem)
63 {
64 // check if message was new
65 if ( tSysTimeFloat() > netitem->lastChangeTime_ + 100 || sn_Update( netitem->lastChangeMessage_, m.MessageIDBig() ) )
66 {
67 netitem->lastChangeMessage_ = m.MessageIDBig();
68 netitem->lastChangeTime_ = tSysTimeFloat();
69 netitem->NetReadVal(m);
70 }
71 else
72 {
73 static bool warn = true;
74 if ( warn )
75 con << tOutput( "$nconfig_error_ignoreold", name );
76 warn = false;
77 }
78 }
79 else
80 {
81 static bool warn = true;
82 if ( warn )
83 con << tOutput( "$nconfig_error_nonet", name );
84 warn = false;
85 }
86 }
87 else
88 {
89 static bool warn = true;
90 if ( warn )
91 con << tOutput( "$nconfig_error_unknown", name );
92 warn = false;
93 }
94 }
95 }
96
97
98 static nDescriptor transferConfig(60,nConfItemBase::s_GetConfigMessage,
99 "transfer config");
100
s_SendConfig(bool force,int peer)101 void nConfItemBase::s_SendConfig(bool force, int peer){
102 if(sn_GetNetState()==nSERVER){
103 tConfItemMap & confmap = ConfItemMap();
104 for(tConfItemMap::iterator iter = confmap.begin(); iter != confmap.end() ; ++iter)
105 {
106 tConfItemBase * item = (*iter).second;
107
108 nConfItemBase *netitem = dynamic_cast<nConfItemBase*> (item);
109 if (netitem)
110 netitem->SendConfig(force, peer);
111 }
112 }
113 }
114
SendConfig(bool force,int peer)115 void nConfItemBase::SendConfig(bool force, int peer){
116 if ( (changed || force) && sn_GetNetState()==nSERVER)
117 {
118 //con << "sending conf message for " << tConfItems(i)->title << "\n";
119 nMessage *m=new nMessage(transferConfig);
120 *m << title;
121 NetWriteVal(*m);
122 if (peer==-1)
123 {
124 m->BroadCast();
125 changed = false;
126 }
127 else
128 m->Send(peer);
129 }
130 }
131
WasChanged(bool nonDefault)132 void nConfItemBase::WasChanged( bool nonDefault ){
133 // inform watcher
134 if (this->watcher_ )
135 this->watcher_->Change( nonDefault );
136
137 SendConfig();
138 }
139
Writable()140 bool nConfItemBase::Writable()
141 {
142 // network settings are read only on the client
143 if ( sn_GetNetState() == nCLIENT )
144 return false;
145
146 // on the server, we need to check for a watcher...
147 if ( !watcher_ )
148 return true;
149
150 // delegate
151 return watcher_->Writable();
152 }
153
154 // *******************************************************************************************
155 // *
156 // * s_RevertToDefaults
157 // *
158 // *******************************************************************************************
159 //!
160 //!
161 // *******************************************************************************************
162
s_RevertToDefaults(void)163 void nConfItemBase::s_RevertToDefaults( void )
164 {
165 tConfItemMap & confmap = ConfItemMap();
166 for(tConfItemMap::iterator iter = confmap.begin(); iter != confmap.end() ; ++iter)
167 {
168 tConfItemBase * item = (*iter).second;
169 nConfItemBase *netitem = dynamic_cast<nConfItemBase*> (item);
170 if (netitem)
171 {
172 netitem->RevertToDefaults();
173 }
174 }
175 }
176
177 // *******************************************************************************************
178 // *
179 // * s_SaveValues
180 // *
181 // *******************************************************************************************
182 //!
183 //!
184 // *******************************************************************************************
185
s_SaveValues(void)186 void nConfItemBase::s_SaveValues( void )
187 {
188 tConfItemMap & confmap = ConfItemMap();
189 for(tConfItemMap::iterator iter = confmap.begin(); iter != confmap.end() ; ++iter)
190 {
191 tConfItemBase * item = (*iter).second;
192 nConfItemBase *netitem = dynamic_cast<nConfItemBase*> (item);
193 if (netitem)
194 {
195 netitem->SaveValue();
196 }
197 }
198 }
199
200 // *******************************************************************************************
201 // *
202 // * s_RevertToSavedValues
203 // *
204 // *******************************************************************************************
205 //!
206 //!
207 // *******************************************************************************************
208
s_RevertToSavedValues(void)209 void nConfItemBase::s_RevertToSavedValues( void )
210 {
211 tConfItemMap & confmap = ConfItemMap();
212 for(tConfItemMap::iterator iter = confmap.begin(); iter != confmap.end() ; ++iter)
213 {
214 tConfItemBase * item = (*iter).second;
215 nConfItemBase *netitem = dynamic_cast<nConfItemBase*> (item);
216 if (netitem)
217 {
218 netitem->RevertToSavedValue();
219 }
220 }
221 }
222
nConfItemLine(const char * title,tString & s)223 nConfItemLine::nConfItemLine(const char *title,tString &s)
224 :tConfItemBase(title),nConfItem<tString>(s){}
225
~nConfItemLine()226 nConfItemLine::~nConfItemLine(){}
227
ReadVal(std::istream & s)228 void nConfItemLine::ReadVal(std::istream & s)
229 {
230 tString dummy;
231 dummy.ReadLine(s,true);
232 if(strcmp(dummy,*target)){
233 if (printChange)
234 {
235 tOutput o;
236 o.SetTemplateParameter(1, title);
237 o.SetTemplateParameter(2, *target);
238 o.SetTemplateParameter(3, dummy);
239 o << "$config_value_changed";
240 con << o;
241 }
242 *target=dummy;
243 changed=true;
244 }
245
246 *target=dummy;
247 }
248
249 // *******************************************************************************************
250 // *
251 // * nIConfItemWatcher
252 // *
253 // *******************************************************************************************
254 //!
255 //! @param item the item to watch
256 //!
257 // *******************************************************************************************
258
nIConfItemWatcher(nConfItemBase & item)259 nIConfItemWatcher::nIConfItemWatcher( nConfItemBase & item )
260 :watched_( item )
261 {
262 item.watcher_ = this;
263 }
264
265 // *******************************************************************************************
266 // *
267 // * ~nIConfItemWatcher
268 // *
269 // *******************************************************************************************
270 //!
271 //!
272 // *******************************************************************************************
273
~nIConfItemWatcher(void)274 nIConfItemWatcher::~nIConfItemWatcher( void )
275 {
276 watched_.watcher_ = NULL;
277 }
278
279 // *******************************************************************************************
280 // *
281 // * OnChange
282 // *
283 // *******************************************************************************************
284 //!
285 //! @param nonDefault flag indicating whether the change was away from the default
286 //!
287 // *******************************************************************************************
288
OnChange(bool nonDefault)289 void nIConfItemWatcher::OnChange( bool nonDefault )
290 {
291 }
292
293 // *******************************************************************************************
294 // *
295 // * nIConfItemWatcher
296 // *
297 // *******************************************************************************************
298 //!
299 //!
300 // *******************************************************************************************
301
302 //nIConfItemWatcher::nIConfItemWatcher( void )
303 //{
304 //}
305
306 // *******************************************************************************************
307 // *
308 // * nIConfItemWatcher
309 // *
310 // *******************************************************************************************
311 //!
312 //! @param other object to copy from
313 //!
314 // *******************************************************************************************
315
316 //nIConfItemWatcher::nIConfItemWatcher( nIConfItemWatcher const & other )
317 //{
318 //}
319
320 // *******************************************************************************************
321 // *
322 // * operator =
323 // *
324 // *******************************************************************************************
325 //!
326 //! @param other object to copy from
327 //! @return reference to self
328 //!
329 // *******************************************************************************************
330
331 //nIConfItemWatcher & nIConfItemWatcher::operator =( nIConfItemWatcher const & other )
332 //{
333 // return *this;
334 //}
335
336 typedef std::set< nConfItemVersionWatcher * > nStrongWatcherList;
337 static nStrongWatcherList * sn_watchers=0;
338 static int sn_refcount=0;
339
sn_GetStrongWatchers()340 static nStrongWatcherList & sn_GetStrongWatchers()
341 {
342 if (!sn_watchers)
343 {
344 sn_watchers = tNEW(nStrongWatcherList)();
345 }
346
347 return *sn_watchers;
348 }
349
sn_StrongWatchersAddRef()350 void sn_StrongWatchersAddRef()
351 {
352 sn_refcount++;
353 }
354
sn_StrongWatchersRelease()355 void sn_StrongWatchersRelease()
356 {
357 if ( --sn_refcount <= 0 )
358 {
359 tDESTROY( sn_watchers );
360 }
361 }
362
363 // *******************************************************************************************
364 // *
365 // * nConfItemVersionWatcher
366 // *
367 // *******************************************************************************************
368 //!
369 //! @param item
370 //! @param feature
371 //!
372 // *******************************************************************************************
373
nConfItemVersionWatcher(nConfItemBase & item,Group c,int min,int max)374 nConfItemVersionWatcher::nConfItemVersionWatcher( nConfItemBase & item, Group c, int min, int max )
375 : nIConfItemWatcher( item )
376 , version_( min, max > 0 ? max : 0x7FFFFFFF )
377 , nonDefault_( false )
378 , reverted_( false )
379 , group_( c )
380 , overrideGroupBehavior_( Behavior_Default )
381 , overrideGroupBehaviorConf_( item.GetTitle() + "_OVERRIDE", overrideGroupBehavior_ )
382 {
383 sn_StrongWatchersAddRef();
384 sn_GetStrongWatchers().insert(this);
385 }
386
387 // *******************************************************************************************
388 // *
389 // * ~nConfItemVersionWatcher
390 // *
391 // *******************************************************************************************
392 //!
393 //!
394 // *******************************************************************************************
395
~nConfItemVersionWatcher(void)396 nConfItemVersionWatcher::~nConfItemVersionWatcher( void )
397 {
398 sn_GetStrongWatchers().erase(this);
399 sn_StrongWatchersRelease();
400 }
401
402 // *******************************************************************************************
403 // *
404 // * OnChange
405 // *
406 // *******************************************************************************************
407 //!
408 //! @param nonDefault flag indicating whether the change was away from the default
409 //!
410 // *******************************************************************************************
411
OnChange(bool nonDefault)412 void nConfItemVersionWatcher::OnChange( bool nonDefault )
413 {
414 bool changed = ( nonDefault != nonDefault_ );
415
416 nonDefault_ = nonDefault;
417 if ( changed )
418 {
419 sn_UpdateCurrentVersion();
420 }
421 }
422
423 static char const * sn_groupName[ nConfItemVersionWatcher::Group_Max ] =
424 {
425 "Breaking",
426 "Bumpy",
427 "Annoying",
428 "Cheating",
429 "Visual"
430 };
431
432 // mapping network version to program version
433 static char const * sn_versionString[] =
434 {
435 "0.2.0", // 0
436 "0.2.0", // 1
437 "0.2.5.0", // 2
438 "0.2.6.0", // 3
439 "0.2.7.1", // 4
440 "0.2.8_beta1", // 5
441 "0.2.8_beta1", // 6
442 "0.2.8_beta2", // 7
443 "0.2.8_beta3", // 8
444 "0.2.8_beta4", // 9
445 "0.2.8_rc1", // 10
446 "0.2.8.0", // 11
447 "0.2.8_alpha20060414", // 12
448 "0.2.8.2", // 13
449 "0.2.8.3_alpha", // 14
450 "0.2.8.3_alpha_auth", // 15
451 "0.2.8.3.X", // 16, was: 0.2.8.3_beta2
452 0
453 };
454
sn_GetCurrentProtocolVersion()455 int sn_GetCurrentProtocolVersion()
456 {
457 return (sizeof(sn_versionString)/sizeof(char const *)) - 2;
458 }
459
sn_GetVersionString(int version)460 static char const * sn_GetVersionString( int version )
461 {
462 tVERIFY ( version * sizeof( char * ) < sizeof sn_versionString );
463 tVERIFY ( version >= 0 );
464
465 return sn_versionString[ version ];
466 }
467
sn_GetClientVersionString(int version)468 tOutput sn_GetClientVersionString(int version) {
469 if(version >= 0 && version * sizeof(char *) < sizeof(sn_versionString)) {
470 tOutput ret;
471 ret.AddLiteral(sn_GetVersionString(version));
472 return ret;
473 }
474 return tOutput("$network_unknown_version", version);
475 }
476
477 // *******************************************************************************************
478 // *
479 // * AdaptVersion
480 // *
481 // *******************************************************************************************
482 //!
483 //! @param version the version to adapt to the settings
484 //!
485 // *******************************************************************************************
486
487 // the last version we warned the user about
488 static nVersion lastVersion = sn_MyVersion();
489
AdaptVersion(nVersion & version)490 void nConfItemVersionWatcher::AdaptVersion( nVersion & version )
491 {
492 if ( sn_GetNetState() != nSERVER )
493 return;
494
495 // iterate over all watchers
496 nStrongWatcherList & watchers = sn_GetStrongWatchers();
497 for ( nStrongWatcherList::iterator iter = watchers.begin(); iter != watchers.end(); ++iter )
498 {
499 nConfItemVersionWatcher * run = *iter;
500
501 // adapt version to needs
502 if ( run->nonDefault_ && run->GetBehavior() >= Behavior_Block )
503 {
504 tVERIFY( version.Merge( version, run->version_ ) );
505 if ( version.Min() > lastVersion.Min() )
506 {
507 // inform user about potential problem
508 tOutput o;
509 run->FillTemplateParameters(o);
510 o << "$setting_legacy_clientblock";
511 con << o;
512
513 lastVersion = version;
514 }
515 }
516 }
517 }
518
519 // *******************************************************************************************
520 // *
521 // * OnVersionChange
522 // *
523 // *******************************************************************************************
524 //!
525 //! @param version the version to adapt the settings to
526 //!
527 // *******************************************************************************************
528
OnVersionChange(nVersion const & version)529 void nConfItemVersionWatcher::OnVersionChange( nVersion const & version )
530 {
531 // store version for reference
532 lastVersion = version;
533
534 if ( sn_GetNetState() != nSERVER )
535 return;
536
537 // iterate over all watchers
538 nStrongWatcherList & watchers = sn_GetStrongWatchers();
539 for ( nStrongWatcherList::iterator iter = watchers.begin(); iter != watchers.end(); ++iter )
540 {
541 nConfItemVersionWatcher * run = *iter;
542
543 // warn about settings that will revert or be ignored
544 Behavior behavior = run->GetBehavior();
545 if (run->nonDefault_ && behavior != Behavior_Block )
546 {
547 // don't warn twice for the same group and behavior
548 static int warnedRevert[ Behavior_Default ][ Group_Max ];
549 {
550 static bool inited = false;
551 if (!inited)
552 {
553 inited = true;
554 for ( int i = Behavior_Default-1; i>=0; --i )
555 for ( int j = Group_Max-1; j>=0; --j )
556 warnedRevert[i][j] = sn_MyVersion().Min();
557 }
558 }
559 int & warned = warnedRevert[ behavior ][ run->group_ ];
560
561 if ( warned < run->version_.Min() && run->version_.Min() > version.Min() )
562 {
563 warned = run->version_.Min();
564
565 // inform user about potential problem with nondefault settings
566 tOutput o;
567 run->FillTemplateParameters(o);
568 o << ( ( behavior == Behavior_Revert ) ? "$setting_legacy_revert" : "$setting_legacy_ignore" );
569 con << o;
570 }
571 }
572
573 // ignore settings where this is desired
574 if ( run->GetBehavior() == Behavior_Nothing )
575 continue;
576
577 // if version is supported..
578 if ( run->version_.Min() <= version.Max() )
579 {
580 // ...restore saved value of config item
581 if ( run->reverted_ )
582 {
583 run->reverted_ = false;
584 run->watched_.RevertToSavedValue();
585 }
586 }
587 else
588 {
589 // version is not supported. Revert to defaults.
590 if ( !run->reverted_ && run->nonDefault_ )
591 {
592 run->reverted_ = true;
593 run->watched_.SaveValue();
594 run->watched_.RevertToDefaults();
595 }
596 }
597
598 }
599 }
600
601 static nConfItemVersionWatcher::Behavior sn_GroupBehaviors[ nConfItemVersionWatcher::Group_Max ] =
602 {
603 Behavior_Block,
604 Behavior_Block,
605 Behavior_Nothing,
606 Behavior_Block,
607 Behavior_Nothing,
608 };
609
610 static tSettingItem< nConfItemVersionWatcher::Behavior > sn_GroupBehaviorBreaks( "SETTING_LEGACY_BEHAVIOR_BREAKING", sn_GroupBehaviors[ nConfItemVersionWatcher::Group_Breaking] );
611 static tSettingItem< nConfItemVersionWatcher::Behavior > sn_GroupBehaviorBumpy( "SETTING_LEGACY_BEHAVIOR_BUMPY", sn_GroupBehaviors[ nConfItemVersionWatcher::Group_Bumpy] );
612 static tSettingItem< nConfItemVersionWatcher::Behavior > sn_GroupBehaviorAnnoyance( "SETTING_LEGACY_BEHAVIOR_ANNOYING", sn_GroupBehaviors[ nConfItemVersionWatcher::Group_Annoying] );
613 static tSettingItem< nConfItemVersionWatcher::Behavior > sn_GroupBehaviorCheat( "SETTING_LEGACY_BEHAVIOR_CHEATING", sn_GroupBehaviors[ nConfItemVersionWatcher::Group_Cheating] );
614 static tSettingItem< nConfItemVersionWatcher::Behavior > sn_GroupBehaviorDisplay( "SETTING_LEGACY_BEHAVIOR_VISUAL", sn_GroupBehaviors[ nConfItemVersionWatcher::Group_Visual] );
615
616 // *******************************************************************************************
617 // *
618 // * GetBehavior
619 // *
620 // *******************************************************************************************
621 //!
622 //! @return behavior if this setting is on non-default and a client that does not support it connects
623 //!
624 // *******************************************************************************************
625
GetBehavior(void) const626 nConfItemVersionWatcher::Behavior nConfItemVersionWatcher::GetBehavior( void ) const
627 {
628 // look up default behavior
629 tASSERT( 0 <= group_ && group_ < nConfItemVersionWatcher::Group_Max );
630 Behavior behavior = sn_GroupBehaviors[ group_ ];
631
632 // override it
633 if ( Behavior_Default != this->overrideGroupBehavior_ )
634 behavior = this->overrideGroupBehavior_;
635
636 return behavior;
637 }
638
639 // *******************************************************************************************
640 // *
641 // * GetBehavior
642 // *
643 // *******************************************************************************************
644 //!
645 //! @param behavior behavior if this setting is on non-default and a client that does not support it connects to fill
646 //! @return A reference to this to allow chaining
647 //!
648 // *******************************************************************************************
649
GetBehavior(Behavior & behavior) const650 nConfItemVersionWatcher const & nConfItemVersionWatcher::GetBehavior( Behavior & behavior ) const
651 {
652 behavior = this->GetBehavior();
653 return *this;
654 }
655
656 // *******************************************************************************************
657 // *
658 // * DoWritable
659 // *
660 // *******************************************************************************************
661 //!
662 //! @return true if the watched item is changable
663 //!
664 // *******************************************************************************************
665
DoWritable(void) const666 bool nConfItemVersionWatcher::DoWritable( void ) const
667 {
668 // if we're not set to revert, the setting is writable
669 if ( GetBehavior() != Behavior_Revert )
670 return true;
671
672 // and if the setting is currently supported by all parites, it's writable too
673 if ( version_.Min() <= sn_CurrentVersion().Max() )
674 return true;
675
676 // inform user about impossible change
677 tOutput o;
678 FillTemplateParameters(o);
679 o << "$setting_legacy_change_blocked";
680 con << o;
681
682 // only if it's not, it needs to be protected.
683 return false;
684
685 }
686
687 // *******************************************************************************************
688 // *
689 // * FillTemplateParameters
690 // *
691 // *******************************************************************************************
692 //!
693 //! @param o output to fill. Template parameter 1 will be the setting name, parameter 2 the setting's group, and parameter 3 the first version supporting the setting
694 //!
695 // *******************************************************************************************
696
FillTemplateParameters(tOutput & o) const697 void nConfItemVersionWatcher::FillTemplateParameters( tOutput & o ) const
698 {
699 o.SetTemplateParameter(1, watched_.GetTitle() );
700 o.SetTemplateParameter(2, sn_groupName[group_] );
701 o.SetTemplateParameter(3, sn_GetVersionString( version_.Min() ) );
702 }
703
704
705