Merge branch '138-toggle-free-look-with-hotkey' into main/gingo-test
[ryzomcore.git] / ryzom / client / src / r2 / editor.h
blob2fc85e1fade64d4e3cb19966355fbe40c3c778eb
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #ifndef R2_EDITOR_H
21 #define R2_EDITOR_H
23 #include "nel/gui/lua_object.h"
24 #include "instance.h"
25 #include "tool.h"
26 #include "../decal.h"
27 #include "../decal_anim.h"
28 #include "entity_custom_select_box.h"
29 #include "island_collision.h"
30 #include "prim_render.h"
32 #include "nel/misc/singleton.h"
33 #include "nel/misc/class_registry.h"
34 #include "nel/misc/time_nl.h"
35 #include "nel/misc/sstring.h"
36 #include "nel/misc/array_2d.h"
38 #include "dmc/dmc.h"
40 #include "game_share/object.h"
41 #include "game_share/scenario_entry_points.h"
42 #include "game_share/r2_types.h"
47 namespace NLGUI
49 class CGroupTree;
52 class CEntityCL;
54 namespace NL3D
56 class CPackedWorld;
59 namespace R2
61 class CDynamicMapService;
62 class CUserComponentsManager;
63 class CEntitySorter;
65 // texture for the default mouse cursor
66 extern const char *DEFAULT_CURSOR;
69 class CDisplayerVisualEntity;
71 /** Ryzom Ring in game editor
73 * ///////////////////////////////////////////////////////////
74 * // TMP OVERVIEW OF R2 UI BEHAVIOR (WORK IN PROGRESS ...) //
75 * ///////////////////////////////////////////////////////////
78 * The ui can be in one of the following states :
80 * I CREATION MODE
81 * ===============
83 * No tool is displayed as "highlighted"
85 * 1) Mouse in 3D view
86 * --------------------
87 * The mouse cursor has a little star to indicate "creation mode".
88 * If creation is not possible at the mouse position, then there's is a little 'stop' icon shown
89 * No instance selection is done
91 * EVENTS :
92 * --------
93 * LCLICK -> create
94 * RCLICK -> cancel & restore default tool
96 * NB : we don't do creation on LDOWN or RUP in order to allow camera manipulation
98 * 2) Mouse over UI
99 * -----------------
100 * The mouse cursor still has a little star to indicate "creation mode".
101 * Ideally on some actions, the creation is canceled, and the default tool is backuped;
102 * NB nico : this is unclear to me atm, is it for button clicks only ?
103 * (for example just moving a slider do not seem a good reason to cancel the tool...)
104 * so no-op for now
105 * (TODO : exception for the minimap, if we want to be able to create by clicking on it ?)
107 * II CONTEXT MENU MODE
108 * ====================
110 * The standard mouse cursor is displayed.
112 * EVENTS :
113 * --------
114 * LDOWN / RDOWN -> cancel the menu
116 * III CAPTURED BY UI MODE
117 * =======================
118 * ... same as 'context menu mode'
120 * IV TOOL MODE
121 * =============
122 * The current tool icon is highlighted in the toolbar
124 * std tool includes :
125 * - Move
126 * - Rotate
127 * ...
129 * 1) Mouse in 3D view
130 * --------------------
131 * a ) Mouse over empty space in scene
132 * -----------------------------------
133 * The standard mouse cursor is displayed
135 * EVENTS :
136 * --------
137 * nothing to do here, camera event are handled by the 'UserControls' global object
138 * If the right button is up without being preceded by a camera move, then the context
139 * menu is shown
142 * b ) Mouse over an instance in scene that is not the selection
143 * -------------------------------------------------------------
144 * The mouse with a little circle is displayed
146 * EVENTS :
147 * --------
148 * RDOWN -> Test and see which one is best :
149 * - a new slection is done and the context menu is shown ?
150 * - nothing ? (e.g no selection and the context menu is trigerred by
151 * the 'UserControls' global object as usual ?
152 * RDOWN while maintained action : cancel the current action and restore
153 * state (same behaviour as most apps)
154 * LDOWN -> selection + tool dependent (instant action or maintained action)
155 * a maintained action (such as moving an entity) will usually
156 * capture the mouse.
157 * others -> tool dependent
159 * c ) Mouse over an instance in scene that the selection
160 * -------------------------------------------------------------
161 * The mouse shows the action that can be performed
162 * RDOWN -> same as previous
163 * others -> tool dependent
164 * RDOWN while maintained action : cancel the current action and restore
165 * state (same behaviour as most apps)
167 * NB : a tool may want to capture the mouse, in this case it must call CTool::captureMouse
168 * and CTool::releaseMouse when it is done
170 * REMARKS:
172 * - Maybe it would be cool to make camera manipulation totally orthogonal to the system,
173 * and transparently layered on top of it.
174 * This would requires using something like the middle button or some shift / control combination
175 * to avoid conflict with the previous events ...
177 * 2) Mouse over UI
178 * -----------------
179 * The mouse is dipslayed as usual
180 * Events are taken in account by the UI, not by the tool
181 * This is transparent for CTool derivers, because mouse events won't reach them
182 * Clicking in the interface doesn't change the current tool
185 * \author Nicolas Vizerie
186 * \author Nevrax France
187 * \date 5/2005
192 class CEditor : public NLMISC::CSingleton<CEditor>
194 public:
195 enum TMode { NotInitialized = 0, EditionMode, GoingToDMMode, GoingToEditionMode, TestMode, DMMode,
196 AnimationModeLoading, AnimationModeWaitingForLoading, AnimationModeDm, AnimationModePlay,
197 AnimationModeGoingToDm, AnimationModeGoingToPlay, ModeCount };
199 enum TAccessMode { AccessEditor = 0, AccessDM, AccessOutlandOwner, AccessModeCount, AccessModeUnknown = AccessModeCount };
201 ////////////
202 // OBJECT //
203 ////////////
205 CEditor();
206 ~CEditor();
208 // Init what's need to be initialized depending on the configuration
209 void autoConfigInit(bool serverIsRingSession);
211 // Release what's need to be released depending on the configuration
212 void autoConfigRelease(bool serverIsRingSession);
214 // initialisation of modules & gw
215 void initModules(bool connectDMC);
216 void releaseModules();
218 // wait first scenario to be received (may be an empty one ...)
219 void waitScenario();
221 TAccessMode getAccessMode() const { return _AccessMode; }
222 void setAccessMode(TAccessMode mode);
224 // Initialisation of the editor
225 void init(TMode initialMode, TAccessMode accessMode);
227 // reload xml, lua & translation & reset. scenario is preserved
228 void reset();
229 // reload xml, lua & translation & reset. scenario is reseted
230 void resetScenario();
231 // reload xml, lua & translation & reset. Last save scenario is reloaded
232 void reloadScenario();
233 // load / reload the work language file
234 void loadLanguageFile();
236 void release();
237 // clear all content in the map, client side
238 void clearContent();
240 bool isInitialized() const { return _Initialized; }
241 // (re)load the ui if its date changed
242 void reloadUI();
244 // set current mode of the editor
245 void setMode(TMode mode);
246 TMode getMode() const { return _Mode; }
248 // test if user is DMing (be it masterless or not)
249 bool isDMing() const;
251 /////////////////////
252 // UPDATE & EVENTS //
253 /////////////////////
255 /** Events handling
256 * Handle an user input event
257 * \return true if the event was handled by the editor
259 bool handleEvent (const NLGUI::CEventDescriptor &eventDesc);
261 // Handle copy, reaches the editor if no edit box is currently active
262 void copy();
264 // Handle paste, reaches the editor if no edit box is currently active
265 void paste();
267 // An entity has been selected with the standard selection system (usually in test mode)
268 void inGameSelection(const CLFECOMMON::TCLEntityId &slot);
270 void onContinentChanged();
273 /** update of editor just before precamera call for entities
275 void updatePreCamera();
276 /** update of editor (after update of entities just before render)
278 void updateBeforeRender();
279 /** Update of editor (just after render of the scene and entities update and before rendering of the interface)
280 * This is the place to display additionnal visual infos (slection bbox etc ...)
282 void updateAfterRender();
284 // called after main loop 'swap buffer'
285 void updateBeforeSwapBuffer();
287 /////////////////////////////////////////////
288 // CLIENT OBJECTS (yet named 'instances' ) //
289 /////////////////////////////////////////////
291 // NB about this tmp mess
292 // 'CInstance' are client counterparts of 'CObjectTable'
294 // set current selected instance in the editor
295 void setSelectedInstance(CInstance *inst);
296 void forceSetSelectedInstance(CInstance *inst);
297 // get current selected instance in the editor
298 CInstance *getSelectedInstance() const;
299 // set current highlighted instance in the editor
300 void setFocusedInstance(CInstance *inst);
301 // get current higlighted entity in the editor (with mouseoverit)
302 CInstance *getFocusedInstance() const;
304 bool hasInstance(const CInstance *instance) const;
305 // Check if there's an instance with the given id
306 bool hasInstanceWithId(const TInstanceId &id) const;
307 // Get an instance from its id
308 CInstance *getInstanceFromId(const TInstanceId &id) const;
310 /** Create Visual Properties for an instance
311 * Return false if can not retrieve VisualProperties
313 bool getVisualPropertiesFromObject(CObject* instance, SPropVisualA& vA, SPropVisualB& vB, SPropVisualC& vC);
315 /** Generate a new user readable name for an object in the scene
316 * If the name if already postfixed by a number, it will be stripped.
317 * Example : Npc 1, Npc 2, Group 1, Bandit camp 1 etc.
318 * Localised base name is given (for example "road" if using english)
319 * The function looks in all road instances and finds the first free number.
322 * \param baseClass Filter base class for the search : only class that derived from (or are of ) that class will
323 * be considered when looking for a new name
325 ucstring genInstanceName(const ucstring &baseName);
327 // test if an instance name is post fixed by a number
328 static bool isPostFixedByNumber(const ucstring &baseName);
330 /** test if a ucstring has the format of a generated name that is : baseName + " " + index
331 * Return index on success or -1 on failure
333 static sint getGeneratedNameIndex(const std::string &nameUtf8, const std::string &baseNameUtf8);
335 /** Set a local user value (we name it a "cookie") that should be attached to an instance at creation time
336 * (that is, when the object will be created on client -> when the server creation msg is received)
337 * The value will be stored in the 'User' lua table.
338 * The 'User' table is attached to each instances in the editor and is Read/Write
339 * (other properties in client and server and are read only, and should be modified by sending a requestxxx network message)
340 * This table is local only (that is, not seen by the server, nor by other clients editing the same map).
342 * Example of use :
344 * We want that when a road is created, a dialog pop to enter the name of the road.
346 * First we must be able to distinguish between roads created by ourselves and road created by
347 * other persons editing the map.
349 * Secondly we don't want that all roads to have this behaviour (for example, a road in a more complex system
350 * would be named automatically)
353 * In lua script it would look like :
355 * At creation request time :
356 * ==========================
358 * local road = r2.newComponent("Road")
359 * r2.setCookie(road.InstanceId, "AskName", true)
360 * r2.requestInsertNode(... -> send newtork creation message for the road
363 * When creation message is received (may be placed in the 'onCreate' method of a displayer attached to that instance)
364 * ==================================================================================================================
366 * function roadDisplayer:onCreate(road)
367 * if road.User.AskName == true then
368 * -- road was created by this client
369 * -- dialog to enter the name was asked
370 * -- => popup the dialog
371 * ....
372 * end
373 * end
375 * Other example : when an act is created by the user it becomes the current act
378 void setCookie(const TInstanceId &instanceId, const std::string &key, CLuaObject &value);
379 // helpers to add cookie of predefined type (to be completed ..)
380 void setCookie(const TInstanceId &instanceId, const std::string &key, bool value);
383 struct IInstanceObserver : public NLMISC::CRefCount // refptr'ed observers
385 virtual ~IInstanceObserver() {}
387 typedef NLMISC::CRefPtr<IInstanceObserver> TRefPtr;
388 // called when the watched instance has been created
389 virtual void onInstanceCreated(CInstance &/* instance */) {}
390 virtual void onInstanceErased(CInstance &/* instance */) {}
391 virtual void onInstancePreHrcMove(CInstance &/* instance */) {}
392 virtual void onInstancePostHrcMove(CInstance &/* instance */) {}
393 virtual void onPreHrcMove(CInstance &/* instance */) {}
394 virtual void onPostHrcMove(CInstance &/* instance */) {}
395 virtual void onInstanceEraseRequest(CInstance &/* instance */) {}
396 virtual void onAttrModified(CInstance &/* instance */, const std::string &/* attrName */, sint32 /* attrIndex */) {}
399 typedef sint TInstanceObserverHandle;
401 enum { BadInstanceObserverHandle = -1 };
403 /** add a watch to know when an instance is created (the instance is identified by its instance id)
404 * returns a handle for removal, or 'BadInstanceObserverHandle' if creation failed
406 TInstanceObserverHandle addInstanceObserver(const TInstanceId &instanceId, IInstanceObserver *observer);
407 // Get a pointer to an observer from its handle (or NULL if not found)
408 IInstanceObserver *getInstanceObserver(TInstanceObserverHandle handle);
409 // Remove an instance observer from its handle (but do not delete it). Return the pointer to the observer
410 IInstanceObserver *removeInstanceObserver(TInstanceObserverHandle handle);
411 /** Test from a pointer if the object is currently observing an instance
412 * NB : slow because of linear search
414 bool isInstanceObserver(IInstanceObserver *observer) const;
418 ////////////////////////
419 // LUA R2 ENVIRONMENT //
420 ////////////////////////
422 // get table for global variables in lua environment (equivallent to _G lua variable)
423 CLuaObject &getGlobals() { return _Globals; }
424 // get table for registry in lua environment
425 CLuaObject &getRegistry() { return _Registry; }
426 // get lua classes (the r2.Classes table)
427 CLuaObject getClasses();
428 // get R2 environment (the 'r2' table into lua global environment)
429 CLuaObject &getEnv();
430 // get the config table (that is the 'r2.Config' table)
431 CLuaObject getConfig();
432 // get a reference to the lua state object
433 CLuaState &getLua();
434 /** Project a CObjectTable into lua (accessor is pushed onto the lua stack)
435 * property of the table, which is a C++ object, will be accessible from lua (by using metatable)
437 void projectInLua(const CObjectTable *table);
439 // get the default feature for the current selected act
440 CInstance *getDefaultFeature();
441 // get the default feature for the given act
442 CInstance *getDefaultFeature(CInstance *act);
444 // set the current act (NULL being synonimous with the base act)
445 void setCurrentAct(CInstance *act);
446 void setCurrentActFromTitle(const std::string &title);
447 CInstance *getCurrentAct() const { return _CurrentAct; }
448 CInstance *getBaseAct() const { return _BaseAct; }
450 /** helper : calls a function in the lua r2ed environment
451 * Arguments must have already been pushed on the stack
452 * If the call fails then an error msg is printed in the log, and no arguments are returned
454 * \param funcName name of the function to call (must resides in the r2ed table)
455 * \param numArgs, numbers of arguments that the functions will receive
456 * \param numRet : Number of parameters that the function returns
457 * As usual the stack will be adjusted to that size after the call
459 bool callEnvFunc(const char *funcName, int numArgs, int numRet = 0);
460 // Behave like 'callEnvFunc', but call a method instead (r2 is passed as the 'self' parameter, that is)
461 bool callEnvMethod(const char *funcName, int numArgs, int numRet = 0);
463 //////////////////////
464 // SERVER COMMANDS //
465 //////////////////////
467 // access to interface with server
468 CDynamicMapClient &getDMC() const { nlassert(_DMC); return *_DMC; }
470 /** Set a property of an object locally. No network msg is sent, but modification events are triggered to signal that
471 * the object has been modified (rooted to one of the CDisplayerBase derived object, attached to the object being modified. see displayer_base.h).
472 * Changes to local value must be commited or cancelled when edition is finish by calling 'requestCommitLocalNode' or
473 * 'requestRollbackLocalNode'
474 * Typical use is by the slider widget : real value is sent accross the network only when the user release the mouse, but
475 * local update of object property related to the slider is done each time the slider is modified before release.
476 * During the maintained action, no network message are desireable.
477 * NB : a copy of input parameter 'value' will be done. Caller is responsible for deleting 'value' after use.
479 void requestSetLocalNode(const std::string& instanceId, const std::string& attrName, const CObject *value);
480 void requestCommitLocalNode(const std::string& instanceId, const std::string& attrName);
481 void requestRollbackLocalNode(const std::string& instanceId, const std::string& attrName);
483 /////////////
484 // DECALS //
485 /////////////
486 void showHighlightDecal(const NLMISC::CVector &pos, float scale);
487 void showSelectDecal(const NLMISC::CVector &pos, float scale);
488 void addSelectingDecal(const NLMISC::CVector &pos, float scale);
489 void showSelectBox(const NLMISC::CAABBox &localBox, const NLMISC::CMatrix &worldMat);
490 void showHighlightBox(const NLMISC::CAABBox &localBox, const NLMISC::CMatrix &worldMat);
493 /////////////////
494 // COLLISIONS //
495 /////////////////
497 CIslandCollision &getIslandCollision() { return _IslandCollision; }
500 ///////////
501 // MISC //
502 ///////////
504 // Shortcut to the GUI
505 static CInterfaceManager &getUI();
507 /** Set current edition tool. NULL will reset to the default tool (selection tool)
509 void setCurrentTool(CTool *tool);
510 // Get current tool for edition
511 CTool *getCurrentTool() const { return _CurrentTool; }
512 /** Helper to execute a lua script
513 * \param filename name of the lua script file
514 * \param fileDescText short description of the script function (for error messages)
515 * \return true on success
517 bool doLuaScript(const char *filename, const char *fileDescText);
518 // helper : create an entity in scene at the given slot & position, replacing any previous entity in that slot
520 static CEntityCL *createEntity(uint slot, const NLMISC::CSheetId &sheetId, const NLMISC::CVector &pos, float heading, const std::string & permanentStatutIcon=std::string(""));
521 // helper : get an instance from a CEntityCL pointer
522 CInstance *getInstanceFromEntity(CEntityCL *entity) const;
523 // helper : clear content of the debug window
524 void clearDebugWindow();
525 // display the editor contextual menu
526 void displayContextMenu();
527 // tmp, for debug
528 void dumpInstances();
529 // helper : return the entity under the mouse
530 CInstance *getInstanceUnderPos(float x, float y, float distSelection, bool &isPlayerUnderCursor);
531 // helper : test intersection between an entity and a ray
532 static float preciseEntityIntersectionTest(CEntityCL &entity, const NLMISC::CVector &worldRayStart, const NLMISC::CVector &worldRayDir);
533 // Tmp show the connection window and display a msg in it. An empty msg will close the window
534 static void connectionMsg(const std::string &stringId);
535 TEntityCustomSelectBoxMap &getEntityCustomSelectBoxMap() { return _EntityCustomSelectBoxMap; }
536 // from a pointer on an entity, retrieve its local selection bbox (possibly redefined in r2_ui_custom_boxes_data.lua
537 const NLMISC::CAABBox &getLocalSelectBox(CEntityCL &entity) const;
538 // from a pointer on an entity, retrieve its local selection bbox (possibly redefined in r2_ui_custom_boxes_data.lua
539 NLMISC::CAABBox getSelectBox(CEntityCL &entity) const;
540 // check if there's room left to create new objects in the scene
541 sint getLeftQuota();
544 bool checkRoomLeft();
545 // display an error msg to prompt the user to make room for new objects in its scenario
546 void makeRoomMsg();
547 // check if there is room in specific category if not display an error msg
548 // verify ther is at least size object in category StaticObject or AiObject
549 bool verifyRoomLeft(uint aiCost, uint staticCost);
551 // rename delete auto_save9, rename auto_save1.r2 to auto_save2.r2 and so until auto_save8.r2, copy auto_save.r2 to auto_save1.r2,
552 void autoSave();
554 /** Season driven from editor
555 * This value is usually 'Unknwown' unless the mode is "edit'.
556 * In this case, the value depends on the act being edited
558 enum TSeason { Automatic = 0, Spring, Summer, Autumn, Winter, UnknownSeason };
559 TSeason getSeason() const;
560 void tpReceived();
562 bool getFixedLighting() const { return _FixedLighting; }
563 void setFixedLighting(bool enabled);
565 /** Get current infos of a plot item plot display in the editor
566 * Plot items are items with SCROLL_R2 as family. Each sheet can be used only once in
567 * a scenario (meaning that each icon can only be seen for a single plot item).
568 * The name of a plot item can also be change by using the lua command r2:setPlotItemName(sheetId, ucName)
570 void setPlotItemInfos(const TMissionItem &infos);
571 const TMissionItem *getPlotItemInfos(uint32 sheetId) const;
574 // convert name of a class in R2 to a unique index (-1 if not found)
575 sint classToIndex(const std::string &className) const;
576 // this if one class id 'indexOf' another from their index
577 bool isKindOf(sint testedClassIndex, sint kindClassIndex) const;
578 // from one class index, returns the index to the derived class (-1 if not found)
579 sint getBaseClass(sint derivedClass) const;
582 ///////////////////////////////
583 // > 254 entities management //
584 ///////////////////////////////
586 CEntitySorter *getEntitySorter() const;
588 private:
590 CEntitySorter *_EntitySorter;
593 // mapping from sheet id to plot item name
594 std::map<uint32, TMissionItem> _PlotItemInfos;
595 CIslandCollision _IslandCollision;
598 bool _SerializeUIConfig;
599 TMode _Mode;
600 TAccessMode _AccessMode;
602 typedef std::map<const CObjectTable *, CInstance::TSmartPtr> TInstanceMap;
603 private:
605 CLuaObject _Globals; // match to the '_G' lua global variable
606 CLuaObject _Registry;
607 CLuaObject _Env;
608 CLuaObject _Config;
609 CLuaObject _ObjectProjectionMetatable;
610 CLuaObject _LuaUIMainLoop;
612 TInstanceMap _Instances;
613 CInstance *_SelectedInstance;
614 CInstance *_FocusedInstance;
616 CHashMap<std::string, uint> _ClassNameToIndex; // Map each class name to an unique index (filled at init)
617 NLMISC::CArray2D<uint8> _KindOfTable; // Table to test if one class derives from another (filled at init)
618 std::vector<sint> _BaseClassIndices; // for each class, give index of thebase class (vector ordered by classes indices)
620 typedef CHashMultiMap<ucstring, CInstance *, NLMISC::CUCStringHashMapTraits> TInstanceByName;
622 bool _MaxVisibleEntityExceededFlag;
624 // instance sorted by name
625 class CSortedInstances
627 public:
628 void insert(const ucstring &name, CInstance *inst);
629 void remove(CInstance *inst);
630 bool contains(CInstance *inst) const;
631 TInstanceByName::iterator begin() { return _ByName.begin(); }
632 TInstanceByName::iterator end() { return _ByName.end(); }
633 private:
635 typedef std::map<CInstance *, TInstanceByName::iterator> TInstanceToIter;
637 TInstanceByName _ByName;
638 TInstanceToIter _InstanceToIter;
640 // typedef TInstanceByDispName; // for usage by CInstance
641 // list of instances for each classes (ordered by class index)
642 std::vector<CSortedInstances> _InstancesByDispName; // instances sorted by their display name (private use)
644 //priv for debug
645 bool isRegisteredByDispName(CInstance *inst) const;
647 // Cookies (local objects attached to instances at creation time, see setCookie)
648 struct CCookie
650 std::string Key;
651 CLuaObject Value;
653 typedef std::list<CCookie> TCookieList; // for a single instance, map each key to its value
654 typedef std::map<TInstanceId, TCookieList> TCookieMap;
655 TCookieMap _Cookies;
657 CInstance::TRefPtr _CurrentAct;
658 CInstance::TRefPtr _BaseAct;
659 CInstance::TRefPtr _ScenarioInstance;
660 CObjectTable *_Scenario;
661 std::string _WantedActOnInit;
663 friend class CDynamicMapClientEventForwarder;
664 friend class CAHR2QuitConnectingScreen;
665 CDynamicMapClient *_DMC; // replication of server map state on that client
666 CDynamicMapService *_DMS; // the server (hosted in local for now)
667 CInstance::TRefPtr _LastInstanceUnderPos;
669 CTool::TSmartPtr _CurrentTool;
670 static bool _ReloadWanted;
672 CDecal _HighlightDecal;
673 CDecalAnim _HighlightDecalAnim;
674 CDecal _SelectDecal;
675 CDecalAnim _SelectDecalAnim;
676 CDecalAnim _SelectingDecalAnim;
677 CDecal _PionneerDecal;
678 // alternative selection for huge element like particle systems, display a box on ground rather than
679 // the selection circle
680 CPrimRender _SelectBox;
681 CPrimRender _HighlightBox;
683 NLMISC::TTime _LastAutoSaveTime;
684 CDecalAnim _PionneerDecalAnim;
685 struct CSelectingDecal : public NLMISC::CRefCount
687 CDecal Decal;
688 sint64 EndDate;
689 NLMISC::CVector Pos;
690 float Scale;
692 std::vector<NLMISC::CSmartPtr<CSelectingDecal> > _SelectingDecals;
693 sint64 _DecalRefTime; // reference time for "decals" animation
695 bool _EnteredInSetSelectedInstance; // prevent recursive call from CEditor::setSelectedInstance
696 bool _Initialized;
697 bool _ForceDesktopReset[4];
698 // cache to avoid to reparse the ui : last modification date of ui files
699 std::map<std::string, uint32> _LastUIModificationDate;
700 TEntityCustomSelectBoxMap _EntityCustomSelectBoxMap;
701 /** system for local generation of name : for each kind of name, gives the locally allocated ids
702 * -> Used to generate name for instances, taking in account instance that have not been added to the scene yet.
703 * (that is, requestSetNode message has been sent, but server has not added object to the scenario yet)
705 typedef std::set<uint> TNameSet;
706 typedef std::map<std::string, TNameSet> TGeneratedNameMap;
707 TGeneratedNameMap _LocalGeneratedNames;
709 // instance observers
711 typedef std::multimap<TInstanceId, IInstanceObserver::TRefPtr> TInstanceObserverMap;
712 TInstanceObserverMap _InstanceObservers;
713 typedef std::map<TInstanceObserverHandle, TInstanceObserverMap::iterator> TInstanceObserverHandleMap;
714 TInstanceObserverHandleMap _InstanceObserverHandles; // map each observer handle into an entry in the map
715 TInstanceObserverHandle _InstanceObserverHandleCounter; // current handle to generate when adding a new observer
718 TSeason _Season;
719 bool _FixedLighting;
720 bool _IsWaitingTPForSeasonChange;
721 bool _UpdatingScenario;
722 bool _WillTP; // true if a teleport should be expected after the scenario has been updated
723 // in this case, first season change is ignored, because it is done during the teleport
725 bool _ScenarioReceivedFlag; // for the wait screen ...
726 bool _TPReceivedFlag; // for the wait screen ...
727 bool _WaitScenarioScreenWanted; // lua requests that we display the 'wait scenario' screen
728 bool _WaitScenarioScreenActive; // the 'wait scenario' screen is being displayed
729 bool _EditionModeDisconnectedFlag;
730 CObject *_NewScenario; // new scenario that will be updated just after the wait screen is over
731 uint32 _NewScenarioInitialAct;// the start at which the user start an edition session (can be ~= from 1 after a test session)
732 bool _PostponeScenarioUpdated;
734 // Contextual selection
736 // We keep track of the last selected 'logic entity' (npc most of the time),
737 // and the last list of primitive through which its current activity sequence goes
738 // This way we can handle the following scenario :
739 // - create a npc
740 // - make him wander in zone A then zone B
741 // - select contextual visibility for primitive
742 // - click on npc : both zone shows
743 // - click on zone A : zone B dissapear -> strange
744 // By keeping the last list of contextual primitive, we ensure that contextual selection
745 // remains visible when one click on one element in the currently displayed sequence
746 CInstance::TRefPtr _LastContextualLogicEntity;
747 std::vector<CInstance::TRefPtr> _LastContextualPrims;
752 private:
754 /////////////////////////////
755 // NETWORK EVENTS HANDLING //
756 /////////////////////////////
758 void nodeErased(const std::string& instanceId, const std::string& attrName, sint32 position);
760 void nodeInserted(const std::string& instanceId, const std::string& attrName, sint32 position,
761 const std::string& key, CObject* value);
763 virtual void nodeSet(const std::string& instanceId, const std::string& attrName, CObject* value);
766 void nodeMoved(const std::string& instanceId, const std::string& attrName, sint32 position,
767 const std::string& destInstanceId, const std::string& destAttrName, sint32 destPosition);
769 void scenarioUpdated(CObject* highLevel, bool willTP, uint32 startingActIndex);
771 // send the needed events to tell that the attr at 'attrName' inside 'parentInstance' (possibly at position (indexInArray') has been modified
772 void onAttrModified(CInstance &parentInstance, const std::string &attrName, sint32 indexInArray = -1);
774 // send the needed events to tell that an object has been modified (& propagate to parents)
775 void onAttrModified(const CObject *value);
778 void onResetEditionMode();
779 void onEditionModeConnected( uint32 userSlotId, uint32 adventureId, CObject* highLevel, const std::string& versionName, bool willTP, uint32 initialActIndex);
780 void onAnimationModeConnected(const CClientMessageAdventureUserConnection& connected);
781 void onEditionModeDisconnected();
782 void onTestModeConnected();
783 // deconnect from test or play
784 void onTestModeDisconnected(TSessionId sessionId, uint32 lasAct, TScenarioSessionType sessionType);
787 ///////////////////////////////////////////////////////
788 // EDITOR OBJECTS (instances) / CObjectTable mapping //
789 ///////////////////////////////////////////////////////
791 public:
792 // Get a CObjectTable from its id
793 const CObjectTable *getObjectTableFromId(const TInstanceId &id) const;
794 private:
795 // Erase the current Scenario (and block outgoing message)
796 void eraseScenario();
797 void onErase(CObject *object);
798 void onErase(CObject *object, bool &foundInBase, std::string &nameInParent);
799 /** Create a new CInstance for the given CObject
800 * - Displayer are attached
801 * - Object is inserted in the object map
802 * - 'onCreate' msg is sent
803 * 'obj' must be a table or it fails
805 void createNewInstanceForObjectTable(const CObject *obj);
806 void createNewInstanceForObjectTableInternal(const CObject *obj);
807 void onPostCreate(const CObject *obj);
809 void waitScenarioScreen();
811 public:
812 /** private : retrieve lua 'User' table attached to an object (a read / write table)
813 * The table is pushed on stack
815 static void getLuaUserTableFromObject(CLuaState &ls, const CObjectTable &table);
816 private:
818 //////////////////////////////////////
819 // EDITOR FUNCTIONS EXPORTED TO LUA //
820 //////////////////////////////////////
821 static int luaGetVisualPropertiesFromInstanceId(CLuaState &ls);
822 static int luaGetSelectedInstanceId(CLuaState &ls);
823 static int luaGetSelectedInstance(CLuaState &ls);
824 static int luaSetSelectedInstanceId(CLuaState &ls);
825 static int luaSetCurrentTool(CLuaState &ls);
826 static int luaGetCurrentTool(CLuaState &ls);
827 static int luaGetInstanceFromId(CLuaState &ls);
828 static int luaDisplayContextMenu(CLuaState &ls);
829 static int luaConnectAsCreator(CLuaState &ls);
830 static int luaDofile(CLuaState &ls); // equivalent of the 'dofile' lua function, but with more info output
831 static int luaTryFile(CLuaState &ls); // same as try file, but do not throw an exception on error, just return an error message and return false
832 static int luaSetEntityCustomSelectBox(CLuaState &ls);
833 static int luaGetEntityCustomSelectBox(CLuaState &ls);
834 static int luaChoosePos(CLuaState &ls);
835 static int luaSnapPosToGround(CLuaState &ls); // takes x, y, z as parameters and return the snapped position
836 static int luaGetUserEntityPosition(CLuaState &ls);
837 static int luaGetUserEntityFront(CLuaState &ls);
838 static int luaRequestSetLocalNode(CLuaState &ls);
839 static int luaRequestCommitLocalNode(CLuaState &ls);
840 static int luaRequestRollbackLocalNode(CLuaState &ls);
841 static int luaSetCurrentActFromId(CLuaState &ls);
842 static int luaGetCurrentAct(CLuaState &ls);
843 static int luaAddInstanceObserver(CLuaState &ls); // param 1 = instance id of the instance to observe
844 // param 2 = table of an object that will receive notifications. The table should contain methods
845 // with the same names than those found in 'IInstanceObserver' (plus parameters are the same)
846 // the method returns a handle for future deletion
847 static int luaRemoveInstanceObserver(CLuaState &ls); // remove an observer that was previously added by a 'addInstanceObserver'
848 // param 1 = the handle returned by 'addInstanceObserver' at the registration time
849 // returns a reference to the observer that was registered
850 static int luaGenInstanceName(CLuaState &ls); // calls CEditor::genInstanceName, same parameters
851 // NB : return has type 'ucstring', so may need to call :toUtf8() in the lua script
852 static int luaIsPostFixedByNumber(CLuaState &ls);
853 static int luaIsClearingContent(CLuaState &ls);
854 static int luaSetCookie(CLuaState &ls); // same than CEditor::setCookie
855 static int luaIsCreature(CLuaState &ls);
856 static int luaSetEditorSeason(CLuaState &ls); // set the weather to display when editing
857 static int luaSetFixedLighting(CLuaState &ls);
858 static int luaGetFixedLighting(CLuaState &ls);
859 static int luaSetPlotItemInfos(CLuaState &ls);
860 static int luaIsCurrentSelectionPlayer(CLuaState &ls);
861 static int luaFindEmptyPlace(CLuaState &ls);
862 static int luaIsInIslandRect(CLuaState &ls); // test if pos is in the current island (not necessarily a valid pos, but inside the island rect)
863 // takes x, y as entry, returns true on success
865 static int luaGetCurrentIslandName(CLuaState &ls);
867 static int luaWaitScenarioScreen(CLuaState &ls); // display the wait screen after the scenario creation has been launched
868 static int luaIsScenarioUpdating(CLuaState &ls);
870 // undo / redo possible ?
871 static int luaCanUndo(CLuaState &ls);
872 static int luaCanRedo(CLuaState &ls);
873 // return the name of the editer
874 static sint luaGetUserEntityName(CLuaState &ls);
876 static int luaGetStartingAnimationFilename(CLuaState &ls);
878 static int luaKickCharacter(CLuaState &ls);
879 static int luaUnkickCharacter(CLuaState &ls);
880 static int luaTeleportToCharacter(CLuaState &ls);
881 static int luaEnumInstances(CLuaState &ls);
884 void connect();
886 // remove all object from the entity manager (but the player)
887 static void removeAllEntitySlots();
890 ////////////////
891 // PLOT ITEMS //
892 ////////////////
894 public:
895 static uint getMaxNumPlotItems();
896 static NLMISC::CCDBNodeLeaf *getPlotItemSheetDBLeaf(uint index);
897 static bool getIsStartingScenario() { return _IsStartingScenario; }
898 bool isClearingContent() const { return _ClearingContent; }
899 void registerLuaFunc();
901 private:
902 void initPlotItems();
903 void initReferencePlotItems();
904 static void initDummyPlotItems();
905 void resetPlotItems();
906 static void setReferencePlotItemSheet(uint index, uint32 sheetId);
907 static NLMISC::CCDBNodeLeaf *getRefPlotItemSheetDBLeaf(uint index);
909 //////////
910 // MISC //
911 //////////
912 void setMaxVisibleEntityExceededFlag(bool on);
913 void backupRequestCommands();
914 void restoreRequestCommands();
915 void setForceDesktopReset(bool force);
916 void setUIMode(uint8 mode);
917 bool loadUIConfig(const std::string &prefix);
918 void loadStandardUI();
919 void saveUIConfig();
920 void hideRingWindows();
921 std::string getUIPrefix(TMode mode) const;
922 void loadKeySet(const std::string &keySet);
923 static std::string getKeySetPrefix(TMode mode);
924 void saveCurrentKeySet();
925 void reloadUI(const char *filename);
926 void initHighlightDecal();
927 void updateDecalBlendRegion(CDecal &decal, const NLMISC::CVector &pos);
928 void initPalette();
929 void initObjectProjectionMetatable();
930 void registerDisplayers();
931 void registerTools();
933 // add a C++ method in the environement
934 void registerEnvMethod(const char *name, TLuaWrappedFunction func);
935 void registerEnvFunction(const char *name, TLuaWrappedFunction func);
936 // Initialisation of contextual cursor.
937 void initDecals();
938 void showDecal(const NLMISC::CVector2f &pos, float scale, CDecal &decal, const CDecalAnim &decalAnim);
939 void updatePrimitiveContextualVisibility();
940 void initClassInheritanceTable();
941 // contextual mouse handling
942 static void checkCursor();
943 // Forward click from contextual cursor to current tool
944 static void mouseClick(bool rightButton, bool dblClick);
945 // callback to reload the editor when one of the config files changed
946 static void reloadEditorCallback(const std::string &filename);
947 // update the display of decals created when the player select an instance in the scene
948 void updateSelectingDecals();
949 // display of highlight or select box (for selection of huge objects)
950 // the CDecalAnim is used to mimic the color cycle seen when standard selection circle is displayed
951 // (no CPrimRenderAnim for now)
952 void showPrimRender(CPrimRender &dest, const NLMISC::CAABBox &localBox, const NLMISC::CMatrix &worldMat, const CDecalAnim &refDecalAnim);
954 CLuaObject _OldLuaRequestInsertNode;
955 CLuaObject _OldLuaRequestInsertGhostNode;
956 CLuaObject _OldLuaRequestSetNode;
957 CLuaObject _OldLuaRequestEraseNode;
958 CLuaObject _OldLuaRequestMoveNode;
960 bool _ClearingContent;
962 std::string _ConnectionMsg;
963 static std::string _ScenarioToLoadWhenEntreringIntoAnimation;
964 static bool _IsStartingScenario; // the scenario is an animation scenario launch from the ring access point
966 //bool _ModeEnabled[ModeCount];
968 public:
969 // private method
970 CInstance *getInstanceFromObject(const CObject *obj) const; // nb : only table have associated instance
971 void connectAsCreator();
972 // notify obervers of an instance that it has been created
973 void notifyInstanceObserversOfCreation(CInstance &inst);
975 // TMP for debug : dump missing collisions in the log
976 void checkMissingCollisions();
978 // trigger an instance observers for the given instance id. A copy of the observer list is made, thus
979 // allowing for safe removal of observer when they are triggered
980 struct IObserverAction
982 virtual ~IObserverAction() { }
983 virtual void doAction(IInstanceObserver &obs) = 0;
985 void triggerInstanceObserver(const TInstanceId &id, IObserverAction &action);
987 static void setStartingAnimationFilename(const std::string& filename);
989 // for CInstance usage : allows to keep a list of instances sorted by their display name
990 void registerInstanceDispName(const ucstring &displayName, CInstance *inst);
991 void unregisterInstanceDispName(CInstance *inst);
995 // shortcut function to get the editor
996 inline CEditor &getEditor() { return CEditor::getInstance(); }
998 // test whether editor is currently enabled and is in EDITION mode. (In this mode, selection is managed by the editor rather than by the entity manager)
999 bool isEditionCurrent();
1001 /** helper to create a class from the registry
1002 * \TODO a true factory class!
1003 * \TODO or put this in a better place (NLMISC ? )
1005 template <class T>
1006 T *createObjectFromClassName(const std::string &className)
1008 if (className.empty()) return NULL;
1011 NLMISC::IClassable *obj = NLMISC::CClassRegistry::create(className);
1012 if (!obj)
1014 nlwarning("Couldn't create object of class %s", className.c_str());
1015 return NULL;
1017 T *inst = dynamic_cast<T *>(obj);
1018 if (!inst)
1020 nlwarning("<R2::createObjectFromClassName> class %s found in the registry, but does not match the expected class.",
1021 obj->getClassName().c_str());
1022 delete obj;
1023 return NULL;
1025 return inst;
1027 catch(const NLMISC::ERegistry &)
1029 return NULL;
1033 extern bool ResetWanted;
1034 extern bool ResetScenarioWanted;
1035 extern bool ReloadScenarioWanted;
1036 extern bool ConnectionWanted;
1041 // helper : get a NLMISC::CVector from a DMC::CObject
1042 NLMISC::CVector getVector(const CObject *obj);
1043 NLMISC::CVectorD getVectorD(const CObject *obj);
1044 //helper : build a CObject from a NLMISC::CVectorD
1045 CObject *buildVector(const NLMISC::CVectorD &v, const std::string &instanceId = "");
1049 // DMC helpers:
1050 std::string getString(const CObject *obj, const std::string &attrName);
1051 double getNumber(const CObject *obj, const std::string &attrName);
1052 const CObject *getObject(const CObject *obj, const std::string &attrName);
1054 /** Helper : read an enum from a lua string, printing necessary error if no match is found.
1055 * nil found -> no op
1057 template <class T>
1058 void enumFromLua(const CLuaObject &value,
1059 std::pair<std::string, T> *enumTable,
1060 uint numEnum,
1061 T &dest,
1062 const std::string &errorMsgPrefix
1065 if (value.isNil())
1067 return;
1069 if (!value.isString())
1071 nlwarning("%s : String expected when reading '%s'", errorMsgPrefix.c_str(), value.getId().c_str());
1072 return;
1074 for(uint k = 0; k < numEnum; ++k)
1076 if (value.toString() == enumTable[k].first)
1078 dest = enumTable[k].second;
1079 return;
1082 nlwarning("%s : Unknown enum %s read from object %s", errorMsgPrefix.c_str(),
1083 value.toString().c_str(),
1084 value.getId().c_str());
1088 } // R2
1090 bool IsInRingMode();
1093 #endif