1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
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/>.
23 #include "nel/gui/lua_object.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"
40 #include "game_share/object.h"
41 #include "game_share/scenario_entry_points.h"
42 #include "game_share/r2_types.h"
61 class CDynamicMapService
;
62 class CUserComponentsManager
;
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 :
83 * No tool is displayed as "highlighted"
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
94 * RCLICK -> cancel & restore default tool
96 * NB : we don't do creation on LDOWN or RUP in order to allow camera manipulation
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...)
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.
114 * LDOWN / RDOWN -> cancel the menu
116 * III CAPTURED BY UI MODE
117 * =======================
118 * ... same as 'context menu mode'
122 * The current tool icon is highlighted in the toolbar
124 * std tool includes :
129 * 1) Mouse in 3D view
130 * --------------------
131 * a ) Mouse over empty space in scene
132 * -----------------------------------
133 * The standard mouse cursor is displayed
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
142 * b ) Mouse over an instance in scene that is not the selection
143 * -------------------------------------------------------------
144 * The mouse with a little circle is displayed
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
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
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 ...
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
192 class CEditor
: public NLMISC::CSingleton
<CEditor
>
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
};
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 ...)
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
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();
237 // clear all content in the map, client side
240 bool isInitialized() const { return _Initialized
; }
241 // (re)load the ui if its date changed
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 /////////////////////
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
264 // Handle paste, reaches the editor if no edit box is currently active
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).
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
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
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
);
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
);
497 CIslandCollision
&getIslandCollision() { return _IslandCollision
; }
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();
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
544 bool checkRoomLeft();
545 // display an error msg to prompt the user to make room for new objects in its scenario
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,
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;
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;
590 CEntitySorter
*_EntitySorter
;
593 // mapping from sheet id to plot item name
594 std::map
<uint32
, TMissionItem
> _PlotItemInfos
;
595 CIslandCollision _IslandCollision
;
598 bool _SerializeUIConfig
;
600 TAccessMode _AccessMode
;
602 typedef std::map
<const CObjectTable
*, CInstance::TSmartPtr
> TInstanceMap
;
605 CLuaObject _Globals
; // match to the '_G' lua global variable
606 CLuaObject _Registry
;
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
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(); }
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)
645 bool isRegisteredByDispName(CInstance
*inst
) const;
647 // Cookies (local objects attached to instances at creation time, see setCookie)
653 typedef std::list
<CCookie
> TCookieList
; // for a single instance, map each key to its value
654 typedef std::map
<TInstanceId
, TCookieList
> TCookieMap
;
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
;
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
692 std::vector
<NLMISC::CSmartPtr
<CSelectingDecal
> > _SelectingDecals
;
693 sint64 _DecalRefTime
; // reference time for "decals" animation
695 bool _EnteredInSetSelectedInstance
; // prevent recursive call from CEditor::setSelectedInstance
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
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 :
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
;
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 ///////////////////////////////////////////////////////
792 // Get a CObjectTable from its id
793 const CObjectTable
*getObjectTableFromId(const TInstanceId
&id
) const;
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();
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
);
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
);
886 // remove all object from the entity manager (but the player)
887 static void removeAllEntitySlots();
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();
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
);
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();
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
);
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.
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];
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 ? )
1006 T
*createObjectFromClassName(const std::string
&className
)
1008 if (className
.empty()) return NULL
;
1011 NLMISC::IClassable
*obj
= NLMISC::CClassRegistry::create(className
);
1014 nlwarning("Couldn't create object of class %s", className
.c_str());
1017 T
*inst
= dynamic_cast<T
*>(obj
);
1020 nlwarning("<R2::createObjectFromClassName> class %s found in the registry, but does not match the expected class.",
1021 obj
->getClassName().c_str());
1027 catch(const NLMISC::ERegistry
&)
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
= "");
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
1058 void enumFromLua(const CLuaObject
&value
,
1059 std::pair
<std::string
, T
> *enumTable
,
1062 const std::string
&errorMsgPrefix
1069 if (!value
.isString())
1071 nlwarning("%s : String expected when reading '%s'", errorMsgPrefix
.c_str(), value
.getId().c_str());
1074 for(uint k
= 0; k
< numEnum
; ++k
)
1076 if (value
.toString() == enumTable
[k
].first
)
1078 dest
= enumTable
[k
].second
;
1082 nlwarning("%s : Unknown enum %s read from object %s", errorMsgPrefix
.c_str(),
1083 value
.toString().c_str(),
1084 value
.getId().c_str());
1090 bool IsInRingMode();