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>
6 // Copyright (C) 2013-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as
10 // published by the Free Software Foundation, either version 3 of the
11 // License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Affero General Public License for more details.
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "nel/misc/path.h"
25 #include "nel/misc/i18n.h"
26 #include "nel/misc/sheet_id.h"
27 #include "nel/misc/polygon.h"
28 #include "nel/misc/time_nl.h"
30 #include "nel/3d/u_driver.h"
31 #include "nel/3d/u_text_context.h"
33 #include "nel/ligo/ligo_config.h"
34 #include "nel/net/unified_network.h"
35 #include "nel/net/module_manager.h"
36 #include "nel/pacs/u_global_retriever.h"
39 #include "game_share/r2_share_itf.h"
40 #include "game_share/r2_messages.h"
41 #include "game_share/scenario_entry_points.h"
43 #include "dmc/dmc.h" // client interface to the dynamic scenario service
44 #include "dmc/client_edition_module.h"
45 #include "dmc/property_accessor.h"
46 #include "dmc/com_lua_module.h"
47 #include "game_share/dms.h"
49 #include "../client_sheets/item_sheet.h"
53 #include "nel/gui/lua_helper.h"
54 #include "nel/gui/group_tree.h"
55 #include "../interface_v3/interface_manager.h"
56 #include "../contextual_cursor.h"
57 #include "../cursor_functions.h"
58 #include "../entities.h"
59 #include "../events_listener.h"
60 #include "nel/gui/group_list.h"
61 #include "nel/gui/event_descriptor.h"
62 #include "nel/gui/group_tree.h"
63 #include "../client_cfg.h"
64 #include "nel/gui/lua_ihm.h"
65 #include "../interface_v3/lua_ihm_ryzom.h"
66 #include "nel/gui/lua_object.h"
67 #include "../global.h"
68 #include "../connection.h"
69 #include "../main_loop.h"
70 #include "../interface_v3/people_interraction.h"
71 #include "../time_client.h"
72 #include "../pacs_client.h"
73 #include "nel/gui/lua_ihm.h"
74 #include "../actions.h"
75 #include "../actions_client.h"
76 #include "object_factory_client.h"
77 #include "../weather.h"
78 #include "../light_cycle_manager.h"
79 #include "../dummy_progress.h"
80 #include "../continent_manager.h"
81 #include "../world_database_manager.h"
82 #include "../init_main_loop.h"
83 #include "../net_manager.h"
84 #include "../interface_v3/input_handler_manager.h"
85 #include "../connection.h"
86 #include "../init_main_loop.h"
87 #include "nel/gui/group_editbox.h"
88 #include "../landscape_poly_drawer.h"
90 #include "../motion/user_controls.h"
91 #include "../game_context_menu.h"
92 #include "../interface_v3/macrocmd_manager.h"
94 #include "../player_r2_cl.h"
95 #include "palette_node.h"
96 #include "tool_create_entity.h"
97 #include "tool_select_move.h"
98 #include "tool_new_vertex.h"
99 #include "displayer_visual_entity.h"
100 #include "displayer_visual_group.h"
101 #include "displayer_visual_shape.h"
102 #include "displayer_visual_activity_sequence.h"
103 #include "displayer_lua.h"
104 #include "verbose_clock.h"
105 #include "r2_config.h"
106 #include "entity_sorter.h"
108 #include "tool_draw_prim.h"
109 #include "tool_select_move.h"
110 #include "tool_select_rotate.h"
111 #include "tool_choose_pos_lua.h"
115 #include "../sheet_manager.h"
117 #include "../session_browser_impl.h"
118 #include "../far_tp.h"
119 #include "nel/gui/lua_manager.h"
122 #define new DEBUG_NEW
125 using namespace NLMISC
;
126 using namespace NLNET
;
127 using namespace NL3D
;
128 using namespace NLGUI
;
130 extern CEventsListener EventsListener
;
132 extern CGameContextMenu GameContextMenu
;
133 extern void badXMLParseMessageBox();
135 R2::TUserRole UserRoleInSession
;
137 #define OPERATOR_EQUAL(X,Y) X==Y
138 //#define OPERATOR_EQUAL(X, Y) ::operator==(X,Y)
146 CEditorCheck() { check(); }
147 ~CEditorCheck() { check(); }
150 if (!EditorCreated
) return; // avoid infinite loop
151 if (getEditor().getMode() != CEditor::NotInitialized
)
153 nlassert(getEditor().getEnv().isValid());
156 static bool EditorCreated
;
160 bool CEditorCheck::EditorCreated
= false;
163 #define CHECK_EDITOR CEditorCheck __ec;
165 #define CHECK_EDITOR (void) 0;
170 const char *DEFAULT_CURSOR
= "curs_default.tga";
172 bool ResetWanted
= false;
173 bool ReloadUIFlag
= true; // by default, CEditor loads its own UI
174 bool ResetScenarioWanted
= false;
175 bool ReloadScenarioWanted
= false;
176 bool ConnectionWanted
= false;
177 std::string
CEditor::_ScenarioToLoadWhenEntreringIntoAnimation
;
178 bool CEditor::_IsStartingScenario
=false;
180 // *********************************************************************************************************
181 /** this class forward modification events from the network so that the editor can
182 * update its state to match the current state of the map
184 class CDynamicMapClientEventForwarder
: public CDynamicMapClient
187 CDynamicMapClientEventForwarder(const std::string
&eid
, NLNET::IModuleSocket
* clientGateway
, lua_State
*luaState
);
188 virtual void nodeErased(const std::string
& instanceId
, const std::string
& attrName
, sint32 position
);
189 virtual void nodeSet(const std::string
& instanceId
, const std::string
& attrName
, CObject
* value
);
190 virtual void nodeInserted(const std::string
& instanceId
, const std::string
& attrName
, sint32 position
,
191 const std::string
& key
, CObject
* value
);
192 virtual void nodeMoved(const std::string
& instanceId
, const std::string
& attrName
, sint32 position
,
193 const std::string
& destInstanceId
, const std::string
& destAttrName
, sint32 destPosition
);
194 virtual void scenarioUpdated(CObject
* highLevel
, bool willTP
, uint32 initialActIndex
);
196 virtual void onAnimationModeConnected(const CClientMessageAdventureUserConnection
& connected
);
197 virtual void onEditionModeConnected( uint32 userSlotId
, uint32 adventureId
, CObject
* highLevel
, const std::string
& versionName
, bool willTP
, uint32 initialActIndex
);
198 virtual void onEditionModeDisconnected();
199 virtual void onResetEditionMode();
200 virtual void onTestModeConnected();
201 virtual void onTestModeDisconnected(TSessionId sessionId
, uint32 lasAct
, TScenarioSessionType sessionType
);
205 CDynamicMapClientEventForwarder::CDynamicMapClientEventForwarder(const std::string
&eid
, NLNET::IModuleSocket
* clientGateway
, lua_State
*luaState
) :
206 CDynamicMapClient(eid
, clientGateway
, luaState
)
212 void CDynamicMapClientEventForwarder::nodeErased(const std::string
& instanceId
, const std::string
& attrName
, sint32 position
)
214 //H_AUTO(R2_CDynamicMapClientEventForwarder_nodeErased)
215 if (getEditor().getMode() != CEditor::EditionMode
)
217 nlassert(getEditor().getMode() != CEditor::AnimationModeLoading
); /* Probably should not happen */
218 nldebug("Node erased, but not in edition mode");
221 getEditor().nodeErased(instanceId
, attrName
, position
);
224 void CDynamicMapClientEventForwarder::nodeSet(const std::string
& instanceId
, const std::string
& attrName
, CObject
* value
)
226 //H_AUTO(R2_CDynamicMapClientEventForwarder_nodeSet)
227 if (getEditor().getMode() != CEditor::EditionMode
228 && getEditor().getMode() != CEditor::AnimationModeLoading
/* Loading animation scenario from terminal, ghost nodes created by translator */)
230 nldebug("Node set, but not in edition mode");
233 getEditor().nodeSet(instanceId
, attrName
, value
);
236 void CDynamicMapClientEventForwarder::nodeInserted(const std::string
& instanceId
, const std::string
& attrName
, sint32 position
,
237 const std::string
& key
, CObject
* value
)
239 //H_AUTO(R2_CDynamicMapClientEventForwarder_nodeInserted)
240 if (getEditor().getMode() != CEditor::EditionMode
241 && getEditor().getMode() != CEditor::AnimationModeLoading
/* Loading animation scenario from terminal, ghost nodes created by translator */)
243 nldebug("Node inserted, but not in edition mode");
246 getEditor().nodeInserted(instanceId
, attrName
, position
, key
, value
);
249 void CDynamicMapClientEventForwarder::nodeMoved(
250 const std::string
& instanceId
, const std::string
& attrName
, sint32 position
,
251 const std::string
& destInstanceId
, const std::string
& destAttrName
, sint32 destPosition
)
253 //H_AUTO(R2_CDynamicMapClientEventForwarder_nodeMoved)
254 if (getEditor().getMode() != CEditor::EditionMode
)
256 nlassert(getEditor().getMode() != CEditor::AnimationModeLoading
); /* Probably should not happen */
257 nldebug("Node moved, but not in edition mode");
260 getEditor().nodeMoved(instanceId
, attrName
, position
, destInstanceId
, destAttrName
, destPosition
);
263 void CDynamicMapClientEventForwarder::scenarioUpdated(CObject
* highLevel
, bool willTP
, uint32 initialActIndex
)
265 //H_AUTO(R2_CDynamicMapClientEventForwarder_scenarioUpdated)
266 if (getEditor().getMode() != CEditor::EditionMode
267 && getEditor().getMode() != CEditor::GoingToEditionMode
/* New scenario */
268 && getEditor().getMode() != CEditor::AnimationModeLoading
/* Loading animation scenario from terminal */)
270 nldebug("Scenario update received, but not in edition mode");
273 getEditor().scenarioUpdated(highLevel
, willTP
, initialActIndex
);
277 void CDynamicMapClientEventForwarder::onEditionModeConnected( uint32 userSlotId
, uint32 adventureId
, CObject
* highLevel
, const std::string
& versionName
, bool willTP
, uint32 initialActIndex
)
279 //H_AUTO(R2_CDynamicMapClientEventForwarder_onEditionModeConnected)
280 getEditor().onEditionModeConnected(userSlotId
, adventureId
, highLevel
, versionName
, willTP
, initialActIndex
);
283 void CDynamicMapClientEventForwarder::onEditionModeDisconnected()
285 //H_AUTO(R2_CDynamicMapClientEventForwarder_onEditionModeDisconnected)
286 getEditor().onEditionModeDisconnected();
289 void CDynamicMapClientEventForwarder::onResetEditionMode()
291 //H_AUTO(R2_CDynamicMapClientEventForwarder_onResetEditionMode)
292 getEditor().onResetEditionMode();
295 void CDynamicMapClientEventForwarder::onTestModeConnected()
297 //H_AUTO(R2_CDynamicMapClientEventForwarder_onTestModeConnected)
298 getEditor().onTestModeConnected();
301 void CDynamicMapClientEventForwarder::onTestModeDisconnected(TSessionId sessionId
, uint32 lastAct
, TScenarioSessionType sessionType
)
303 //H_AUTO(R2_CDynamicMapClientEventForwarder_onTestModeDisconnected)
304 getEditor().onTestModeDisconnected(sessionId
, lastAct
, sessionType
);
307 void CDynamicMapClientEventForwarder::onAnimationModeConnected(const CClientMessageAdventureUserConnection
& connected
)
309 //H_AUTO(R2_CDynamicMapClientEventForwarder_onAnimationModeConnected)
310 getEditor().onAnimationModeConnected(connected
);
313 // *********************************************************************************************************
316 //H_AUTO(R2_CEditor_CEditor)
317 _SelectedInstance
= NULL
;
318 _FocusedInstance
= NULL
;
320 _EnteredInSetSelectedInstance
= false;
322 _Initialized
= false;
323 //vianney?? _LastUIModificationDate = 0;
324 _InstanceObserverHandleCounter
= 0;
325 // module are initialized one time and never reconnected
328 _Mode
= NotInitialized
;
329 _AccessMode
= AccessModeUnknown
;
330 _SerializeUIConfig
= true;
331 _LastAutoSaveTime
= NLMISC::CTime::getLocalTime();// wait ClientCfg.R2EDAutoSaveWait
332 setForceDesktopReset(false);
333 CEditorCheck::EditorCreated
= true;
334 _ClearingContent
= false;
335 _Season
= UnknownSeason
;
336 _IsWaitingTPForSeasonChange
= true;
337 _UpdatingScenario
= false;
339 _FixedLighting
= false;
341 _ScenarioReceivedFlag
= false;
342 _TPReceivedFlag
= false;
343 _WaitScenarioScreenWanted
= false;
344 _WaitScenarioScreenActive
= false;
346 _NewScenarioInitialAct
= 0;
347 _EditionModeDisconnectedFlag
= true;
348 _PostponeScenarioUpdated
= false;
349 _EntitySorter
= NULL
;
350 _MaxVisibleEntityExceededFlag
= false;
353 // *********************************************************************************************************
354 void CEditor::setForceDesktopReset(bool force
)
356 //H_AUTO(R2_CEditor_setForceDesktopReset)
358 std::fill(_ForceDesktopReset
, _ForceDesktopReset
+ sizeofarray(_ForceDesktopReset
), force
);
361 // *********************************************************************************************************
362 void CEditor::autoConfigInit(bool serverIsRingSession
)
364 //H_AUTO(R2_CEditor_autoConfigInit)
366 if (ClientCfg
.R2EDEnabled
)
368 // Editor and Animator (DM) modes
371 TAccessMode initialAccessMode
;
372 switch (UserRoleInSession
.getValue())
374 case R2::TUserRole::ur_editor
:
375 initialMode
= R2::CEditor::EditionMode
;
376 initialAccessMode
= R2::CEditor::AccessEditor
;
378 case R2::TUserRole::ur_animator
:
379 initialMode
= R2::CEditor::AnimationModeDm
;
380 initialAccessMode
= R2::CEditor::AccessDM
;
382 case R2::TUserRole::ur_outland_owner
:
383 initialMode
= R2::CEditor::AnimationModeDm
;
384 initialAccessMode
= R2::CEditor::AccessOutlandOwner
;
386 case R2::TUserRole::ur_player
:
387 initialMode
= R2::CEditor::AnimationModePlay
;
388 // NOTE: I'm not sure if 'editor' is the right mode here - but I can't find anything better for now
389 // If I try 'AccessModeUnknown' the code asserts later on.
390 initialAccessMode
= R2::CEditor::AccessEditor
;
393 nlwarning( "Unexpected user role %u while editor enabled", (uint
)(UserRoleInSession
.getValue()) );
394 initialMode
= R2::CEditor::EditionMode
;
395 initialAccessMode
= R2::CEditor::AccessEditor
;
397 init(initialMode
, initialAccessMode
);
401 // Normal player and Ring player modes
402 ActionsContext
.setContext("game");
403 if (serverIsRingSession
)
405 if (UserRoleInSession
.getValue() != R2::TUserRole::ur_player
)
406 nlwarning( "Unexpected user role %u while editor disabled", (uint
)(UserRoleInSession
.getValue()) );
411 // *********************************************************************************************************
412 void CEditor::autoConfigRelease(bool serverIsRingSession
)
414 //H_AUTO(R2_CEditor_autoConfigRelease)
415 if (ClientCfg
.R2EDEnabled
)
417 R2::getEditor().release();
418 R2::getEditor().releaseModules();
420 else if (serverIsRingSession
)
421 R2::getEditor().releaseModules();
424 // *********************************************************************************************************
425 void CEditor::initModules(bool connectDMC
)
427 //H_AUTO(R2_CEditor_initModules)
429 IModuleManager
&mm
= IModuleManager::getInstance();
431 IModule
*gateway
= mm
.createModule("StandardGateway", "clientGw", "");
432 nlassert(gateway
!= NULL
);
433 NLNET::IModuleSocket
*socketClientGw
= mm
.getModuleSocket("clientGw");
434 nlassert(socketClientGw
!= NULL
);
435 // connect the client gateway to the server
436 CCommandRegistry::getInstance().execute("clientGw.transportAdd FEClient fec", *InfoLog
);
437 if (!ClientCfg
.Local
)
439 CCommandRegistry::getInstance().execute("clientGw.transportCmd fec(open)", *InfoLog
);
444 _DMS
= new CDynamicMapService(ClientCfg
.ConfigFile
, socketClientGw
);
452 _DMC
= new CDynamicMapClientEventForwarder("Client0",socketClientGw
, getLua().getStatePointer());
454 _DMC
= new CDynamicMapClient("Client0",socketClientGw
, getLua().getStatePointer());
456 _DMC
->setInstantFeedBackFlag(true);
460 // *********************************************************************************************************
462 void CEditor::releaseModules()
464 //H_AUTO(R2_CEditor_releaseModules)
466 delete _DMC
; // must have a virtual destructor
472 IModuleManager
&mm
= IModuleManager::getInstance();
473 NLNET::IModule
* clientGw
= mm
.getLocalModule("clientGw");
476 mm
.deleteModule(clientGw
);
479 _Initialized
= false;
482 // *********************************************************************************************************
483 void CEditor::inGameSelection(const CLFECOMMON::TCLEntityId
&/* slot */)
485 //H_AUTO(R2_CEditor_inGameSelection)
489 case AnimationModeDm
:
490 // reset current selection options
491 getEditor().callEnvMethod("updateAnimBarActions", 0);
494 getEditor().callEnvMethod("dssTarget", 1);
502 // *********************************************************************************************************
508 // ***************************************************************
509 void CEditor::requestSetLocalNode(const std::string
& instanceId
, const std::string
& attrName
, const CObject
*value
)
511 //H_AUTO(R2_CEditor_requestSetLocalNode)
517 CObject
*src
= _DMC
->find(instanceId
);
520 nlwarning("Can't find object with id %s", instanceId
.c_str());
523 if (!attrName
.empty())
525 CObject
*subObj
= src
->getAttr(attrName
);
528 CObject
* valueBase
= (CObject
*) getObject(src
, attrName
); // from Base
531 nlwarning("Can't find attribute %s inside object (or is base) with InstanceId = %s", attrName
.c_str(), instanceId
.c_str());
534 CObject
*valueClone
= valueBase
->clone();
535 valueClone
->setParent(0);
536 src
->setObject(attrName
, valueClone
);
537 subObj
= src
->getAttr(attrName
);
541 nlwarning("Can't find attribute %s inside object with InstanceId = %s", attrName
.c_str(), instanceId
.c_str());
549 getDMC().getPropertyAccessor().shadowValue(obj
, value
->clone());
554 // *****************************************
556 void CEditor::requestCommitLocalNode(const std::string
& instanceId
, const std::string
& attrName
)
558 //H_AUTO(R2_CEditor_requestCommitLocalNode)
560 CObject
*obj
= _DMC
->find(instanceId
, attrName
);
563 nlwarning("(while calling requestSetLocalNode");
567 //nlwarning("**** current unshadowed value");
571 // when requestSetNode is called, the old value can't be retrieved because it will
572 // be erased by 'commitValue', so backup old value
573 CObject *oldValueBackup = obj->clone();
576 getDMC().getPropertyAccessor().commitValue(obj);
577 getDMC().requestSetNode(instanceId, attrName, obj);
579 CObject
*localValue
= getDMC().getPropertyAccessor().getShadowingValue(obj
);
582 nlwarning("value is not shadowed : ");
586 CObject
*localValueBackup
= localValue
->clone();
587 getDMC().getPropertyAccessor().rollbackValue(obj
);
588 getDMC().requestSetNode(instanceId
, attrName
, localValueBackup
);
592 // ***************************************************************
593 void CEditor::requestRollbackLocalNode(const std::string
& instanceId
, const std::string
& attrName
)
595 //H_AUTO(R2_CEditor_requestRollbackLocalNode)
597 CObject
*obj
= _DMC
->find(instanceId
, attrName
);
600 nlwarning("(while calling requestSetLocalNode");
603 getDMC().getPropertyAccessor().rollbackValue(obj
);
604 // force the displayer to update their state from the shadowed value in place of the local value
608 // ***************************************************************
609 CInterfaceManager
&CEditor::getUI()
611 //H_AUTO(R2_CEditor_getUI)
613 CInterfaceManager
*im
= CInterfaceManager::getInstance();
618 // *********************************************************************************************************
619 CLuaState
&CEditor::getLua()
621 //H_AUTO(R2_CEditor_getLua)
623 CLuaState
*ls
= CLuaManager::getInstance().getLuaState();
628 // *********************************************************************************************************
629 CLuaObject
&CEditor::getEnv()
631 //H_AUTO(R2_CEditor_getEnv)
632 nlassert(_Env
.isValid());
636 // *********************************************************************************************************
637 CLuaObject
CEditor::getConfig()
639 //H_AUTO(R2_CEditor_getConfig)
641 return getEnv()["Config"];
644 // *********************************************************************************************************
645 void CEditor::clearDebugWindow()
647 //H_AUTO(R2_CEditor_clearDebugWindow)
649 getUI().flushDebugWindow();
650 CGroupList
*gl
= dynamic_cast<CGroupList
*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:debug_info:content:cb:text_list"));
653 gl
->deleteAllChildren();
657 // *********************************************************************************************************
658 // callback to reload the editor when one of the config files changed
659 void CEditor::reloadEditorCallback(const std::string
&filename
)
661 //H_AUTO(R2_CEditor_reloadEditorCallback)
664 if (nlstricmp(CFile::getExtension(filename
), "xml") == 0 ||
665 nlstricmp(CFile::getExtension(filename
), "uxt") == 0)
671 // *********************************************************************************************************
672 void CEditor::setFixedLighting(bool enabled
)
674 //H_AUTO(R2_CEditor_setFixedLighting)
675 if (_FixedLighting
== enabled
) return;
676 _FixedLighting
= enabled
;
677 LightCycleManager
.touch();
680 // *********************************************************************************************************
681 int CEditor::luaGetSelectedInstanceId(CLuaState
&ls
)
683 //H_AUTO(R2_CEditor_luaGetSelectedInstanceId)
685 if (!getEditor().getSelectedInstance())
691 ls
.push(toString(getEditor().getSelectedInstance()->getId()));
695 void CEditor::setStartingAnimationFilename(const std::string
& filename
)
697 //H_AUTO(R2_CEditor_setStartingAnimationFilename)
698 _ScenarioToLoadWhenEntreringIntoAnimation
= filename
;
700 // *********************************************************************************************************
702 int CEditor::luaGetStartingAnimationFilename(CLuaState
&ls
)
704 //H_AUTO(R2_CEditor_luaGetStartingAnimationFilename)
705 ls
.push( _ScenarioToLoadWhenEntreringIntoAnimation
);
708 // *********************************************************************************************************
709 int CEditor::luaSetSelectedInstanceId(CLuaState
&ls
)
711 //H_AUTO(R2_CEditor_luaSetSelectedInstanceId)
713 CLuaIHM::checkArgCount(ls
, "setSelectedInstance (method)", 2);
714 CLuaIHM::checkArgType(ls
, "setSelectedInstance", 2, LUA_TSTRING
);
715 if (strcmp(ls
.toString(2), "") == 0)
717 getEditor().setSelectedInstance(NULL
);
720 CInstance
*inst
= getEditor().getInstanceFromId(ls
.toString(2));
723 nlwarning("setSelectedInstance : Instance with Id %s not found", ls
.toString(2));
726 if (!inst
->getSelectableFromRoot())
728 nlwarning("Instance with id %s or one of its ancestor is not selectable", ls
.toString(2));
731 getEditor().setSelectedInstance(inst
);
735 // *********************************************************************************************************
736 int CEditor::luaSetCurrentTool(CLuaState
&ls
)
738 //H_AUTO(R2_CEditor_luaSetCurrentTool)
740 CLuaIHM::check(ls
, ls
.getTop() == 2 || ls
.getTop() == 3, "luaSetCurrentTool (method)");
741 CLuaIHM::checkArgType(ls
, "setCurrentTool", 2, LUA_TSTRING
);
742 if (ls
.strlen(2) == 0)
744 getEditor().setCurrentTool(NULL
);
748 CTool
*tool
= createObjectFromClassName
<CTool
>(ls
.toString(2));
751 if (ls
.getTop() == 3)
753 CLuaObject
initParams(ls
);
754 tool
->init(initParams
);
756 getEditor().setCurrentTool(tool
);
762 // *********************************************************************************************************
763 int CEditor::luaGetCurrentTool(CLuaState
&ls
)
765 //H_AUTO(R2_CEditor_luaGetCurrentTool)
767 CLuaIHM::checkArgCount(ls
, "getCurrentTool", 1); // 1 because of the method call
768 CLuaIHM::pushReflectableOnStack(ls
, getEditor().getCurrentTool());
772 // *********************************************************************************************************
773 int CEditor::luaGetSelectedInstance(CLuaState
&ls
)
775 //H_AUTO(R2_CEditor_luaGetSelectedInstance)
777 if (!getEditor().getSelectedInstance())
783 getEditor().projectInLua(getEditor().getSelectedInstance()->getObjectTable());
788 // *********************************************************************************************************
789 int CEditor::luaGetInstanceFromId(CLuaState
&ls
)
791 //H_AUTO(R2_CEditor_luaGetInstanceFromId)
793 const char *funcName
= "getInstanceFromId";
794 CLuaIHM::checkArgCount(ls
, funcName
, 2);
795 CLuaIHM::checkArgType(ls
, funcName
, 2, LUA_TSTRING
);
796 CInstance
*inst
= getEditor().getInstanceFromId(ls
.toString(2));
804 getEditor().projectInLua(inst
->getObjectTable());
810 // ********************************************************************************************************
811 int CEditor::luaGetVisualPropertiesFromInstanceId(CLuaState
&ls
)
813 //H_AUTO(R2_CEditor_luaGetVisualPropertiesFromInstanceId)
814 const char *funcName
= "getVisualPropertiesFromInstanceId";
816 CLuaIHM::checkArgCount(ls
, funcName
, 1);
817 CLuaIHM::checkArgType(ls
, funcName
, 1, LUA_TSTRING
); // instance sheetClient
819 CInstance
*inst
= getEditor().getInstanceFromId(ls
.toString(1));
820 if (!inst
) { return 0; }
823 CObject
*object
= inst
->getObjectTable();
824 if (!object
) { return 0; }
830 bool ok
= getEditor().getVisualPropertiesFromObject(object
, vA
, vB
, vC
);
837 uint64 uVPA
= vA
.get();
838 uint64 uVPB
= vB
.get();
839 uint64 uVPC
= vC
.get();
841 std::string strVPABC
= NLMISC::toString( "VPA:%016.16" NL_I64
"x\nVPB:%016.16" NL_I64
"x\nVPC:%016.16" NL_I64
"x", uVPA
, uVPB
, uVPC
);
848 // *********************************************************************************************************
849 int CEditor::luaDisplayContextMenu(CLuaState
&ls
)
851 //H_AUTO(R2_CEditor_luaDisplayContextMenu)
853 CLuaIHM::checkArgCount(ls
, "displayContextMenu", 1); // this is a method
854 getEditor().displayContextMenu();
858 // *********************************************************************************************************
859 int CEditor::luaConnectAsCreator(CLuaState
&ls
)
861 //H_AUTO(R2_CEditor_luaConnectAsCreator)
863 CLuaIHM::checkArgCount(ls
, "connectAsCreator", 1); // this is a method
864 //getEditor().connectAsCreator();
868 // *********************************************************************************************************
869 int CEditor::luaDofile(CLuaState
&ls
)
871 //H_AUTO(R2_CEditor_luaDofile)
873 CLuaIHM::checkArgCount(ls
, "doFile", 1);
874 CLuaIHM::checkArgType(ls
, "doFile", 1, LUA_TSTRING
);
875 getEditor().doLuaScript(ls
.toString(-1), ls
.toString(-1));
879 // *********************************************************************************************************
880 int CEditor::luaTryFile(CLuaState
&/* ls */)
882 //H_AUTO(R2_CEditor_luaTryFile)
884 CLuaIHM::checkArgCount(ls, "doFile", 1);
885 CLuaIHM::checkArgType(ls, "doFile", 1, LUA_TSTRING);
886 getEditor().doLuaScript(ls.toString(-1), ls.toString(-1));*/
890 // *********************************************************************************************************
891 int CEditor::luaSetEntityCustomSelectBox(CLuaState
&ls
)
893 //H_AUTO(R2_CEditor_luaSetEntityCustomSelectBox)
895 CLuaIHM::checkArgCount(ls
, "setEntityCustomSelectBox", 3); // 3 because of method call
896 CLuaIHM::checkArgType(ls
, "setEntityCustomSelectBox", 2, LUA_TSTRING
);
897 CLuaIHM::checkArgType(ls
, "setEntityCustomSelectBox", 3, LUA_TTABLE
);
898 std::string sheetName
= ls
.toString(2);
899 CEntityCustomSelectBox selectBox
;
901 selectBox
.fromTable(obj
);
902 TEntityCustomSelectBoxMap
&boxMap
= getEditor().getEntityCustomSelectBoxMap();
903 boxMap
[sheetName
] = selectBox
;
905 static volatile bool dumpMap = false;
908 for (TEntityCustomSelectBoxMap::const_iterator watchIt = boxMap.begin(); watchIt != boxMap.end(); ++ watchIt)
910 nlwarning(watchIt->first.c_str());
917 // *********************************************************************************************************
918 int CEditor::luaGetEntityCustomSelectBox(CLuaState
&ls
)
920 //H_AUTO(R2_CEditor_luaGetEntityCustomSelectBox)
922 CLuaIHM::checkArgCount(ls
, "getEntityCustomSelectBox", 2); // 3 because of method call
923 CLuaIHM::checkArgType(ls
, "getEntityCustomSelectBox", 2, LUA_TSTRING
);
924 std::string sheetName
= ls
.toString(2);
925 TEntityCustomSelectBoxMap boxMap
= getEditor().getEntityCustomSelectBoxMap();
926 if (boxMap
.count(sheetName
))
929 CLuaObject
result(ls
);
930 boxMap
[sheetName
].toTable(result
);
940 // *********************************************************************************************************
941 int CEditor::luaChoosePos(CLuaState
&ls
)
943 //H_AUTO(R2_CEditor_luaChoosePos)
945 const char *funcName
= "choosePos";
946 CLuaIHM::checkArgMin(ls
, funcName
, 5);
947 CLuaIHM::checkArgMax(ls
, funcName
, 10);
948 CLuaIHM::checkArgType(ls
, funcName
, 2, LUA_TSTRING
);
949 CLuaIHM::checkArgType(ls
, funcName
, 5, LUA_TSTRING
);
950 std::string toolName
= ls
.toString(5);
951 std::string cursValid
= "curs_create.tga";
952 std::string cursInvalid
= "curs_stop.tga";
953 if (ls
.getTop() >= 6)
955 CLuaIHM::checkArgType(ls
, funcName
, 6, LUA_TSTRING
);
956 cursValid
= ls
.toString(6);
958 if (ls
.getTop() >= 7)
960 CLuaIHM::checkArgType(ls
, funcName
, 7, LUA_TSTRING
);
961 cursInvalid
= ls
.toString(7);
963 // method param 1 -> sheet id
964 // method param 2 -> ok function
965 // method param 3 -> cancel function
967 CLuaObject
validFunc(ls
); // pop valid function
969 CLuaObject
cancelFunc(ls
); // pop cancel function
972 if (ls
.strlen(2) != 0)
974 CSheetId
sheetId(ls
.toString(2));
975 if (sheetId
== CSheetId::Unknown
)
977 nlwarning("Can't get sheet %s", ls
.toString(2));
980 ghostSlot
= 1; // TMP TMP
981 if (!createEntity(ghostSlot
, sheetId
, CVector::Null
, 0.f
))
983 nlwarning("Cannot create entity for sheet %s", ls
.toString(2));
989 ghostSlot
= -1; // no representation in scene
991 // additionnal polys displayed by the choose pos
992 std::vector
<NLMISC::CPolygon2D
> polys
;
994 CPrimLook invalidLook
;
995 if (ls
.getTop() >= 8)
997 CLuaStackRestorer
lsr(&ls
, ls
.getTop());
998 CLuaIHM::checkArgType(ls
, funcName
, 8, LUA_TTABLE
);
1002 ENUM_LUA_TABLE(poly
, it
)
1004 NLMISC::CPolygon2D newPoly
;
1005 it
.nextValue().push();
1006 CLuaIHM::getPoly2DOnStack(ls
, -1, newPoly
);
1008 polys
.push_back(newPoly
);
1011 if (ls
.getTop() >= 9)
1016 validLook
.init(look
);
1018 if (ls
.getTop() >= 10)
1023 invalidLook
.init(look
);
1026 getEditor().setCurrentTool(new CToolChoosePosLua(ghostSlot
, validFunc
, cancelFunc
, toolName
, cursValid
, cursInvalid
, polys
, validLook
, invalidLook
));
1030 // *********************************************************************************************************
1031 int CEditor::luaSnapPosToGround(CLuaState
&ls
)
1033 //H_AUTO(R2_CEditor_luaSnapPosToGround)
1035 const char *funcName
= "snapPosToGround";
1036 CLuaIHM::checkArgCount(ls
, funcName
, 3);
1037 CLuaIHM::checkArgType(ls
, funcName
, 2, LUA_TNUMBER
);
1038 CLuaIHM::checkArgType(ls
, funcName
, 3, LUA_TNUMBER
);
1040 /*NLPACS::UGlobalPosition gpos = GR->retrievePosition(CVector((float) ls.toNumber(2), (float) ls.toNumber(3), 2000.f));
1041 if (gpos.InstanceId != -1)
1043 CVector snappedPos = GR->getGlobalPosition(gpos);
1044 ls.push(snappedPos.x);
1045 ls.push(snappedPos.y);
1046 ls.push(snappedPos.z);
1056 // new algo : to avoid to snapping to a cliff, start from the approximate (valid) height found in the height map
1058 if (CTool::computeWorldMapIntersection((float) ls
.toNumber(2), (float) ls
.toNumber(3), inter
) != CTool::NoIntersection
)
1073 // *********************************************************************************************************
1074 int CEditor::luaGetUserEntityPosition(CLuaState
&ls
)
1076 //H_AUTO(R2_CEditor_luaGetUserEntityPosition)
1078 const char *funcName
= "getUserEntityPosition";
1079 CLuaIHM::checkArgCount(ls
, funcName
, 1);
1080 ls
.push(UserEntity
->pos().x
);
1081 ls
.push(UserEntity
->pos().y
);
1082 ls
.push(UserEntity
->pos().z
);
1086 // *********************************************************************************************************
1087 int CEditor::luaGetUserEntityFront(CLuaState
&ls
)
1089 //H_AUTO(R2_CEditor_luaGetUserEntityFront)
1091 const char *funcName
= "getUserEntityPosition";
1092 CLuaIHM::checkArgCount(ls
, funcName
, 1);
1093 ls
.push(UserEntity
->front().x
);
1094 ls
.push(UserEntity
->front().y
);
1098 // *********************************************************************************************************
1099 int CEditor::luaRequestSetLocalNode(CLuaState
&ls
)
1101 //H_AUTO(R2_CEditor_luaRequestSetLocalNode)
1103 const char *funcName
= "requestSetLocalNode";
1104 CLuaIHM::checkArgCount(ls
, funcName
, 3);
1105 CLuaIHM::checkArgType(ls
, funcName
, 1, LUA_TSTRING
);
1106 CLuaIHM::checkArgType(ls
, funcName
, 2, LUA_TSTRING
);
1107 CObject
*object
= CComLuaModule::getObjectFromLua(ls
.getStatePointer());
1110 CLuaIHM::fails(ls
, "%s : can't read object from parameter 3", funcName
);
1112 getEditor().requestSetLocalNode(ls
.toString(1), ls
.toString(2), object
);
1117 // *********************************************************************************************************
1118 int CEditor::luaRequestCommitLocalNode(CLuaState
&ls
)
1120 //H_AUTO(R2_CEditor_luaRequestCommitLocalNode)
1122 const char *funcName
= "requestCommitLocalNode";
1123 CLuaIHM::checkArgCount(ls
, funcName
, 2);
1124 CLuaIHM::checkArgType(ls
, funcName
, 1, LUA_TSTRING
);
1125 CLuaIHM::checkArgType(ls
, funcName
, 2, LUA_TSTRING
);
1126 getEditor().requestCommitLocalNode(ls
.toString(1), ls
.toString(2));
1130 // *********************************************************************************************************
1131 int CEditor::luaRequestRollbackLocalNode(CLuaState
&ls
)
1133 //H_AUTO(R2_CEditor_luaRequestRollbackLocalNode)
1135 const char *funcName
= "requestRollbackLocalNode";
1136 CLuaIHM::checkArgCount(ls
, funcName
, 2);
1137 CLuaIHM::checkArgType(ls
, funcName
, 1, LUA_TSTRING
);
1138 CLuaIHM::checkArgType(ls
, funcName
, 2, LUA_TSTRING
);
1139 getEditor().requestRollbackLocalNode(ls
.toString(1), ls
.toString(2));
1143 // *********************************************************************************************************
1144 int CEditor::luaSetCurrentActFromId(CLuaState
&ls
)
1146 //H_AUTO(R2_CEditor_luaSetCurrentActFromId)
1148 const char *funcName
= "setCurrentActFromId";
1149 CLuaIHM::checkArgCount(ls
, funcName
, 2); // this is a method
1150 CLuaIHM::checkArgType(ls
, funcName
, 2, LUA_TSTRING
);
1151 CInstance
*act
= getEditor().getInstanceFromId(ls
.toString(2));
1153 if (getEditor()._ClearingContent
) { return 0; }
1156 nlwarning("%s : act with id %s not found", funcName
, ls
.toString(1));
1159 if (!act
->isKindOf("Act"))
1161 nlwarning("%s : instance with id %s is not an act", funcName
, ls
.toString(1));
1164 getEditor().setCurrentAct(act
);
1168 // *********************************************************************************************************
1169 int CEditor::luaGetCurrentAct(CLuaState
&ls
)
1171 //H_AUTO(R2_CEditor_luaGetCurrentAct)
1173 const char *funcName
= "getCurrentAct";
1174 CLuaIHM::checkArgCount(ls
, funcName
, 1); // this is a method
1175 if (getEditor().getCurrentAct())
1177 getEditor().projectInLua(getEditor().getCurrentAct()->getObjectTable());
1187 // *********************************************************************************************************
1188 int CEditor::luaGenInstanceName(CLuaState
&ls
)
1190 //H_AUTO(R2_CEditor_luaGenInstanceName)
1192 const char *funcName
= "genInstanceName";
1193 CLuaIHM::checkArgCount(ls
, funcName
, 2); // this is a method
1194 #ifdef RYZOM_LUA_UCSTRING
1195 CLuaIHM::checkArgTypeUCString(ls
, funcName
, 2); // name
1197 nlverify(CLuaIHM::getUCStringOnStack(ls
, 2, baseName
));
1198 CLuaIHM::push(ls
, getEditor().genInstanceName(baseName
));
1200 CLuaIHM::checkArgType(ls
, funcName
, 2, LUA_TSTRING
);
1201 ls
.push(getEditor().genInstanceName(ucstring::makeFromUtf8(ls
.toString(2))).toUtf8()); // FIXME: Ring UTF-8
1206 // *********************************************************************************************************
1207 int CEditor::luaIsPostFixedByNumber(CLuaState
&ls
)
1209 //H_AUTO(R2_CEditor_luaIsPostFixedByNumber)
1211 const char *funcName
= "isPostFixedByNumber";
1212 CLuaIHM::checkArgCount(ls
, funcName
, 2); // this is a method
1213 #ifdef RYZOM_LUA_UCSTRING
1214 CLuaIHM::checkArgTypeUCString(ls
, funcName
, 2); // name
1216 nlverify(CLuaIHM::getUCStringOnStack(ls
, 2, baseName
));
1217 ls
.push(getEditor().isPostFixedByNumber(baseName
));
1219 CLuaIHM::checkArgType(ls
, funcName
, 2, LUA_TSTRING
);
1220 ls
.push(getEditor().isPostFixedByNumber(ucstring::makeFromUtf8(ls
.toString(2)))); // FIXME: Ring UTF-8
1225 // *********************************************************************************************************
1226 int CEditor::luaIsClearingContent(CLuaState
&ls
)
1228 //H_AUTO(R2_CEditor_luaIsPostFixedByNumber)
1230 const char *funcName
= "isClearingContent";
1231 CLuaIHM::checkArgCount(ls
, funcName
, 1); // this is a method
1232 ls
.push(getEditor().isClearingContent());
1237 // *********************************************************************************************************
1238 int CEditor::luaSetCookie(CLuaState
&ls
)
1240 //H_AUTO(R2_CEditor_luaSetCookie)
1242 const char *funcName
= "setCookie";
1243 CLuaIHM::checkArgCount(ls
, funcName
, 4); // this is a method (self + 3 params)
1244 CLuaIHM::checkArgType(ls
, funcName
, 2, LUA_TSTRING
); // instance id
1245 CLuaIHM::checkArgType(ls
, funcName
, 3, LUA_TSTRING
); // key
1246 // last parameters may have any type
1247 CLuaObject
value(ls
); // pop it
1248 getEditor().setCookie(ls
.toString(2), ls
.toString(3), value
);
1252 // *********************************************************************************************************
1253 int CEditor::luaIsCreature(CLuaState
&ls
)
1255 //H_AUTO(R2_CEditor_luaIsCreature)
1257 const char *funcName
= "isCreature";
1258 CLuaIHM::checkArgCount(ls
, funcName
, 1);
1259 CLuaIHM::checkArgType(ls
, funcName
, 1, LUA_TSTRING
); // instance sheetClient
1261 CInstance
*inst
= getEditor().getInstanceFromId(ls
.toString(1));
1263 if (!inst
) return 0;
1265 const CCharacterSheet
*sheet
= dynamic_cast<const CCharacterSheet
*>(SheetMngr
.get(NLMISC::CSheetId(inst
->getSheet())));
1267 if (!sheet
) return 0;
1269 bool isNPC
= sheet
->Race
< EGSPD::CPeople::Creature
;
1271 // neither NPC, not Kami, nor Karavan
1272 bool creature
= !(isNPC
|| (!isNPC
&& (sheet
->Race
==EGSPD::CPeople::Kami
|| sheet
->Race
==EGSPD::CPeople::Karavan
)));
1278 // *********************************************************************************************************
1279 int CEditor::luaSetEditorSeason(CLuaState
&ls
)
1281 //H_AUTO(R2_CEditor_luaSetEditorSeason)
1283 const char *funcName
= "setEditorSeason";
1284 if (getEditor().getMode() != CEditor::EditionMode
1285 && getEditor().getMode() != CEditor::AnimationModeLoading
)
1287 CLuaIHM::fails(ls
, "%s : cannot set weather value outside of edit mode", funcName
);
1289 CLuaIHM::checkArgCount(ls
, funcName
, 2);
1290 CLuaIHM::checkArgType(ls
, funcName
, 2, LUA_TSTRING
); // this is a method (self + 1 param)
1291 if (strcmp(ls
.toString(2), "Automatic") == 0) getEditor()._Season
= Automatic
;
1292 else if (strcmp(ls
.toString(2), "Spring") == 0) getEditor()._Season
= Spring
;
1293 else if (strcmp(ls
.toString(2), "Summer") == 0) getEditor()._Season
= Summer
;
1294 else if (strcmp(ls
.toString(2), "Autumn") == 0) getEditor()._Season
= Autumn
;
1295 else if (strcmp(ls
.toString(2), "Winter") == 0) getEditor()._Season
= Winter
;
1296 else CLuaIHM::fails(ls
, "%s, invalid season name : %s", ls
.toString(2));
1297 // If season is changed while scenario is being received, we do not have received the tp command yet,
1298 // so signal the weather system that the season should not be changed for now
1299 if ((getEditor()._UpdatingScenario
&& getEditor()._WillTP
)
1300 || getEditor().getMode() != CEditor::AnimationModeLoading
)
1302 getEditor()._IsWaitingTPForSeasonChange
= true;
1306 getEditor()._IsWaitingTPForSeasonChange
= false;
1311 // *********************************************************************************************************
1312 int CEditor::luaSetFixedLighting(CLuaState
&ls
)
1314 //H_AUTO(R2_CEditor_luaSetFixedLighting)
1315 const char *funcName
= "setEditorSeason";
1316 CLuaIHM::checkArgCount(ls
, funcName
, 2);
1317 CLuaIHM::checkArgType(ls
, funcName
, 2, LUA_TBOOLEAN
); // this is a method (self + 1 param)
1318 getEditor().setFixedLighting(ls
.toBoolean(2));
1322 // *********************************************************************************************************
1323 int CEditor::luaGetFixedLighting(CLuaState
&ls
)
1325 //H_AUTO(R2_CEditor_luaGetFixedLighting)
1326 const char *funcName
= "getEditorSeason";
1327 CLuaIHM::checkArgCount(ls
, funcName
, 1); // this is a method
1328 ls
.push(getEditor().getFixedLighting());
1332 // *********************************************************************************************************
1333 int CEditor::luaSetPlotItemInfos(CLuaState
&ls
)
1335 //H_AUTO(R2_CEditor_luaSetPlotItemInfos)
1336 const char *funcName
= "setPlotItemInfos";
1337 CLuaIHM::checkArgCount(ls
, funcName
, 5); // a method with 4 args
1338 CLuaIHM::checkArgType(ls
, funcName
, 2, LUA_TNUMBER
);
1339 #ifdef RYZOM_LUA_UCSTRING
1340 CLuaIHM::checkArgTypeUCString(ls
, funcName
, 3);
1341 CLuaIHM::checkArgTypeUCString(ls
, funcName
, 4);
1342 CLuaIHM::checkArgTypeUCString(ls
, funcName
, 5);
1344 CLuaIHM::checkArgType(ls
, funcName
, 3, LUA_TSTRING
);
1345 CLuaIHM::checkArgType(ls
, funcName
, 4, LUA_TSTRING
);
1346 CLuaIHM::checkArgType(ls
, funcName
, 5, LUA_TSTRING
);
1348 CItemSheet
*item
= dynamic_cast<CItemSheet
*>(SheetMngr
.get(CSheetId((uint32
) ls
.toInteger(2))));
1349 if (!item
|| item
->Family
!= ITEMFAMILY::SCROLL_R2
)
1351 CLuaIHM::fails(ls
, "%s : bad sheet, r2 plot item required", funcName
);
1353 R2::TMissionItem mi
;
1354 mi
.SheetId
= (uint32
) ls
.toInteger(2);
1355 #ifdef RYZOM_LUA_UCSTRING
1356 CLuaIHM::getUCStringOnStack(ls
, 3, mi
.Name
);
1357 CLuaIHM::getUCStringOnStack(ls
, 4, mi
.Description
);
1358 CLuaIHM::getUCStringOnStack(ls
, 5, mi
.Comment
);
1360 mi
.Name
= ucstring::makeFromUtf8(ls
.toString(3));
1361 mi
.Description
= ucstring::makeFromUtf8(ls
.toString(4));
1362 mi
.Comment
= ucstring::makeFromUtf8(ls
.toString(5));
1364 getEditor().setPlotItemInfos(mi
);
1368 // *********************************************************************************************************
1369 int CEditor::luaIsCurrentSelectionPlayer(CLuaState
&ls
)
1371 //H_AUTO(R2_CEditor_luaIsCurrentSelectionPlayer)
1372 const char *funcName
= "isCurrentSelectionPlayer";
1373 CLuaIHM::checkArgCount(ls
, funcName
, 1); // method with 0 args
1374 CPlayerCL
*player
= dynamic_cast<CPlayerCL
*>(EntitiesMngr
.entity(UserEntity
->getTargetSlotNoLag()));
1375 ls
.push(player
!= NULL
);
1379 // *********************************************************************************************************
1380 int CEditor::luaFindEmptyPlace(CLuaState
&ls
)
1382 //H_AUTO(R2_CEditor_luaFindEmptyPlace)
1383 const char *funcName
= "findEmptyPlace";
1384 CLuaIHM::checkArgCount(ls
, funcName
, 3); // method with 2 args
1385 CLuaIHM::checkArgType(ls
, funcName
, 2, LUA_TNUMBER
);
1386 CLuaIHM::checkArgType(ls
, funcName
, 3, LUA_TNUMBER
);
1388 if (getEditor().getIslandCollision().findEmptyPlace(CVector2f((float) ls
.toNumber(2), (float) ls
.toNumber(3)), result
))
1398 // *********************************************************************************************************
1399 int CEditor::luaIsInIslandRect(CLuaState
&ls
)
1401 //H_AUTO(R2_CEditor_luaIsInIslandRect)
1402 const char *funcName
= "isInIslandRect";
1403 CLuaIHM::checkArgCount(ls
, funcName
, 3); // method with 2 args
1404 CLuaIHM::checkArgType(ls
, funcName
, 2, LUA_TNUMBER
);
1405 CLuaIHM::checkArgType(ls
, funcName
, 3, LUA_TNUMBER
);
1406 const R2::CScenarioEntryPoints::CCompleteIsland
*island
= getEditor().getIslandCollision().getCurrIslandDesc();
1412 float x
= (float) ls
.toNumber(2);
1413 float y
= (float) ls
.toNumber(3);
1414 ls
.push(x
>= island
->XMin
&& y
>= island
->YMin
&&
1415 x
<= island
->XMax
&& y
<= island
->YMax
);
1419 // *********************************************************************************************************
1420 int CEditor::luaGetCurrentIslandName(CLuaState
&ls
)
1422 //H_AUTO(R2_CEditor_luaGetCurrentIslandName)
1423 const char *funcName
= "getCurrentIslandName";
1424 CLuaIHM::checkArgCount(ls
, funcName
, 1); // method with no args
1425 R2::CScenarioEntryPoints::CCompleteIsland
*ci
= getEditor().getIslandCollision().getCurrIslandDesc();
1426 ls
.push(ci
? ci
->Island
.c_str() : "");
1430 // *********************************************************************************************************
1431 int CEditor::luaKickCharacter(CLuaState
&ls
)
1433 //H_AUTO(R2_CEditor_luaKickCharacter)
1434 const char *funcName
= "kickCharacter";
1435 CLuaIHM::checkArgCount(ls
, funcName
, 2); // this is a method (self + 1 params)
1436 CLuaIHM::checkArgType(ls
, funcName
, 2, LUA_TNUMBER
);
1438 CSessionBrowserImpl
&sb
= CSessionBrowserImpl::getInstance();
1439 sb
.kickCharacter(sb
.getCharId(), R2::getEditor().getDMC().getEditionModule().getCurrentAdventureId(),
1440 (uint32
)ls
.toInteger(2));
1442 if(!sb
.waitOneMessage(sb
.getMessageName("on_invokeResult")))
1443 nlwarning("kickCharacter callback return false");
1448 // *********************************************************************************************************
1449 int CEditor::luaUnkickCharacter(CLuaState
&ls
)
1451 //H_AUTO(R2_CEditor_luaUnkickCharacter)
1452 const char *funcName
= "unkickCharacter";
1453 CLuaIHM::checkArgCount(ls
, funcName
, 2); // this is a method (self + 1 params)
1454 CLuaIHM::checkArgType(ls
, funcName
, 2, LUA_TNUMBER
);
1456 CSessionBrowserImpl
&sb
= CSessionBrowserImpl::getInstance();
1457 sb
.unkickCharacter(sb
.getCharId(), R2::getEditor().getDMC().getEditionModule().getCurrentAdventureId(),
1458 (uint32
)ls
.toInteger(2));
1460 if(!sb
.waitOneMessage(sb
.getMessageName("on_invokeResult")))
1461 nlwarning("unkickCharacter callback return false");
1466 // *********************************************************************************************************
1467 int CEditor::luaTeleportToCharacter(CLuaState
&ls
)
1469 //H_AUTO(R2_CEditor_luaTeleportToCharacter)
1470 const char *funcName
= "teleportToCharacter";
1471 CLuaIHM::checkArgCount(ls
, funcName
, 2); // this is a method (self + 1 params)
1472 CLuaIHM::checkArgType(ls
, funcName
, 2, LUA_TNUMBER
);
1474 CClientEditionModule
& cem
= R2::getEditor().getDMC().getEditionModule();
1475 cem
.requestTeleportOneCharacterToAnother(cem
.getCurrentAdventureId(), CSessionBrowserImpl::getInstance().getCharId(),
1476 (uint32
)ls
.toInteger(2));
1480 // *********************************************************************************************************
1481 int CEditor::luaWaitScenarioScreen(CLuaState
&ls
)
1483 //H_AUTO(R2_CEditor_luaWaitScenarioScreen)
1484 const char *funcName
= "waitScenarioScreen";
1485 CLuaIHM::checkArgCount(ls
, funcName
, 1); // method with no args
1486 if (!ClientCfg
.Local
)
1488 getEditor()._WaitScenarioScreenWanted
= true;
1494 // *********************************************************************************************************
1495 int CEditor::luaIsScenarioUpdating(CLuaState
&ls
)
1497 //H_AUTO(R2_CEditor_luaIsScenarioUpdating)
1498 const char *funcName
= "isScenarioUpdating";
1499 CLuaIHM::checkArgCount(ls
, funcName
, 1); // method with no args
1500 ls
.push( getEditor()._UpdatingScenario
);
1507 // *********************************************************************************************************
1508 int CEditor::luaIsValidPoly(CLuaState &ls)
1510 //H_AUTO(R2_CEditor_luaIsValidPoly)
1511 const char *funcName = "isValidPoly";
1512 CLuaIHM::checkArgCount(ls, funcName, 2); // method with no args
1513 CLuaIHM::checkArgType(ls, funcName, 3, LUA_TTABLE); // method with no args
1516 NLMISC::CPolygon2D poly2D;
1518 ENUM_LUA_TABLE(table, it)
1520 NLMISC::CVector2f pos;
1521 if (!CLuaIHM::pop(ls, pos))
1523 CLuaIHM::fails(ls, "%s expects CVector2f for poly coordinates);
1525 poly2D.Vertices.push_back(pos);
1527 ls.push(getEditor().getIslandCollision().isValidPoly(poly2D);
1531 // *********************************************************************************************************
1532 int CEditor::luaIsValidPosition(CLuaState &ls)
1535 const char *funcName = "snapPosToGround";
1536 CLuaIHM::checkArgCount(ls, funcName, 3);
1537 CLuaIHM::checkArgType(ls, funcName, 2, LUA_TNUMBER);
1538 CLuaIHM::checkArgType(ls, funcName, 3, LUA_TNUMBER);
1540 // NLPACS::UGlobalPosition gpos = GR->retrievePosition(CVector((float) ls.toNumber(2), (float) ls.toNumber(3), 2000.f));
1541 if (gpos.InstanceId != -1)
1543 CVector snappedPos = GR->getGlobalPosition(gpos);
1544 ls.push(snappedPos.x);
1545 ls.push(snappedPos.y);
1546 ls.push(snappedPos.z);
1556 // new algo : to avoid to snapping to a cliff, start from the approximate (valid) height found in the height map
1558 if (CTool::computeWorldMapIntersection((float) ls.toNumber(2), (float) ls.toNumber(3), inter) != CTool::NoIntersection)
1568 // *********************************************************************************************************
1569 int CEditor::luaCanUndo(CLuaState
&ls
)
1571 //H_AUTO(R2_CEditor_luaCanUndo)
1572 const char *funcName
= "canUndo";
1573 CLuaIHM::checkArgCount(ls
, funcName
, 1); // method with no args
1574 ls
.push(getEditor().getDMC().getActionHistoric().canUndo());
1578 // *********************************************************************************************************
1579 int CEditor::luaCanRedo(CLuaState
&ls
)
1581 //H_AUTO(R2_CEditor_luaCanRedo)
1582 const char *funcName
= "canRedo";
1583 CLuaIHM::checkArgCount(ls
, funcName
, 1); // method with no args
1584 ls
.push(getEditor().getDMC().getActionHistoric().canRedo());
1588 // *********************************************************************************************************
1589 int CEditor::luaGetUserEntityName(CLuaState
&ls
)
1591 //H_AUTO(R2_CEditor_luaGetUserEntityName)
1592 const char *funcName
= "getUserEntityName";
1593 CLuaIHM::checkArgCount(ls
, funcName
, 1); // this is a method
1596 string name
= UserEntity
->getEntityName()+PlayerSelectedHomeShardNameWithParenthesis
;
1601 ls
.push(std::string());
1607 static CLuaString
lstr_Next("next");
1609 // *********************************************************************************************************
1610 int CEditor::luaEnumInstances(CLuaState
&ls
)
1612 //H_AUTO(R2_CEditor_luaEnumInstances)
1613 CLuaStackChecker
lsc(&ls
, 1);
1614 // return an enumerator that allows to iterate over instance, by kind
1615 const char *funcName
= "enumInstances";
1616 CLuaIHM::checkArgCount(ls
, funcName
, 2); // method with no args
1617 CLuaIHM::checkArgType(ls
, funcName
, 2, LUA_TSTRING
);
1618 struct CInstanceEnumerator
1620 CSortedInstances
*InstMap
;
1621 TInstanceByName::iterator Current
;
1622 static int next(CLuaState
&ls
)
1624 const char *funcName
= "InstanceEnumerator:next";
1625 CLuaIHM::checkArgCount(ls
, funcName
, 1);
1626 CLuaIHM::checkArgType(ls
, funcName
, 1, LUA_TUSERDATA
);
1627 CInstanceEnumerator
*ie
= (CInstanceEnumerator
*) ls
.toUserData(1);
1628 CEditor
&ed
= getEditor();
1629 while(ie
->Current
!= ie
->InstMap
->end())
1631 CInstance
*inst
= ie
->Current
->second
;
1632 if (!inst
->getGhost())
1634 // object must be in current act or base act
1635 CInstance
*parentAct
= inst
->getParentAct();
1636 if (!parentAct
|| parentAct
== ed
.getCurrentAct() || parentAct
== ed
.getBaseAct())
1638 inst
->getLuaProjection().push();
1648 static int gc(CLuaState
&ls
)
1650 const char *funcName
= "InstanceEnumerator:next";
1651 CLuaIHM::checkArgCount(ls
, funcName
, 1);
1652 CLuaIHM::checkArgType(ls
, funcName
, 1, LUA_TUSERDATA
);
1653 CInstanceEnumerator
*ie
= (CInstanceEnumerator
*) ls
.toUserData(1);
1654 ie
->~CInstanceEnumerator(); // no real effect for now...
1657 static int index(CLuaState
&ls
)
1659 const char *funcName
= "InstanceEnumerator.__index";
1660 CLuaIHM::checkArgCount(ls
, funcName
, 2);
1661 CLuaIHM::checkArgType(ls
, funcName
, 1, LUA_TUSERDATA
);
1662 CLuaIHM::checkArgType(ls
, funcName
, 2, LUA_TSTRING
);
1663 if (ls
.toString(2) == lstr_Next
)
1665 ls
.push(CInstanceEnumerator::next
);
1671 sint classIndex
= getEditor().classToIndex(ls
.toString(2));
1674 CLuaIHM::fails(ls
, "Trying to iterate over unknown class : %s", ls
.toString(2));
1679 ls
.push(CInstanceEnumerator::index
);
1680 mt
.setValue("__index", CLuaObject(ls
));
1681 ls
.push(CInstanceEnumerator::gc
);
1682 mt
.setValue("__gc", CLuaObject(ls
));
1684 void *newIter
= ls
.newUserData(sizeof(CInstanceEnumerator
));
1690 CInstanceEnumerator
*ie
= new (newIter
) CInstanceEnumerator
;
1693 #define new DEBUG_NEW
1696 ie
->InstMap
= &getEditor()._InstancesByDispName
[classIndex
];
1697 ie
->Current
= ie
->InstMap
->begin();
1699 ls
.setMetaTable(-2);
1704 // *********************************************************************************************************
1705 void CEditor::waitScenarioScreen()
1707 //H_AUTO(R2_CEditor_waitScenarioScreen)
1708 if (ClientCfg
.Local
) return;
1709 if (_Mode
==EditionMode
)
1711 setMode(GoingToEditionMode
);
1713 CWidgetManager::getInstance()->hideAllWindows();
1714 CInterfaceGroup
*waitScreen
= dynamic_cast<CInterfaceGroup
*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:r2ed_connecting"));
1717 waitScreen
->setActive(true);
1718 CWidgetManager::getInstance()->setTopWindow(waitScreen
);
1721 enum TState
{ WaitingScenario
, WaitingTP
, DoExit
};
1722 TState state
= WaitingScenario
;
1724 getEditor()._ScenarioReceivedFlag
= false;
1725 getEditor()._TPReceivedFlag
= false;
1726 bool firewallTimeout
= false;
1728 ActionsContext
.setContext("waiting_network");
1729 TGameCycle serverTick
= NetMngr
.getCurrentServerTick();
1730 CWidgetManager::getInstance()->setCaptureKeyboard(NULL
);
1731 CWidgetManager::getInstance()->setDefaultCaptureKeyboard(NULL
);
1732 loadBackgroundBitmap (StartBackground
);
1734 // patch for the 'sys info that pop' prb (cause unknown for now ...)
1735 CInterfaceElement
*sysInfo
= CWidgetManager::getInstance()->getElementFromId("ui:interface:system_info");
1736 bool sysInfoActive
= false;
1737 if (sysInfo
) sysInfoActive
= sysInfo
->getActive();
1743 case WaitingScenario
:
1744 if (getEditor()._ScenarioReceivedFlag
)
1746 if (getEditor()._WillTP
)
1764 if (state
== DoExit
)
1772 if ( ! firewallTimeout
)
1775 catch (const EBlockedByFirewall
&)
1777 if ( NetMngr
.getConnectionState() == CNetManager::Disconnect
)
1779 firewallTimeout
= true;
1783 // Display the firewall alert string
1784 CViewText
*pVT
= dynamic_cast<CViewText
*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:r2ed_connecting:title"));
1786 pVT
->setText(CI18N::get("uiFirewallAlert")+"...");
1788 // The mouse and fullscreen mode should be unlocked for the user to set the firewall permission
1789 nlSleep( 30 ); // 'nice' the client, and prevent to make too many send attempts
1793 IngameDbMngr
.flushObserverCalls();
1794 NLGUI::CDBManager::getInstance()->flushObserverCalls();
1796 // check if we can send another dated block
1797 if (NetMngr
.getCurrentServerTick() != serverTick
)
1800 serverTick
= NetMngr
.getCurrentServerTick();
1801 NetMngr
.send(serverTick
);
1809 // update module manager
1810 NLNET::IModuleManager::getInstance().updateModules();
1813 // Update the DT T0 and T1 global variables
1815 CInputHandlerManager::getInstance()->pumpEvents();
1816 Driver
->clearBuffers(CRGBA::Black
);
1817 Driver
->setMatrixMode2D11();
1818 drawLoadingBitmap (1);
1820 if ( state
==WaitingTP
&& getEditor()._TPReceivedFlag
)
1822 break; // don't want an additionnal swap buffer here, so exit now (the loading bitmap is good,
1823 // has just been reloaded by the tp screen...
1828 // Interface handling & displaying (processes clicks...)
1829 getUI().updateFrameEvents();
1833 CWidgetManager::getInstance()->setTopWindow(waitScreen
);
1836 if (sysInfo
) sysInfo
->setActive(false);
1838 getUI().updateFrameViews(NULL
);
1839 IngameDbMngr
.flushObserverCalls();
1840 NLGUI::CDBManager::getInstance()->flushObserverCalls();
1843 globalMenuMovieShooter();
1845 // Force the client to sleep a bit.
1846 if(ClientCfg
.Sleep
>= 0)
1848 nlSleep(ClientCfg
.Sleep
);
1854 TextContext
->setShaded(true);
1855 TextContext
->setShadeOutline(false);
1856 TextContext
->setFontSize(40);
1857 TextContext
->setColor(CRGBA::White
);
1861 TextContext
->setHotSpot(NL3D::UTextContext::MiddleMiddle
);
1862 TextContext
->printfAt(0.5f
, 0.5f
, "(UI NOT FOUND) Waiting scenario from server.");
1867 Driver
->swapBuffers();
1869 if (NetMngr
.getConnectionState() == CNetManager::Disconnect
)
1871 if ( firewallTimeout
)
1873 // Display the firewall error string instead of the normal failure string
1874 CViewText
*pVT
= dynamic_cast<CViewText
*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:r2ed_connecting:title"));
1877 pVT
->setMultiLine( true );
1878 pVT
->setText(CI18N::get("uiFirewallFail")+".\n"+
1879 CI18N::get("uiFirewallAlert")+".");
1884 if (sysInfo
) sysInfo
->setActive(sysInfoActive
);
1885 destroyLoadingBitmap ();
1886 if (_Mode
== GoingToEditionMode
)
1888 setMode(EditionMode
);
1893 // *********************************************************************************************************
1894 // lua instance observer
1895 class CInstanceObserverLua
: public CEditor::IInstanceObserver
1898 CInstanceObserverLua(CLuaObject
&receiver
);
1899 ~CInstanceObserverLua();
1900 CLuaObject
&getReceiver() { return _Receiver
; }
1901 // from IInstanceObserver
1902 virtual void onInstanceCreated(CInstance
&instance
);
1903 virtual void onInstanceErased(CInstance
&instance
);
1904 virtual void onInstancePreHrcMove(CInstance
&instance
);
1905 virtual void onInstancePostHrcMove(CInstance
&instance
);
1906 virtual void onPreHrcMove(CInstance
&instance
);
1907 virtual void onPostHrcMove(CInstance
&instance
);
1908 virtual void onAttrModified(CInstance
&instance
, const std::string
&attrName
, sint32 attrIndex
);
1910 CLuaObject _Receiver
; // table that will receive the notifications
1915 uint
CInstanceObserverLua::_Count
= 0;
1918 CInstanceObserverLua::CInstanceObserverLua(CLuaObject
&receiver
) : _Receiver(receiver
)
1923 CInstanceObserverLua::~CInstanceObserverLua()
1926 nlassert(!getEditor().isInstanceObserver(this));
1928 nlassert(_Count
< 1000000000);
1933 void CInstanceObserverLua::onInstanceCreated(CInstance
&instance
)
1935 //H_AUTO(R2_CInstanceObserverLua_onInstanceCreated)
1936 nlassert(_Receiver
.isValid());
1937 if (_Receiver
["onInstanceCreated"].isNil()) return; // no-op if not handled
1938 getEditor().projectInLua(instance
.getObjectTable());
1939 _Receiver
.callMethodByNameNoThrow("onInstanceCreated", 1, 0);
1942 void CInstanceObserverLua::onInstanceErased(CInstance
&instance
)
1944 //H_AUTO(R2_CInstanceObserverLua_onInstanceErased)
1945 nlassert(_Receiver
.isValid());
1946 if (_Receiver
["onInstanceErased"].isNil()) return; // no-op if not handled
1947 getEditor().projectInLua(instance
.getObjectTable());
1948 _Receiver
.callMethodByNameNoThrow("onInstanceErased", 1, 0);
1951 void CInstanceObserverLua::onInstancePreHrcMove(CInstance
&instance
)
1953 //H_AUTO(R2_CInstanceObserverLua_onInstancePreHrcMove)
1954 nlassert(_Receiver
.isValid());
1955 if (_Receiver
["onInstanceCreated"].isNil()) return; // no-op if not handled
1956 getEditor().projectInLua(instance
.getObjectTable());
1957 _Receiver
.callMethodByNameNoThrow("onInstancePreHrcMove", 1, 0);
1960 void CInstanceObserverLua::onInstancePostHrcMove(CInstance
&instance
)
1962 //H_AUTO(R2_CInstanceObserverLua_onInstancePostHrcMove)
1963 nlassert(_Receiver
.isValid());
1964 if (_Receiver
["onInstanceCreated"].isNil()) return; // no-op if not handled
1965 getEditor().projectInLua(instance
.getObjectTable());
1966 _Receiver
.callMethodByNameNoThrow("onInstancePostHrcMove", 1, 0);
1969 void CInstanceObserverLua::onPreHrcMove(CInstance
&instance
)
1971 //H_AUTO(R2_CInstanceObserverLua_onPreHrcMove)
1972 nlassert(_Receiver
.isValid());
1973 if (_Receiver
["onPreHrcMove"].isNil()) return; // no-op if not handled
1974 getEditor().projectInLua(instance
.getObjectTable());
1975 _Receiver
.callMethodByNameNoThrow("onPreHrcMove", 1, 0);
1978 void CInstanceObserverLua::onPostHrcMove(CInstance
&instance
)
1980 //H_AUTO(R2_CInstanceObserverLua_onPostHrcMove)
1981 nlassert(_Receiver
.isValid());
1982 if (_Receiver
["onPostHrcMove"].isNil()) return; // no-op if not handled
1983 getEditor().projectInLua(instance
.getObjectTable());
1984 _Receiver
.callMethodByNameNoThrow("onPostHrcMove", 1, 0);
1987 void CInstanceObserverLua::onAttrModified(CInstance
&instance
, const std::string
&attrName
, sint32 attrIndex
)
1989 //H_AUTO(R2_CInstanceObserverLua_onAttrModified)
1990 nlassert(_Receiver
.isValid());
1991 if (_Receiver
["onAttrModified"].isNil()) return; // no-op if not handled
1992 getEditor().projectInLua(instance
.getObjectTable());
1993 getEditor().getLua().push(attrName
);
1994 getEditor().getLua().push(attrIndex
);
1995 _Receiver
.callMethodByNameNoThrow("onAttrModified", 3, 0);
1998 // *********************************************************************************************************
1999 int CEditor::luaAddInstanceObserver(CLuaState
&ls
)
2001 //H_AUTO(R2_CEditor_luaAddInstanceObserver)
2003 const char *funcName
= "addInstanceObserver";
2004 CLuaIHM::checkArgCount(ls
, funcName
, 3); // this is a method (self + 2 params)
2005 CLuaIHM::checkArgType(ls
, funcName
, 2, LUA_TSTRING
); // instance id
2006 CLuaIHM::checkArgType(ls
, funcName
, 3, LUA_TTABLE
); // receiver
2007 CLuaObject
receiver(ls
); // pop the receiver
2008 ls
.push(getEditor().addInstanceObserver(ls
.toString(2), new CInstanceObserverLua(receiver
)));
2012 // *********************************************************************************************************
2013 int CEditor::luaRemoveInstanceObserver(CLuaState
&ls
)
2015 //H_AUTO(R2_CEditor_luaRemoveInstanceObserver)
2017 const char *funcName
= "removeInstanceObserver";
2018 CLuaIHM::checkArgCount(ls
, funcName
, 2); // this is a method (self + 1 params)
2019 CLuaIHM::checkArgType(ls
, funcName
, 2, LUA_TNUMBER
); // instance id
2020 IInstanceObserver
*observer
= getEditor().getInstanceObserver((TInstanceObserverHandle
) ls
.toInteger(2));
2021 if (observer
== NULL
)
2023 CLuaIHM::fails(ls
, "Instance observer not found for handle = %" NL_I64
"d", ls
.toInteger(2));
2025 CInstanceObserverLua
*luaObserver
= dynamic_cast<CInstanceObserverLua
*>(observer
);
2026 if (luaObserver
== NULL
)
2028 CLuaIHM::fails(ls
, "Instance observer found for handle %" NL_I64
"d, but has bad type, it wasn't registered from lua.", ls
.toInteger(2));
2030 getEditor().removeInstanceObserver((TInstanceObserverHandle
) ls
.toInteger(2));
2031 CLuaObject receiver
= luaObserver
->getReceiver();
2037 // *********************************************************************************************************
2038 bool CEditor::isInstanceObserver(IInstanceObserver
*observer
) const
2040 //H_AUTO(R2_CEditor_isInstanceObserver)
2041 for(TInstanceObserverMap::const_iterator it
= _InstanceObservers
.begin(); it
!= _InstanceObservers
.end(); ++it
)
2043 if (it
->second
== observer
) return true;
2049 // *********************************************************************************************************
2050 const CObjectTable
*CEditor::getObjectTableFromId(const TInstanceId
&id
) const
2052 //H_AUTO(R2_CEditor_getObjectTableFromId)
2055 const CObject
*obj
= _DMC
->find(id
);
2056 if (!obj
) return NULL
;
2057 nlassert(obj
->isTable());
2058 return (CObjectTable
*) obj
;
2061 // *********************************************************************************************************
2062 CInstance
*CEditor::getInstanceFromObject(const CObject
*obj
) const
2064 //H_AUTO(R2_CEditor_getInstanceFromObject)
2066 if (!obj
->isTable()) return NULL
;
2067 TInstanceMap::const_iterator it
= _Instances
.find((CObjectTable
*) obj
);
2068 if (it
!= _Instances
.end())
2076 // *********************************************************************************************************
2077 void CEditor::registerEnvMethod(const char *name
,TLuaWrappedFunction func
)
2079 //H_AUTO(R2_CEditor_registerEnvMethod)
2082 getEnv().setValue(name
, func
);
2085 // *********************************************************************************************************
2086 void CEditor::registerEnvFunction(const char *name
, TLuaWrappedFunction func
)
2088 //H_AUTO(R2_CEditor_registerEnvFunction)
2091 getEnv().setValue(name
, func
);
2095 // *********************************************************************************************************
2096 void CEditor::registerLuaFunc()
2098 //H_AUTO(R2_CEditor_registerLuaFunc)
2100 registerEnvMethod("getSelectedInstanceId", luaGetSelectedInstanceId
);
2101 registerEnvMethod("setSelectedInstanceId", luaSetSelectedInstanceId
);
2102 registerEnvMethod("setCurrentTool", luaSetCurrentTool
);
2103 registerEnvMethod("getCurrentTool", luaGetCurrentTool
);
2104 registerEnvMethod("getVisualPropertiesFromInstanceId", luaGetVisualPropertiesFromInstanceId
);
2105 registerEnvMethod("getInstanceFromId", luaGetInstanceFromId
);
2106 registerEnvMethod("displayContextMenu", luaDisplayContextMenu
);
2107 registerEnvMethod("getSelectedInstance", luaGetSelectedInstance
);
2108 registerEnvMethod("connectAsCreator", luaConnectAsCreator
);
2109 registerEnvMethod("doFile", luaDofile
);
2110 registerEnvMethod("tryFile", luaTryFile
);
2111 registerEnvMethod("setEntityCustomSelectBox", luaSetEntityCustomSelectBox
);
2112 registerEnvMethod("getEntityCustomSelectBox", luaGetEntityCustomSelectBox
);
2113 registerEnvMethod("choosePos", luaChoosePos
);
2114 registerEnvMethod("snapPosToGround", luaSnapPosToGround
);
2115 registerEnvMethod("getUserEntityPosition", luaGetUserEntityPosition
);
2116 registerEnvMethod("getUserEntityFront", luaGetUserEntityFront
);
2117 registerEnvMethod("setCurrentActFromId", luaSetCurrentActFromId
);
2118 registerEnvMethod("getCurrentAct", luaGetCurrentAct
);
2119 registerEnvMethod("genInstanceName", luaGenInstanceName
);
2120 registerEnvMethod("isPostFixedByNumber", luaIsPostFixedByNumber
);
2121 registerEnvMethod("setCookie", luaSetCookie
);
2122 registerEnvMethod("addInstanceObserver", luaAddInstanceObserver
);
2123 registerEnvMethod("removeInstanceObserver", luaRemoveInstanceObserver
);
2124 registerEnvFunction("requestSetLocalNode", luaRequestSetLocalNode
);
2125 registerEnvFunction("requestCommitLocalNode", luaRequestCommitLocalNode
);
2126 registerEnvFunction("requestRollbackLocalNode", luaRequestRollbackLocalNode
);
2127 registerEnvMethod("isCreature", luaIsCreature
);
2128 registerEnvMethod("setEditorSeason", luaSetEditorSeason
);
2129 registerEnvMethod("setFixedLighting", luaSetFixedLighting
);
2130 registerEnvMethod("getFixedLighting", luaGetFixedLighting
);
2131 registerEnvMethod("setPlotItemInfos", luaSetPlotItemInfos
);
2132 registerEnvMethod("isCurrentSelectionPlayer", luaIsCurrentSelectionPlayer
);
2133 registerEnvMethod("findEmptyPlace", luaFindEmptyPlace
);
2134 registerEnvMethod("isInIslandRect", luaIsInIslandRect
);
2135 registerEnvMethod("getCurrentIslandName", luaGetCurrentIslandName
);
2136 registerEnvMethod("waitScenarioScreen", luaWaitScenarioScreen
);
2137 registerEnvMethod("isScenarioUpdating", luaIsScenarioUpdating
);
2138 registerEnvMethod("canUndo", luaCanUndo
);
2139 registerEnvMethod("canRedo", luaCanRedo
);
2140 registerEnvMethod("getUserEntityName", luaGetUserEntityName
);
2141 registerEnvMethod("getStartingAnimationFilename", luaGetStartingAnimationFilename
);
2142 registerEnvMethod("kickCharacter", luaKickCharacter
);
2143 registerEnvMethod("unkickCharacter", luaUnkickCharacter
);
2144 registerEnvMethod("teleportToCharacter", luaTeleportToCharacter
);
2145 registerEnvMethod("enumInstances", luaEnumInstances
);
2146 registerEnvMethod("isClearingContent", luaIsClearingContent
);
2150 static void polyUnitTest()
2153 poly.Vertices.push_back(CVector2f(0.f, 0.f));
2154 poly.Vertices.push_back(CVector2f(1.f, 0.f));
2155 poly.Vertices.push_back(CVector2f(1.f, 1.f));
2156 poly.Vertices.push_back(CVector2f(0.f, 1.f));
2157 nlassert(poly.contains(CVector2f(0.f, 0.f), false));
2158 nlassert(poly.contains(CVector2f(1.f, 0.f), false));
2159 nlassert(poly.contains(CVector2f(1.f, 1.f), false));
2160 nlassert(poly.contains(CVector2f(0.f, 1.f), false));
2161 nlassert(poly.contains(CVector2f(0.5f, 0.f), false))
2162 nlassert(poly.contains(CVector2f(1.f, 0.5f), false));
2163 nlassert(poly.contains(CVector2f(0.5f, 1.f), false));
2164 nlassert(poly.contains(CVector2f(0.f, 0.5f), false));
2165 nlassert(poly.contains(CVector2f(0.5f, 0.5f), false));
2167 nlassert(!poly.contains(CVector2f(-0.5f, 0.5f), false));
2168 nlassert(!poly.contains(CVector2f(1.5f, 0.5f), false));
2169 nlassert(!poly.contains(CVector2f(0.5f, -0.5f), false));
2170 nlassert(!poly.contains(CVector2f(0.5f, 1.5f), false));
2174 // *********************************************************************************************************
2175 void CEditor::loadLanguageFile()
2177 //H_AUTO(R2_CEditor_loadLanguageFile)
2179 static bool reload
= false;
2180 CI18N::ILoadProxy
*oldLoadProxy
= CI18N::getLoadProxy();
2181 CI18N::setLoadProxy(NULL
);
2182 string lc
= ClientCfg
.LanguageCode
;
2183 nlinfo("Reloading the r2_%s.uxt", lc
.c_str());
2184 CI18N::loadFromFilename("r2_"+lc
+".uxt", reload
);
2185 CI18N::setLoadProxy(oldLoadProxy
);
2190 // *********************************************************************************************************
2191 void CEditor::loadKeySet(const std::string
&keySet
)
2193 //H_AUTO(R2_CEditor_loadKeySet)
2195 if (keySet
.empty()) return;
2196 CVerboseClock
clock("Parsing of keyset " + keySet
);
2197 // remove all existing keys
2198 ActionsContext
.removeAllCombos();
2199 CMacroCmdManager::getInstance()->removeAllMacros();
2201 // parse keys that are specific to r2ed
2202 std::vector
<string
> xmlFilesToParse
;
2204 // Does the r2ed keys file exist ?
2205 std::string userKeyFileName
= "save/" + keySet
+ "_"+PlayerSelectedFileName
+".xml";
2206 if (CFile::fileExists(userKeyFileName
) && CFile::getFileSize(userKeyFileName
) > 0)
2208 // Load the user key file
2209 xmlFilesToParse
.push_back (userKeyFileName
);
2213 std::string filename
= "save/shared_" + keySet
+ ".xml";
2214 if (CFile::fileExists(filename
) && CFile::getFileSize(filename
) > 0)
2216 xmlFilesToParse
.push_back(filename
);
2219 // Load the default key (but don't replace existings bounds, see keys.xml "key_def_no_replace")
2220 xmlFilesToParse
.push_back (keySet
+ ".xml");
2222 if (!CInterfaceManager::getInstance()->parseInterface (xmlFilesToParse
, true))
2224 badXMLParseMessageBox();
2227 CActionsManager
*actionManager
= ActionsContext
.getActionsManager();
2230 // if some mode are unavailable, forbid the associated shortcuts
2231 /*if (!_ModeEnabled[EditionMode])
2233 actionManager->removeBaseAction("r2ed_stop_test");
2235 if (!_ModeEnabled[TestMode] || !_ModeEnabled[DMMode])
2237 actionManager->removeBaseAction("r2ed_try_go_test");
2242 // *********************************************************************************************************
2243 void CEditor::saveCurrentKeySet()
2245 //H_AUTO(R2_CEditor_saveCurrentKeySet)
2247 std::string prefix
= getKeySetPrefix(getMode());
2248 if (prefix
.empty()) return;
2250 std::string filename
= "save/" + prefix
+ "_" + PlayerSelectedFileName
+ ".xml";
2251 std::string sharedfile
="save/shared_" + prefix
+ ".xml";
2252 if (!CFile::fileExists(filename
) && CFile::fileExists(sharedfile
))
2253 filename
= sharedfile
;
2255 getUI().saveKeys (filename
);
2258 // *********************************************************************************************************
2259 std::string
CEditor::getKeySetPrefix(TMode mode
)
2261 //H_AUTO(R2_CEditor_getKeySetPrefix)
2265 case EditionMode
: return "keys_r2ed";
2267 case GoingToEditionMode
:
2268 case AnimationModeLoading
:
2269 case AnimationModeWaitingForLoading
:
2270 case AnimationModeGoingToDm
:
2271 case AnimationModeGoingToPlay
:
2273 case AnimationModePlay
:
2278 return std::string();
2281 // *********************************************************************************************************
2282 void CEditor::setUIMode(uint8 mode
)
2284 //H_AUTO(R2_CEditor_setUIMode)
2286 getUI().setMode(mode
);
2287 if (_ForceDesktopReset
[mode
])
2289 // force to call reset when reloading the ui
2290 getLua().push(mode
);
2291 callEnvMethod("resetDesktop", 1, 0);
2292 _ForceDesktopReset
[mode
] = false;
2294 getLua().push(mode
);
2295 callEnvMethod("onChangeDesktop", 1, 0);
2299 // *********************************************************************************************************
2300 void CEditor::loadStandardUI()
2302 //H_AUTO(R2_CEditor_loadStandardUI)
2304 // force to reload the standard interface
2305 ClientCfg
.R2EDEnabled
= false;
2307 ClientCfg
.R2EDEnabled
= true;
2308 CWidgetManager::getInstance()->updateAllLocalisedElements();
2311 // *********************************************************************************************************
2312 bool CEditor::isDMing() const
2314 //H_AUTO(R2_CEditor_isDMing)
2315 if (getMode() == AnimationModePlay
) return false; // masterless mode -> not a dm
2316 return getMode() == DMMode
||
2317 getMode() == AnimationModeDm
||
2319 getMode() != NotInitialized
&&
2320 getAccessMode() == AccessDM
2324 // *********************************************************************************************************
2325 void CEditor::setMode(TMode mode
)
2329 case NotInitialized
: nlwarning("*R2* Setting mode to NotInitialized"); break;
2330 case EditionMode
: nlwarning("*R2* Setting mode to EditionMode"); break;
2331 case GoingToDMMode
: nlwarning("*R2* Setting mode to GoingToDMMode"); break;
2332 case GoingToEditionMode
: nlwarning("*R2* Setting mode to GoingToEditionMode"); break;
2333 case TestMode
: nlwarning("*R2* Setting mode to TestMode"); break;
2334 case DMMode
: nlwarning("*R2* Setting mode to DMMode"); break;
2335 case AnimationModeLoading
: nlwarning("*R2* Setting mode to AnimationModeLoading"); break;
2336 case AnimationModeWaitingForLoading
: nlwarning("*R2* Setting mode to AnimationModeWaitingForLoading"); break;
2337 case AnimationModeDm
: nlwarning("*R2* Setting mode to AnimationModeDm"); break;
2338 case AnimationModePlay
: nlwarning("*R2* Setting mode to AnimationModePlay"); break;
2339 case AnimationModeGoingToDm
: nlwarning("*R2* Setting mode to AnimationModeGoingToDm"); break;
2340 case AnimationModeGoingToPlay
: nlwarning("*R2* Setting mode to AnimationModeGoingToPlay"); break;
2342 nlwarning("Setting mode to 'unknown'");
2346 if (mode
!= EditionMode
)
2348 delete _EntitySorter
;
2349 _EntitySorter
= NULL
;
2351 //H_AUTO(R2_CEditor_setMode)
2353 //nlassert(_ModeEnabled[mode]);
2354 if (mode
== _Mode
&& !_ForceDesktopReset
[mode
]) return;
2359 if ((_Mode
== AnimationModeDm
|| _Mode
== AnimationModePlay
)
2360 && !((mode
== AnimationModeDm
|| mode
== AnimationModePlay
)))
2362 // remove the chat windows when leaving animation mode
2363 PeopleInterraction
.removeAllFreeTellers();
2368 CVerboseClock
clock("Saving windows & key at a mode change ...");
2369 if (_Mode
!= NotInitialized
)
2371 saveCurrentKeySet();
2373 //if (_Mode != NotInitialized) saveUIConfig();
2374 if (_Mode
== EditionMode
|| _Mode
== AnimationModeLoading
)
2376 getDMC().getActionHistoric().clear(); // no backup of undo/redo for now
2377 clearContent(); // when leaving edition, remove content from tree
2379 else if (mode
== EditionMode
|| mode
== GoingToEditionMode
)
2381 removeAllEntitySlots(); // when leaving test or dm, remove the entities slots
2384 if (mode
== DMMode
|| mode
== AnimationModeDm
)
2386 getEditor().getDMC().getEditionModule().askUpdateCharMode(TCharMode::Dm
);
2388 else if (mode
== EditionMode
)
2390 getEditor().getDMC().getEditionModule().askUpdateCharMode(TCharMode::Editer
);
2392 else if (mode
== AnimationModePlay
)
2394 if(_Mode
!= NotInitialized
)
2396 if (_SerializeUIConfig
)
2401 getEditor().getDMC().getEditionModule().askUpdateCharMode(TCharMode::Player
);
2402 // if access mode is DM, then load the whole ui
2403 if (_AccessMode
== AccessDM
)
2408 else if (mode
== TestMode
)
2410 getEditor().getDMC().getEditionModule().askUpdateCharMode(TCharMode::Tester
);
2412 else // Other like going to dm ...
2418 // reset any selection
2419 if ((!IngameDbMngr
.initInProgress()) && UserEntity
) // prevent from calling selection() if coming from a FarTP, otherwise the server will mess up the action counter because it can't know our datasetrow so early (initInProgress(): heuristic to ensure the setTarget() will work on the EGS)
2421 UserEntity
->selection(CLFECOMMON::INVALID_SLOT
);
2424 ContextCur
.release();
2426 loadKeySet(getKeySetPrefix(_Mode
));
2427 CWidgetManager::getInstance()->disableModalWindow();
2428 CWidgetManager::getInstance()->setCapturePointerLeft(NULL
);
2429 CWidgetManager::getInstance()->setCapturePointerRight(NULL
);
2430 CWidgetManager::getInstance()->setCaptureKeyboard(NULL
);
2431 // Season is now unknown, until server force it (in test mode), or first set act set it (in edit mode)
2432 _Season
= UnknownSeason
;
2440 _EntitySorter
= new CEntitySorter
;
2442 ActionsContext
.setContext("r2ed");
2443 // set new mode in lua
2444 _Env
.setValue("Mode", "Edit");
2446 ::IgnoreEntityDbUpdates
= true;
2447 ::SlotUnderCursor
= CLFECOMMON::INVALID_SLOT
;
2449 * nb we manage mouse bitmap ourselves, so there's only one cursor context here, and it never changes:
2450 * its sole purpose is to route messages to the current tool
2452 ContextCur
.add(false, "STAND BY", DEFAULT_CURSOR
, 0.0f
, CEditor::checkCursor
, CEditor::mouseClick
);
2453 forceSetSelectedInstance(NULL
);
2454 initReferencePlotItems();
2455 // force speed to "run" ("walk" not available in edition)
2456 if (!UserEntity
->running())
2458 UserEntity
->switchVelocity();
2462 ActionsContext
.setContext("r2ed_anim_test");
2463 // set new mode in lua
2464 _Env
.setValue("Mode", "Test");
2466 ::IgnoreEntityDbUpdates
= false;
2467 ::initContextualCursor();
2468 nlassert(CDisplayerBase::ObjCount
== 0);
2472 ActionsContext
.setContext("r2ed_anim_dm");
2473 // set new mode in lua
2474 _Env
.setValue("Mode", "DM");
2476 ::IgnoreEntityDbUpdates
= false;
2477 ::initContextualCursor();
2478 nlassert(CDisplayerBase::ObjCount
== 0);
2479 // when in local mode, init fake plot item to test the 'dm gift' interface
2480 initDummyPlotItems();
2483 ActionsContext
.setContext("waiting_network");
2484 // set new mode in lua
2485 _Env
.setValue("Mode", "GoingToDM");
2487 connectionMsg(_ConnectionMsg
); // update connection window
2488 ::IgnoreEntityDbUpdates
= false;
2489 ::initContextualCursor();
2490 nlassert(CDisplayerBase::ObjCount
== 0);
2493 case GoingToEditionMode
:
2494 nlassert(CDisplayerBase::ObjCount
== 0);
2495 ActionsContext
.setContext("waiting_network");
2496 // set new mode in lua
2497 _Env
.setValue("Mode", "BackToEditing");
2499 connectionMsg(_ConnectionMsg
); // update connection window
2500 ::IgnoreEntityDbUpdates
= true;
2501 ::initContextualCursor();
2505 case AnimationModeLoading
:
2506 nlassert(CDisplayerBase::ObjCount
== 0);
2507 ActionsContext
.setContext("waiting_network");
2508 // set new mode in lua
2509 _Env
.setValue("Mode", "AnimationModeLoading");
2511 connectionMsg(_ConnectionMsg
); // update connection window
2512 // ::IgnoreEntityDbUpdates = true;
2513 ::initContextualCursor();
2517 case AnimationModeWaitingForLoading
:
2518 nlassert(CDisplayerBase::ObjCount
== 0);
2519 ActionsContext
.setContext("waiting_network");
2520 // set new mode in lua
2521 _Env
.setValue("Mode", "AnimationModeWaitingForLoading");
2523 connectionMsg(_ConnectionMsg
); // update connection window
2524 // ::IgnoreEntityDbUpdates = true;
2525 ::initContextualCursor();
2529 case AnimationModeDm
:
2530 PeopleInterraction
.updateAllFreeTellerHeaders(); // if invitation were received during loading, add 'invite' button to the new windows
2531 nlassert(CDisplayerBase::ObjCount
== 0);
2532 ActionsContext
.setContext("r2ed_anim_dm");
2533 // set new mode in lua
2534 _Env
.setValue("Mode", "AnimationModeDm");
2536 ::IgnoreEntityDbUpdates
= false;
2537 ::initContextualCursor();
2541 case AnimationModePlay
:
2543 // animation mode play is still visible in masterless mode
2544 nlassert(CDisplayerBase::ObjCount
== 0);
2545 // no op here, just a player
2546 ActionsContext
.setContext("game");
2547 //ActionsContext.setContext("r2ed_anim_test");
2548 // set new mode in lua
2549 _Env
.setValue("Mode", "r2ed_anim_test");
2550 // hide all ring windows that may remain
2552 // setUIMode(1); // don't change desktop here, because virtual desktops are allowed in this mode
2553 getUI().setMode(0); // default to desktop 0 as with standard game
2554 ::IgnoreEntityDbUpdates
= false;
2555 ::initContextualCursor();
2557 if (getDMC().getEditionModule().isSessionOwner())
2559 // if we are not a player, pop the ui to pop control player window & to quit
2560 callEnvMethod("popDMToolbarWindow", 0, 0);
2564 callEnvMethod("playerModeUIFix", 0, 0);
2569 case AnimationModeGoingToDm
:
2570 nlassert(CDisplayerBase::ObjCount
== 0);
2571 ActionsContext
.setContext("waiting_network");
2572 //set new mode in lua
2573 _Env
.setValue("Mode", "AnimationModeGoingToDM");
2575 connectionMsg(_ConnectionMsg
); // update connection window
2576 ::IgnoreEntityDbUpdates
= false;
2577 ::initContextualCursor();
2587 ClientCfg
.ManualWeatherSetup
= false;
2588 ContextCur
.context("STAND BY");
2591 // warn lua that mode has changed
2592 callEnvMethod("onModeChanged", 0, 0);
2594 setCurrentTool(NULL
);
2596 // display the bars over the player (not available during edition, but available at test time)
2597 UserEntity
->buildInSceneInterface();
2599 if (_Mode
== EditionMode
)
2601 // special context menu for edition
2602 GameContextMenu
.init("game_context_menu_edition");
2606 GameContextMenu
.init("");
2611 // *********************************************************************************************************
2612 void CEditor::hideRingWindows()
2614 //H_AUTO(R2_CEditor_hideRingWindows)
2615 static const char *ringWindows
[] =
2619 "r2ed_property_sheet_no_selection",
2620 "r2ed_property_sheet_no_properties",
2623 "r2ed_windows_dm_bar",
2624 "r2ed_toolbar_window",
2627 "r2ed_animation_loading",
2628 "r2ed_animation_waiting",
2629 "dm_controlled_entities",
2630 "r2ed_current_session",
2631 "r2ed_toolbar_admin",
2635 "r2ed_main_menu_button",
2636 "r2ed_contextual_toolbar_new",
2638 "r2ed_logic_entities",
2641 "r2ed_edit_activity_sequence",
2643 "r2ed_edit_chat_sequence",
2644 "r2ed_mini_activity_view",
2649 "r2ed_scenario_filter",
2652 for (uint k
= 0; k
< sizeofarray(ringWindows
); ++k
)
2654 std::string id
= "ui:interface:" + std::string(ringWindows
[k
]);
2655 CInterfaceElement
*grp
= CWidgetManager::getInstance()->getElementFromId(id
);
2658 grp
->setActive(false);
2662 nlwarning("Can't find group with id : %s", id
.c_str());
2667 // *********************************************************************************************************
2668 void CEditor::init(TMode initialMode
, TAccessMode accessMode
)
2670 nlwarning("*R2* init");
2671 _EntitySorter
= NULL
;
2672 //H_AUTO(R2_CEditor_init)
2673 CNiceInputAuto niceInputs
;
2674 nlassert((uint
) initialMode
< ModeCount
);
2675 nlassert((uint
) accessMode
< AccessModeCount
);
2676 //nlassert(_ModeEnabled[initialMode]; // mode not enabled ...
2678 CVerboseClock
clock("Init of editor ");
2679 _Initialized
= true;
2680 _AccessMode
= accessMode
;
2682 // add a list of files for which modifications will trigger R2ED reset
2683 for(uint k
= 0; k
< ClientCfg
.R2EDReloadFiles
.size(); ++k
)
2685 CFile::removeFileChangeCallback(ClientCfg
.R2EDReloadFiles
[k
]); // avoid to add twice when a reset ...
2686 CFile::addFileChangeCallback(ClientCfg
.R2EDReloadFiles
[k
], reloadEditorCallback
);
2689 CLuaStackChecker
lsc(&getLua());
2690 getLua().pushGlobalTable();
2691 _Globals
.pop(getLua());
2692 getLua().pushValue(LUA_REGISTRYINDEX
);
2693 _Registry
.pop(getLua());
2694 // create R2 environment, and keep a reference on it
2695 _Env
= _Globals
.newTable(R2_LUA_PATH
);
2696 _Config
= _Env
.newTable("Config");
2698 _Env
.setValue("InClient", true); // TMP : signal to the script that it is initialised by the client
2702 case AccessEditor
: _Env
.setValue("AccessMode", "Editor"); break;
2703 case AccessDM
: _Env
.setValue("AccessMode", "DM"); break;
2704 case AccessOutlandOwner
: _Env
.setValue("AccessMode", "OutlandOwner"); break;
2710 // Load the UI files
2715 // setForceDesktopReset is done below
2716 ReloadUIFlag
= false;
2720 registerDisplayers();
2723 std::vector
<std::string
> emptyArgsList
;
2724 // Calling window init proc
2727 _DMC
->init(getLua().getStatePointer());
2729 initObjectProjectionMetatable(); // init system to access to scenary objects from lua
2730 // init client/server stuffs
2733 CConfigVarBase::getConfigFileTimeStamp() ++; // invalidate all var taken from the config file
2735 // load r2 features & components
2737 CVerboseClock
clock("Execution of r2_core.lua");
2738 doLuaScript("r2_core.lua", "r2ed common functions and definitions");
2740 initClassInheritanceTable();
2743 CLuaStackChecker
lsc4(&getLua());
2744 setCurrentTool(NULL
); // force the default tool (select / move)
2749 // TMP nico : unit test for newpoly stuff
2752 _Initialized
= true;
2754 _LuaUIMainLoop
= _Env
["UIMainLoop"];
2756 if (_SerializeUIConfig
)
2758 // load virtual desktops configs
2759 bool configLoaded
= false;
2761 CVerboseClock
clock("Load of ui config from disk ");
2762 // if access mode is DM, then load the whole ui (else it has been previuously loaded)
2763 if (initialMode
== AnimationModePlay
)
2769 configLoaded
= loadUIConfig(getUIPrefix(initialMode
));
2773 // if not found then reset all virtual desktops (one for each mode of the editor)
2776 nlwarning("No interface config found, resetting editor windows to their default");
2777 setForceDesktopReset(true);
2781 setMode(initialMode
);
2784 CVerboseClock
clock("Update of localized elements");
2785 CWidgetManager::getInstance()->updateAllLocalisedElements();
2790 // *********************************************************************************************************
2791 std::string
CEditor::getUIPrefix(TMode mode
) const
2793 //H_AUTO(R2_CEditor_getUIPrefix)
2796 case AnimationModePlay
:
2800 return "r2ed_interface_";
2805 // *********************************************************************************************************
2806 uint
CEditor::getMaxNumPlotItems()
2808 //H_AUTO(R2_CEditor_getMaxNumPlotItems)
2810 fromString( CWidgetManager::getInstance()->getParser()->getDefine("r2ed_max_num_plot_item_sheets"), ret
);
2814 // *********************************************************************************************************
2815 CCDBNodeLeaf
*CEditor::getRefPlotItemSheetDBLeaf(uint index
)
2817 //H_AUTO(R2_CEditor_getRefPlotItemSheetDBLeaf)
2818 return NLGUI::CDBManager::getInstance()->getDbProp(toString("LOCAL:R2:REFERENCE_PLOT_ITEMS:%d:SHEET", (int) index
), false);
2821 // *********************************************************************************************************
2822 CCDBNodeLeaf
*CEditor::getPlotItemSheetDBLeaf(uint index
)
2824 //H_AUTO(R2_CEditor_getPlotItemSheetDBLeaf)
2825 return NLGUI::CDBManager::getInstance()->getDbProp(toString("LOCAL:R2:PLOT_ITEMS:%d:SHEET", (int) index
), false);
2829 // *********************************************************************************************************
2830 void CEditor::setReferencePlotItemSheet(uint index
, uint32 sheetId
)
2832 //H_AUTO(R2_CEditor_setReferencePlotItemSheet)
2833 CCDBNodeLeaf
*leaf
= getRefPlotItemSheetDBLeaf(index
);
2836 leaf
->setValue32(sheetId
);
2838 leaf
= NLGUI::CDBManager::getInstance()->getDbProp(toString("LOCAL:R2:AVAILABLE_PLOT_ITEMS:%d:SHEET", (int) index
), false);
2841 leaf
->setValue32(sheetId
);
2845 // *********************************************************************************************************
2846 void CEditor::initDummyPlotItems()
2848 //H_AUTO(R2_CEditor_initDummyPlotItems)
2849 uint maxNumPlotItems
= getMaxNumPlotItems();
2850 uint numItems
= std::min(10u, maxNumPlotItems
);
2852 for(k
= 0; k
< numItems
; ++k
)
2854 CCDBNodeLeaf
*destLeaf
= getPlotItemSheetDBLeaf(k
);
2855 if (!destLeaf
) continue;
2856 CCDBNodeLeaf
*srcLeaf
= getRefPlotItemSheetDBLeaf(k
);
2857 destLeaf
->setValue32(srcLeaf
? srcLeaf
->getValue32() : 0u);
2859 for(; k
< maxNumPlotItems
; ++k
)
2861 CCDBNodeLeaf
*destLeaf
= getPlotItemSheetDBLeaf(k
);
2862 if (!destLeaf
) continue;
2863 destLeaf
->setValue32(0);
2867 // *********************************************************************************************************
2868 void CEditor::resetPlotItems()
2870 //H_AUTO(R2_CEditor_resetPlotItems)
2871 uint maxNumPlotItems
= getMaxNumPlotItems();
2872 // uint numItems = std::min(10u, maxNumPlotItems);
2873 for(uint k
= 0; k
< maxNumPlotItems
; ++k
)
2875 CCDBNodeLeaf
*destLeaf
= getPlotItemSheetDBLeaf(k
);
2876 if (!destLeaf
) continue;
2877 destLeaf
->setValue32(0);
2879 _PlotItemInfos
.clear();
2882 // *********************************************************************************************************
2883 void CEditor::initReferencePlotItems()
2885 //H_AUTO(R2_CEditor_initReferencePlotItems)
2887 CVerboseClock
clock("InitReferencePlotItems");
2888 uint maxNumPlotItems
= getMaxNumPlotItems();
2889 clamp(maxNumPlotItems
, 0u, 1024u);
2891 // look for plot item sheets
2892 const CSheetManager::TEntitySheetMap
&sheets
= SheetMngr
.getSheets();
2893 for(CSheetManager::TEntitySheetMap::const_iterator it
= sheets
.begin(); it
!= sheets
.end(); ++it
)
2895 if (it
->second
.EntitySheet
&& it
->second
.EntitySheet
->Type
== CEntitySheet::ITEM
)
2897 std::string name
= it
->second
.EntitySheet
->Id
.toString();
2898 if (strstr(name
.c_str(), "r2_plot_item"))
2900 uint32 sheetId
= it
->second
.EntitySheet
->Id
.asInt();
2901 setReferencePlotItemSheet(currIndex
, sheetId
);
2906 for (; currIndex
< maxNumPlotItems
; ++currIndex
)
2908 setReferencePlotItemSheet(currIndex
, 0);
2915 // *********************************************************************************************************
2916 bool CEditor::loadUIConfig(const std::string
&prefix
)
2918 //H_AUTO(R2_CEditor_loadUIConfig)
2921 std::string filename
= "save/" + prefix
+ PlayerSelectedFileName
+ ".icfg";
2922 if (!CFile::fileExists(filename
))
2923 filename
= "save/shared_" + prefix
+ ".icfg";
2925 return getUI().loadConfig(filename
);
2928 // *********************************************************************************************************
2929 void CEditor::saveUIConfig()
2931 //H_AUTO(R2_CEditor_saveUIConfig)
2933 // if there are dirt desktop, update all of them
2934 if (_Mode
!= AnimationModePlay
)
2936 bool restoreMode
= false;
2937 uint8 oldMode
= getUI().getMode();
2938 for (uint k
= 0; k
< 4; ++k
)
2940 if (_ForceDesktopReset
[k
])
2944 _ForceDesktopReset
[k
] = false;
2953 std::string filename
= "save/" + getUIPrefix(_Mode
) + PlayerSelectedFileName
+ ".icfg";
2954 std::string sharedfile
= "save/shared_" + getUIPrefix(_Mode
) + ".icfg";
2955 if (!CFile::fileExists(filename
) && CFile::fileExists(sharedfile
))
2956 filename
= sharedfile
;
2958 getUI().saveConfig(filename
);
2961 // *********************************************************************************************************
2962 void CEditor::initDecals()
2964 //H_AUTO(R2_CEditor_initDecals)
2967 CLuaObject config
= getEnv()["Config"];
2968 CLuaObject objHighlight
= config
["HightlightDecalLook"];
2969 CLuaObject objSelect
= config
["SelectDecalLook"];
2970 CLuaObject objSelecting
= config
["SelectingDecalLook"];
2971 CLuaObject objPioneer
= config
["PionneerDecalLook"];
2973 _HighlightDecalAnim
.buildFromLuaTable(objHighlight
);
2974 _SelectDecalAnim
.buildFromLuaTable(objSelect
);
2975 _SelectingDecalAnim
.buildFromLuaTable(objSelecting
);
2976 _PionneerDecalAnim
.buildFromLuaTable(objPioneer
);
2977 _HighlightDecal
.setClipDownFacing(true);
2978 _SelectDecal
.setClipDownFacing(true);
2979 _PionneerDecal
.setClipDownFacing(true);
2982 boxLook
.init(getEnv()["PrimRender"]["SelectBoxLook"]);
2983 _SelectBox
.setLook(boxLook
);
2984 boxLook
.init(getEnv()["PrimRender"]["HighlightBoxLook"]);
2985 _HighlightBox
.setLook(boxLook
);
2990 // *********************************************************************************************************
2991 void CEditor::showPrimRender(CPrimRender
&dest
, const NLMISC::CAABBox
&localBox
, const NLMISC::CMatrix
&worldMat
, const CDecalAnim
&refDecalAnim
)
2993 //H_AUTO(R2_CEditor_showPrimRender)
2995 static NLMISC::CPolygon2D poly2D
;
2996 poly2D
.Vertices
.resize(4);
2997 CVector pmin
= localBox
.getMin();
2998 CVector pmax
= localBox
.getMax();
2999 poly2D
.Vertices
[0] = worldMat
* CVector(pmin
.x
, pmin
.y
, pmin
.z
);
3000 poly2D
.Vertices
[1] = worldMat
* CVector(pmax
.x
, pmin
.y
, pmin
.z
);
3001 poly2D
.Vertices
[2] = worldMat
* CVector(pmax
.x
, pmax
.y
, pmin
.z
);
3002 poly2D
.Vertices
[3] = worldMat
* CVector(pmin
.x
, pmax
.y
, pmin
.z
);
3003 NLMISC::CAABBox bbox
;
3004 CLandscapePolyDrawer::computeBBoxFromPolygon(poly2D
, bbox
);
3005 dest
.setVertices(poly2D
.Vertices
);
3006 //dest.setWorldMapPolyColor(polyColor);
3007 float animRatio
= refDecalAnim
.DurationInMs
== 0 ? 0.f
: (T1
% refDecalAnim
.DurationInMs
) / (float) refDecalAnim
.DurationInMs
;
3008 animRatio
= 0.5f
* cosf(2.f
* (float) Pi
* animRatio
) + 0.5f
;
3009 CRGBA color
= blend(refDecalAnim
.StartDiffuse
, refDecalAnim
.EndDiffuse
, animRatio
);
3010 CPrimLook pl
= dest
.getLook();
3011 pl
.EdgeLook
.DecalColor
= pl
.VertexLook
.DecalColor
= pl
.FirstVertexLook
.DecalColor
= color
;
3013 dest
.addDecalsToRenderList();
3014 static volatile bool showPoly
= true;
3017 CLandscapePolyDrawer::getInstance().addPoly(poly2D
, dest
.getLook().EdgeLook
.WorldMapColor
, bbox
);
3021 // *********************************************************************************************************
3022 void CEditor::showSelectBox(const NLMISC::CAABBox
&localBox
, const NLMISC::CMatrix
&worldMat
)
3024 //H_AUTO(R2_CEditor_showSelectBox)
3026 showPrimRender(_SelectBox
, localBox
, worldMat
, _SelectDecalAnim
);
3030 // *********************************************************************************************************
3031 void CEditor::showHighlightBox(const NLMISC::CAABBox
&localBox
, const NLMISC::CMatrix
&worldMat
)
3033 //H_AUTO(R2_CEditor_showHighlightBox)
3035 showPrimRender(_HighlightBox
, localBox
, worldMat
, _HighlightDecalAnim
);
3038 // *********************************************************************************************************
3039 void CEditor::showSelectDecal(const NLMISC::CVector
&pos
, float scale
)
3041 //H_AUTO(R2_CEditor_showSelectDecal)
3043 updateDecalBlendRegion(_SelectDecal
, pos
);
3044 showDecal(pos
, scale
, _SelectDecal
, _SelectDecalAnim
);
3048 // *********************************************************************************************************
3049 void CEditor::showHighlightDecal(const NLMISC::CVector
&pos
, float scale
)
3051 //H_AUTO(R2_CEditor_showHighlightDecal)
3053 updateDecalBlendRegion(_HighlightDecal
, pos
);
3054 showDecal(pos
, scale
, _HighlightDecal
, _HighlightDecalAnim
);
3057 // *********************************************************************************************************
3058 void CEditor::showDecal(const NLMISC::CVector2f
&pos
, float scale
, CDecal
&decal
, const CDecalAnim
&decalAnim
)
3060 //H_AUTO(R2_CEditor_showDecal)
3062 float animRatio
= decalAnim
.DurationInMs
== 0 ? 0.f
: ((T1
- _DecalRefTime
) % decalAnim
.DurationInMs
) / (float) decalAnim
.DurationInMs
;
3063 animRatio
= 0.5f
* cosf(2.f
* (float) Pi
* animRatio
) + 0.5f
;
3064 decalAnim
.updateDecal(pos
, animRatio
, decal
, scale
);
3065 decal
.addToRenderList();
3068 // *********************************************************************************************************
3069 void CEditor::addSelectingDecal(const NLMISC::CVector
&pos
, float scale
)
3071 //H_AUTO(R2_CEditor_addSelectingDecal)
3073 CSelectingDecal
*decal
= NULL
;
3074 // see if there's an unused decal in the list
3075 for(uint k
= 0; k
< _SelectingDecals
.size(); ++k
)
3077 if (_SelectingDecals
[k
]->EndDate
< T1
)
3079 decal
= _SelectingDecals
[k
];
3085 _SelectingDecals
.push_back(new CSelectingDecal
);
3086 decal
= _SelectingDecals
.back();
3088 decal
->EndDate
= T1
+ _SelectingDecalAnim
.DurationInMs
;
3090 decal
->Scale
= scale
;
3092 updateDecalBlendRegion(decal
->Decal
, pos
);
3096 // *********************************************************************************************************
3097 void CEditor::updateSelectingDecals()
3099 //H_AUTO(R2_CEditor_updateSelectingDecals)
3101 if (_SelectingDecalAnim
.DurationInMs
== 0) return;
3102 for(uint k
= 0; k
< _SelectingDecals
.size(); ++k
)
3104 CSelectingDecal
*decal
= _SelectingDecals
[k
];
3107 if (decal
->EndDate
> T1
)
3109 float animRatio
= (float) (T1
- (decal
->EndDate
- _SelectingDecalAnim
.DurationInMs
)) / (float) _SelectingDecalAnim
.DurationInMs
;
3110 _SelectingDecalAnim
.updateDecal(decal
->Pos
, animRatio
, decal
->Decal
, decal
->Scale
);
3111 decal
->Decal
.addToRenderList();
3117 // *******************************************************************************************************
3118 void CEditor::reset()
3120 //H_AUTO(R2_CEditor_reset)
3121 if (ClientCfg
.R2EDExtendedDebug
)
3122 Driver
->setWindowTitle(ucstring("Resetting R2ED editor ..."));
3125 _SerializeUIConfig
= false; // prevent reloading of ui for speed
3126 _WantedActOnInit
.clear();
3127 if (getCurrentAct())
3129 R2::CObjectTable
* act
= getCurrentAct()->getObjectTable();
3130 if (act
->isString("Name"))
3132 _WantedActOnInit
= act
->toString("Name");
3136 _WantedActOnInit
= act
->toString("Title"); //obsolete
3139 CVerboseClock
clock("Reset of editor ");
3141 TMode oldMode
= _Mode
;
3142 TAccessMode oldAccessMode
= _AccessMode
;
3143 if (_Mode
== EditionMode
)
3145 R2::getEditor().getLua().executeScriptNoThrow("r2.Version.save(\"save/r2_buffer.dat\")");
3153 setForceDesktopReset(true); // next changes of desktop should force a reset, since ui has been reloaded
3154 ReloadUIFlag
= false;
3156 init(oldMode
, oldAccessMode
);
3158 if (oldMode
== EditionMode
)
3160 CVerboseClock
clock("Request reconnection ");
3161 getLua().executeScriptNoThrow("r2.requestReconnection()");
3163 // try to return to the act with the same title
3164 _SerializeUIConfig
= true;
3166 if (ClientCfg
.R2EDExtendedDebug
)
3168 Driver
->setWindowTitle(CI18N::get("TheSagaOfRyzom"));
3170 Driver
->showWindow();
3173 getUI().displaySystemInfo(CI18N::get("uiR2EDEditorReseted"), "BC");
3176 // *********************************************************************************************************
3177 void CEditor::reloadUI()
3179 //H_AUTO(R2_CEditor_reloadUI)
3181 CVerboseClock
clock("Reload ui");
3182 // reload same list than at startup (given in client.cfg)
3183 for (uint k
= 0; k
< ClientCfg
.XMLR2EDInterfaceFiles
.size(); ++k
)
3185 reloadUI(ClientCfg
.XMLR2EDInterfaceFiles
[k
].c_str());
3189 // *********************************************************************************************************
3190 void CEditor::reloadUI(const char *filename
)
3192 //H_AUTO(R2_CEditor_reloadUI)
3194 CVerboseClock
clock("Loading ui " + std::string(filename
));
3195 CLuaStackChecker
ls(&getLua());
3197 std::string path
= CPath::lookup(filename
, false);
3200 nlwarning("File %s not found, r2 ui not (re)loaded.", filename
);
3203 uint32 fileDate
= CFile::getFileModificationDate(path
);
3204 if (_LastUIModificationDate
.count(filename
) == 0)
3206 _LastUIModificationDate
[filename
] = 0;
3208 uint32
&lastUIModificationDate
= _LastUIModificationDate
[filename
];
3209 if (fileDate
> lastUIModificationDate
|| !ClientCfg
.R2EDDontReparseUnchangedUIFiles
) // TMP (init not complete else ...)
3211 // reload the ui files
3212 NLMISC::ICommand::execute(toString("loadui %s", filename
).c_str(), g_log
);
3213 lastUIModificationDate
= fileDate
;
3217 if (!ClientCfg
.R2EDDontReparseUnchangedUIFiles
)
3219 nlwarning("ui file %s date unchanged, not reloading.", filename
);
3226 // *********************************************************************************************************
3227 void CEditor::connectAsCreator()
3229 //H_AUTO(R2_CEditor_connectAsCreator)
3233 CLuaStackChecker
lsc2(&getLua());
3234 _DMC
->testConnectionAsCreator();
3239 // string cached into lua for fast comparison
3240 static CLuaString
lstr_isNil("isNil");
3241 static CLuaString
lstr_Parent("Parent");
3242 static CLuaString
lstr_ParentInstance("ParentInstance");
3243 static CLuaString
lstr_IndexInParent("IndexInParent");
3244 static CLuaString
lstr_User("User");
3245 static CLuaString
lstr_Size("Size");
3246 static CLuaString
lstr_DisplayerUI("DisplayerUI");
3247 static CLuaString
lstr_DisplayerVisual("DisplayerVisual");
3248 static CLuaString
lstr_DisplayerProperties("DisplayerProperties");
3253 // *********************************************************************************************************
3254 void CEditor::initObjectProjectionMetatable()
3256 //H_AUTO(R2_CEditor_initObjectProjectionMetatable)
3258 _ObjectProjectionMetatable
= getEnv().newTable("_instance_projection_metatable");
3259 // projection functions
3263 static bool checkTag(CLuaState
&ls
)
3265 CLuaStackChecker
lsc(&ls
);
3270 if (ls
.isString(-1))
3272 if (strcmp(ls
.toString(-1), "CObjectTable") == 0)
3280 nlwarning("metatable error : Editor object expected");
3285 static int index(CLuaState
&ls
)
3287 nlassert(ls
.getTop() == 2);
3289 if (!checkTag(ls
)) return false;
3291 CObjectTable::TRefPtrConst
&obj
= *(CObjectTable::TRefPtrConst
*) ls
.toUserData(1);
3292 if (OPERATOR_EQUAL(obj
, NULL
))
3293 //NLMISC::operator==(obj, NULL))
3295 std::string index
= ls
.toString(2);
3297 if ( index
== "isNil")
3298 //if (std::operator==(index "isNil")
3303 CLuaIHMRyzom::dumpCallStack();
3304 // object has been deleted but the script maintains a reference on it
3305 throw ELuaWrappedFunctionException(&ls
, "Attempt to access an erased object");
3308 if (ls
.isInteger(2))
3310 // index is an integer
3311 const CObject
*other
= obj
->getValueAtPos((uint32
) ls
.toInteger(2));
3314 pushValue(ls
, other
);
3319 // 'bad index' message already printed by CObject::getValue
3320 CLuaIHMRyzom::dumpCallStack();
3324 if (!ls
.isString(2))
3326 nlwarning("String expected when accessing an object property, %s found instead", ls
.getTypename(2));
3327 CLuaIHMRyzom::dumpCallStack(0);
3331 const char *strId
= ls
.toString(2); // strings are shared in lua, so a pointer comparison is sufficient
3334 // NB nico : this was added before the R2::CInstance class derived from CReflectable,
3335 // -> see if some of the following properties may better fit into R2::CInstance exported properties
3337 if (OPERATOR_EQUAL( lstr_isNil
, strId
))
3343 if (OPERATOR_EQUAL(strId
, lstr_Parent
))
3345 if (!obj
->getParent())
3350 nlassert(obj
->getParent()->isTable());
3351 getEditor().projectInLua((CObjectTable
*) obj
->getParent());
3354 else if (OPERATOR_EQUAL(strId
, lstr_ParentInstance
))
3356 // look for parent instance (that is, not the
3357 CObject
*parent
= obj
->getParent();
3360 if (parent
->findAttr("InstanceId"))
3362 getEditor().projectInLua((CObjectTable
*) parent
);
3365 parent
= parent
->getParent();
3370 if (OPERATOR_EQUAL(strId
, lstr_IndexInParent
))
3372 if (!obj
->getParent())
3377 sint32 index
= obj
->getParent()->findIndex(obj
);
3378 if (obj
->getParent()->getKey(index
).empty())
3388 else if (OPERATOR_EQUAL(strId
, lstr_User
))
3390 // push user table on stack
3391 CEditor::getLuaUserTableFromObject(ls
, *obj
);
3394 else if (OPERATOR_EQUAL(strId
, lstr_Size
))
3398 ls
.push(obj
->getSize());
3407 if (OPERATOR_EQUAL(strId
, lstr_DisplayerUI
))
3409 CInstance
*instance
= getEditor().getInstanceFromObject(obj
);
3417 if (instance
->getDisplayerUI())
3419 instance
->getDisplayerUI()->pushLuaAccess(ls
);
3429 if (OPERATOR_EQUAL(strId
, lstr_DisplayerVisual
))
3431 CInstance
*instance
= getEditor().getInstanceFromObject(obj
);
3439 if (instance
->getDisplayerVisual())
3441 instance
->getDisplayerVisual()->pushLuaAccess(ls
);
3451 if (OPERATOR_EQUAL(strId
, lstr_DisplayerProperties
))
3453 CInstance
*instance
= getEditor().getInstanceFromObject(obj
);
3461 if (instance
->getDisplayerProperties())
3463 instance
->getDisplayerProperties()->pushLuaAccess(ls
);
3472 // else tries with a string
3473 std::string index
= ls
.toString(2);
3474 const CObject
*other
= getObject(obj
, index
);
3477 pushValue(ls
, other
);
3480 // this is not an attribute of the class
3481 // -> maybe this is a method ?
3482 // look in the parent class is there is a function with the wanted name
3483 // NOTE : calling a method on an editor object in the script can be done by doing
3484 // r2:getClass(instance).methodName(instance, parameters ...)
3485 // with this trick, one can do instance:methodName(parameters ...)
3486 CObject
*className
= obj
->findAttr("Class");
3489 CLuaObject method
= getEditor().getClasses()[className
->toString()][index
];
3490 if (method
.isFunction())
3497 // Try with a property exported from CInstance
3498 // Is is ok to test thos properties after those defined in lua classes definition
3499 // because the init check that no "native" property is declared by the user
3501 CInstance
*instance
= getEditor().getInstanceFromObject(obj
);
3504 const CReflectedProperty
*prop
= instance
->getReflectedProperty(index
, false);
3507 CLuaIHM::luaValueFromReflectedProperty(ls
, *instance
, *prop
);
3512 // unknown attribute
3516 static int newIndex(CLuaState
&ls
)
3518 nlassert(ls
.getTop() == 3);
3520 if (!checkTag(ls
)) return false;
3522 CObjectTable::TRefPtrConst
&obj
= *(CObjectTable::TRefPtrConst
*) ls
.toUserData(1);
3525 throw ELuaWrappedFunctionException(&ls
, "Trying to set a property in an erased object, returning nil");
3528 if (!checkTag(ls
)) return false;
3530 // try with a native (local ..) property exported from CInstance
3531 CInstance
*instance
= getEditor().getInstanceFromObject(obj
);
3534 const CReflectedProperty
*prop
= instance
->getReflectedProperty(ls
.toString(2));
3537 CLuaIHM::luaValueToReflectedProperty(ls
, 3, *instance
, *prop
);
3541 // other instances properties are read only !!
3542 throw ELuaWrappedFunctionException(&ls
, "Property %s of editor object is read-only. You must use 'r2.requestSetNode' function to change it", ls
.toString(2));
3544 static int gc(CLuaState
&ls
)
3547 if (!checkTag(ls
)) return false;
3549 // TODO : maybe not useful ...
3550 CObjectTable::TRefPtrConst
&obj
= *(CObjectTable::TRefPtrConst
*) ls
.toUserData(1);
3551 typedef CObjectTable::TRefPtrConst TRefPtrConst
;
3552 obj
.~TRefPtrConst();
3555 // tool function used by 'next'
3556 // TODO : put this code in a better place ...
3557 static void pushValue(CLuaState
&ls
, const CObject
*obj
)
3564 if (obj
->isString())
3566 ls
.push(obj
->toString());
3568 else if (obj
->isInteger())
3570 ls
.push(obj
->toInteger());
3572 else if (obj
->isNumber())
3574 ls
.push(obj
->toNumber());
3576 else if (obj
->isTable())
3578 getEditor().projectInLua((CObjectTable
*) obj
);
3582 nlassert(0); // type not supported ...
3586 // helper function used by 'next' : push a key
3587 static void pushKey(CLuaState
&ls
, const CObject
*obj
, sint32 index
)
3594 if (obj
->getKey(index
).empty())
3600 ls
.push(obj
->getKey(index
));
3605 // special : we redefine the 'next' global function found in the standard
3606 // lua library in order to allow fields traversal for the projected object.
3607 // This is done in lua in the 'r2_core.lua' script
3608 // The new 'next' function will look into the object metatable
3609 // If a __next function is found, then it will be called for traversal
3610 // otherwise, the standard 'next' function is called instead.
3611 // This allow to have a traversal for objects that are not tables
3612 static int next(CLuaState
&ls
)
3614 if (ls
.getTop() != 2)
3616 CLuaIHM::fails(ls
, "__next metamethod require 2 arguments (table & key)");
3619 if (!checkTag(ls
)) return false;
3621 CObjectTable::TRefPtrConst
&obj
= *(CObjectTable::TRefPtrConst
*) ls
.toUserData(1);
3624 throw ELuaWrappedFunctionException(&ls
, "editor object '__next' metatmethod : Attempt to access an erased object");
3628 // key is nil -> start of traversal
3629 if(obj
->getSize() == 0)
3633 return 2; // let (nil, nil) on the stack
3637 // look for duplicated keys (ignoring empty keys, because in this case th index is the key)
3638 std::set
<std::string
> keys
;
3639 for(uint k
= 0; k
< obj
->getSize(); ++k
)
3641 std::string key
= obj
->getKey((sint32
) k
);
3644 if (keys
.count(key
))
3646 nlwarning("Duplicated key of type string found while attempting to enumerate an instance content.");
3647 nlwarning("key is %s", key
.c_str());
3648 CLuaIHMRyzom::dumpCallStack(1);
3649 CLuaIHM::fails(ls
, "Aborting to avoid infinite loop.");
3655 pushKey(ls
, obj
, 0);
3656 pushValue(ls
, obj
->getValueAtPos(0));
3662 // continuation of traversal
3663 // -> retrieve index from the key
3665 if (ls
.isInteger(2))
3667 index
= (uint32
) ls
.toInteger(2);
3671 if (!ls
.isString(2))
3673 nlwarning("__next metamethod : string expected");
3680 index
= obj
->findIndex(ls
.toString(2));
3685 nlwarning("__next metamethod : key not found");
3691 // retrieve next key
3692 sint32 newIndex
= (uint32
) (index
+ 1);
3693 if (newIndex
== (sint32
) obj
->getSize())
3695 // this was the last element, returns nil
3704 pushKey(ls
, obj
, newIndex
);
3705 pushValue(ls
, obj
->getValueAtPos(newIndex
));
3711 static int equal(CLuaState
&ls
)
3714 static volatile bool from
= false;
3717 CLuaIHMRyzom::dumpCallStack(0);
3719 nlassert(ls
.getTop() == 2);
3720 if (!checkTag(ls
)) return false;
3721 CObjectTable::TRefPtrConst
&lhs
= *(CObjectTable::TRefPtrConst
*) ls
.toUserData(1);
3722 CObjectTable::TRefPtrConst
&rhs
= *(CObjectTable::TRefPtrConst
*) ls
.toUserData(2);
3723 ls
.push(OPERATOR_EQUAL(lhs
, rhs
));
3727 // affect functions to the metatable
3728 getLua().push(CProjector::index
);
3729 _ObjectProjectionMetatable
.setValue("__index", CLuaObject(getLua()));
3730 getLua().push(CProjector::newIndex
);
3731 _ObjectProjectionMetatable
.setValue("__newindex", CLuaObject(getLua()));
3732 getLua().push(CProjector::gc
);
3733 _ObjectProjectionMetatable
.setValue("__gc", CLuaObject(getLua()));
3734 getLua().push(CProjector::next
);
3735 _ObjectProjectionMetatable
.setValue("__next", CLuaObject(getLua()));
3736 getLua().push(CProjector::equal
);
3737 _ObjectProjectionMetatable
.setValue("__eq", CLuaObject(getLua()));
3738 // tag to mark that the user data is a CObjectTable ref ptr
3739 _ObjectProjectionMetatable
.setValue("tag", std::string("CObjectTable"));
3742 // *********************************************************************************************************
3743 void CEditor::getLuaUserTableFromObject(CLuaState
&ls
, const CObjectTable
&table
)
3745 //H_AUTO(R2_CEditor_getLuaUserTableFromObject)
3747 CLuaStackChecker
lsc(&ls
, 1);
3748 // read write environement accessible from lua
3749 ls
.pushLightUserData((void *) &table
);
3750 ls
.getTable(LUA_REGISTRYINDEX
);
3754 // no user table created yet ?... create it
3755 ls
.pushLightUserData((void *) &table
);
3757 ls
.pushValue(-1); // saves the table
3759 ls
.setTable(LUA_REGISTRYINDEX
);
3760 // table remains on the stack
3764 // *********************************************************************************************************
3765 void CEditor::setCurrentAct(CInstance
*act
)
3767 //H_AUTO(R2_CEditor_setCurrentAct)
3769 if (!_ScenarioInstance
) return;
3770 if (_ClearingContent
) return;
3771 bool currentActSelected
= _SelectedInstance
&& (_SelectedInstance
== _CurrentAct
);
3772 CInstance
* previousAct
= _CurrentAct
;
3773 _CurrentAct
= act
? act
: getBaseAct();
3775 struct CPreActChangedVisitor
: public IInstanceVisitor
3777 virtual void visit(CInstance
&inst
)
3779 inst
.onPreActChanged();
3782 CPreActChangedVisitor preActChangedVisitor
;
3783 _ScenarioInstance
->visit(preActChangedVisitor
);
3784 struct CActChangedVisitor
: public IInstanceVisitor
3786 virtual void visit(CInstance
&inst
)
3788 inst
.onActChanged();
3791 CActChangedVisitor actChangedVisitor
;
3792 _ScenarioInstance
->visit(actChangedVisitor
);
3796 // warn lua that current act has changed
3803 previousAct
->getLuaProjection().push();
3812 _CurrentAct
->getLuaProjection().push();
3815 callEnvMethod("onActChanged", 2, 0);
3817 setSelectedInstance(currentActSelected
? _CurrentAct
: NULL
);
3820 setCurrentTool(NULL
);
3823 // *********************************************************************************************************
3824 void CEditor::setCurrentActFromTitle(const std::string
&wantedTitle
)
3826 //H_AUTO(R2_CEditor_setCurrentActFromTitle)
3830 nlwarning("Scenario initialisation failed, can't set current act");
3833 CObject
*actTable
= _Scenario
->getAttr("Acts");
3834 if (actTable
->isTable())
3836 for(uint k
= 0; k
< actTable
->getSize(); ++k
)
3838 R2::CObject
*act
= actTable
->getValueAtPos(k
);
3840 std::string actTitle
;
3841 if (act
->isString("Name"))
3843 actTitle
= act
->toString("Name");
3847 actTitle
= act
->toString("Title"); //obsolete
3850 if (actTitle
== wantedTitle
)
3852 setCurrentAct(getInstanceFromObject(act
));
3859 nlwarning("'Acts' field in scenario should be a table");
3863 // *********************************************************************************************************
3864 void CEditor::projectInLua(const CObjectTable
*table
)
3866 //H_AUTO(R2_CEditor_projectInLua)
3869 const CObjectTableClient
*otc
= NLMISC::safe_cast
<const CObjectTableClient
*>(table
);
3870 otc
->pushOnLuaStack(getLua(), _ObjectProjectionMetatable
);
3874 // *********************************************************************************************************
3875 void CEditor::backupRequestCommands()
3877 //H_AUTO(R2_CEditor_backupRequestCommands)
3878 nlassert(!_OldLuaRequestInsertNode
.isValid()); // restoreRequestCommands not called ?
3879 nlassert(!_OldLuaRequestInsertGhostNode
.isValid());
3880 nlassert(!_OldLuaRequestSetNode
.isValid());
3881 nlassert(!_OldLuaRequestEraseNode
.isValid());
3882 nlassert(!_OldLuaRequestMoveNode
.isValid());
3884 _OldLuaRequestInsertNode
= getEnv()["requestInsertNode"];
3885 _OldLuaRequestInsertGhostNode
= getEnv()["requestInsertGhostNode"];
3886 _OldLuaRequestSetNode
= getEnv()["requestSetNode"];
3887 _OldLuaRequestEraseNode
= getEnv()["requestEraseNode"];
3888 _OldLuaRequestMoveNode
= getEnv()["requestMoveNode"];
3890 struct CIgnoreRequestCall
3892 static int requestSomething(CLuaState
&)
3894 nlwarning("PAS BIEN C MAL !!!");
3896 CLuaIHM::debugInfo("Can't call a 'r2.request' command while object are erased in displayers, or are just being created (in this case, use onPostCreate instead) !");
3897 CLuaIHM::debugInfo("Callstack is :");
3898 CLuaIHM::dumpCallStack(1);*/
3904 // While we delete the object tree, displayers will be triggered
3905 // Make sure that they don't call any r2.requestSomething commands, end if so,
3906 // print an error message
3907 getEnv().setValue("requestInsertNode", CIgnoreRequestCall::requestSomething
);
3908 getEnv().setValue("requestInsertGhostNode", CIgnoreRequestCall::requestSomething
);
3909 getEnv().setValue("requestSetNode", CIgnoreRequestCall::requestSomething
);
3910 getEnv().setValue("requestEraseNode", CIgnoreRequestCall::requestSomething
);
3911 getEnv().setValue("requestMoveNode", CIgnoreRequestCall::requestSomething
);
3914 // *********************************************************************************************************
3915 void CEditor::restoreRequestCommands()
3917 //H_AUTO(R2_CEditor_restoreRequestCommands)
3918 nlassert(_OldLuaRequestInsertNode
.isValid()); // backupRequestCommands not called ?
3919 nlassert(_OldLuaRequestInsertGhostNode
.isValid());
3920 nlassert(_OldLuaRequestSetNode
.isValid());
3921 nlassert(_OldLuaRequestEraseNode
.isValid());
3922 nlassert(_OldLuaRequestMoveNode
.isValid());
3923 // restore old functions
3924 getEnv().setValue("requestInsertNode", _OldLuaRequestInsertNode
);
3925 getEnv().setValue("requestInsertGhostNode", _OldLuaRequestInsertGhostNode
);
3926 getEnv().setValue("requestSetNode", _OldLuaRequestSetNode
);
3927 getEnv().setValue("requestEraseNode", _OldLuaRequestEraseNode
);
3928 getEnv().setValue("requestMoveNode", _OldLuaRequestMoveNode
);
3930 _OldLuaRequestInsertNode
.release();
3931 _OldLuaRequestInsertGhostNode
.release();
3932 _OldLuaRequestSetNode
.release();
3933 _OldLuaRequestEraseNode
.release();
3934 _OldLuaRequestMoveNode
.release();
3937 // *********************************************************************************************************
3938 void CEditor::clearContent()
3940 nlwarning("*R2* clear content");
3941 setMaxVisibleEntityExceededFlag(false);
3943 //H_AUTO(R2_CEditor_clearContent)
3944 if (_Mode
!= EditionMode
&& _Mode
!= AnimationModeLoading
) return;
3945 _ClearingContent
= true;
3948 setSelectedInstance(NULL
);
3949 setFocusedInstance(NULL
);
3951 // backup all "requestCommand"
3954 if (_CurrentTool
) _CurrentTool
->cancel();
3955 CTool::releaseMouse();
3957 delete _NewScenario
; // will be not NULL only if quit is called during the scenario connection screen
3958 _NewScenario
= NULL
;
3962 _InstancesByDispName
.clear();
3963 _InstancesByDispName
.resize(_ClassNameToIndex
.size());
3964 _InstanceObservers
.clear();
3965 _InstanceObserverHandles
.clear();
3967 _LocalGeneratedNames
.clear();
3971 _SelectedInstance
= NULL
;
3972 _FocusedInstance
= NULL
;
3973 _ScenarioInstance
= NULL
;
3975 _SelectingDecals
.clear();
3976 _InstanceObservers
.clear();
3977 _InstanceObserverHandles
.clear();
3978 _LastInstanceUnderPos
= NULL
;
3979 _CurrentTool
= NULL
;
3982 removeAllEntitySlots(); // for safety...
3983 _DMC
->CDynamicMapClient::scenarioUpdated(NULL
, false, 1); // clear scenario for real
3984 _ClearingContent
= false;
3986 _PlotItemInfos
.clear();
3988 PeopleInterraction
.removeAllFreeTellers();
3993 // *********************************************************************************************************
3994 void CEditor::setPlotItemInfos(const TMissionItem
&infos
)
3996 //H_AUTO(R2_CEditor_setPlotItemInfos)
3997 _PlotItemInfos
[infos
.SheetId
.asInt()] = infos
;
4000 // *********************************************************************************************************
4001 const TMissionItem
*CEditor::getPlotItemInfos(uint32 sheetId
) const
4003 //H_AUTO(R2_CEditor_getPlotItemInfos)
4004 std::map
<uint32
, TMissionItem
>::const_iterator it
= _PlotItemInfos
.find(sheetId
);
4005 if (it
== _PlotItemInfos
.end()) return NULL
;
4010 // *********************************************************************************************************
4011 void CEditor::release()
4013 nlwarning("*R2* release");
4014 //H_AUTO(R2_CEditor_release)
4015 GameContextMenu
.init("");
4016 setFixedLighting(false);
4019 if (_Mode
== NotInitialized
)
4021 // nothing more to do there
4025 // warn lua of final release
4026 callEnvMethod("onFinalRelease", 0, 0);
4028 if (_SerializeUIConfig
)
4030 // serialization disabled when resetting the editor (for speed)
4031 saveCurrentKeySet();
4034 CWidgetManager::getInstance()->hideAllWindows(); // make sure all action handlers are called while the r2 lua environment is still active
4036 _EntityCustomSelectBoxMap
.clear();
4038 // must do this after clearContent, which sets the default tool
4041 _CurrentTool
->cancel();
4042 _CurrentTool
= NULL
;
4045 // clear the environment
4046 if (CLuaManager::getInstance().getLuaState())
4048 getLua().pushGlobalTable();
4049 getLua().push(R2_LUA_PATH
);
4051 getLua().setTable(-3); // pop pop
4054 _Registry
.release();
4055 _ObjectProjectionMetatable
.release(); // AJM
4058 CEditorCheck::EditorCreated
= false;
4059 // force a garbage collection to free the mem for real
4060 getLua().setGCThreshold(0);
4070 nlassert(CDisplayerBase::ObjCount
== 0);
4071 _Initialized
= false;
4072 CEditorCheck::EditorCreated
= false; // AJM
4073 _Mode
= NotInitialized
;
4074 _AccessMode
= AccessModeUnknown
;
4076 ::IgnoreEntityDbUpdates
= false;
4079 _IslandCollision
.release();
4081 _LastUIModificationDate
.clear();
4082 _InstancesByDispName
.clear();
4084 delete _EntitySorter
;
4085 _EntitySorter
= NULL
;
4090 // *********************************************************************************************************
4091 void CEditor::removeAllEntitySlots()
4093 //H_AUTO(R2_CEditor_removeAllEntitySlots)
4095 for (uint k
= 1; k
< 255; ++k
)
4097 if (EntitiesMngr
.entity(k
) != NULL
)
4099 EntitiesMngr
.remove(k
, false);
4104 // *********************************************************************************************************
4105 void CEditor::registerDisplayers()
4107 //H_AUTO(R2_CEditor_registerDisplayers)
4109 static bool registered
= false;
4110 if (registered
) return;
4111 NLMISC_REGISTER_CLASS(R2::CDisplayerVisualActivitySequence
);
4112 NLMISC_REGISTER_CLASS(R2::CDisplayerVisualEntity
);
4113 NLMISC_REGISTER_CLASS(R2::CDisplayerVisualGroup
)
4114 NLMISC_REGISTER_CLASS(R2::CDisplayerVisualShape
)
4115 NLMISC_REGISTER_CLASS(R2::CDisplayerLua
)
4119 // *********************************************************************************************************
4120 void CEditor::registerTools()
4122 //H_AUTO(R2_CEditor_registerTools)
4124 static bool registered
= false;
4125 if (registered
) return;
4126 NLMISC_REGISTER_CLASS(R2::CToolDrawPrim
);
4127 NLMISC_REGISTER_CLASS(R2::CToolSelectMove
);
4128 NLMISC_REGISTER_CLASS(R2::CToolSelectRotate
);
4129 NLMISC_REGISTER_CLASS(R2::CToolNewVertex
);
4135 // *********************************************************************************************************
4136 void CEditor::setSelectedInstance(CInstance
*inst
)
4138 //H_AUTO(R2_CEditor_setSelectedInstance)
4140 if (inst
== _SelectedInstance
) return;
4141 forceSetSelectedInstance(inst
);
4144 // *********************************************************************************************************
4145 void CEditor::forceSetSelectedInstance(CInstance
*inst
)
4147 //H_AUTO(R2_CEditor_forceSetSelectedInstance)
4149 if (_EnteredInSetSelectedInstance
) return; // prevent recursive call (may happen because selection highlight an item in a menu, which trigger selection in turn)
4153 nlassert(inst
->getSelectableFromRoot());
4156 _EnteredInSetSelectedInstance
= true;
4159 nlassert(hasInstance(inst
)); // must have been added in the editor !
4161 if (_SelectedInstance
)
4163 _SelectedInstance
->onSelect(false);
4165 _SelectedInstance
= inst
;
4166 if (_SelectedInstance
)
4168 _SelectedInstance
->onSelect(true);
4171 // call r2 method 'onSelectInstance'
4172 if (!_SelectedInstance
)
4178 _SelectedInstance
->getLuaProjection().push();
4180 callEnvMethod("onSelectInstance", 1, 0);
4181 _EnteredInSetSelectedInstance
= false;
4185 // *********************************************************************************************************
4186 CInstance
*CEditor::getSelectedInstance() const
4188 //H_AUTO(R2_CEditor_getSelectedInstance)
4190 return _SelectedInstance
;
4193 // *********************************************************************************************************
4194 void CEditor::setFocusedInstance(CInstance
*inst
)
4196 //H_AUTO(R2_CEditor_setFocusedInstance)
4198 if (inst
== _FocusedInstance
) return;
4201 nlassert(hasInstance(inst
)); // must have been added in the editor !
4203 if (_FocusedInstance
)
4205 _FocusedInstance
->onFocus(false);
4207 _FocusedInstance
= inst
;
4208 if (_FocusedInstance
)
4210 _FocusedInstance
->onFocus(true);
4214 // *********************************************************************************************************
4215 CInstance
*CEditor::getFocusedInstance() const
4217 //H_AUTO(R2_CEditor_getFocusedInstance)
4219 return _FocusedInstance
;
4223 // *********************************************************************************************************
4224 bool CEditor::hasInstance(const CInstance
*instance
) const
4226 //H_AUTO(R2_CEditor_hasInstance)
4228 // TMP : slow test for debug
4229 for(TInstanceMap::const_iterator it
= _Instances
.begin(); it
!= _Instances
.end(); ++it
)
4231 if (it
->second
== instance
) return true;
4236 // *********************************************************************************************************
4237 bool CEditor::hasInstanceWithId(const TInstanceId
&id
) const
4239 //H_AUTO(R2_CEditor_hasInstanceWithId)
4241 return getInstanceFromId(id
) != NULL
;
4244 // *********************************************************************************************************
4245 CInstance
*CEditor::getInstanceFromId(const TInstanceId
&id
) const
4247 //H_AUTO(R2_CEditor_getInstanceFromId)
4249 const CObjectTable
*objTable
= getObjectTableFromId(id
);
4250 if (!objTable
) return NULL
;
4251 return getInstanceFromObject(objTable
);
4254 // *********************************************************************************************************
4255 sint
CEditor::getGeneratedNameIndex(const std::string
&nameUtf8
, const std::string
&baseNameUtf8
)
4257 //H_AUTO(R2_CEditor_getGeneratedNameIndex)
4259 if (nameUtf8
.size() >= baseNameUtf8
.size() + 2)
4261 if (nameUtf8
.substr(0, baseNameUtf8
.size()) == baseNameUtf8
)
4263 std::string::const_iterator strIt
= nameUtf8
.begin() + baseNameUtf8
.size();
4264 std::string::const_iterator endStrIt
= nameUtf8
.end();
4268 const char *numberStart
= &*strIt
;
4269 for (; strIt
!= endStrIt
&& (uint8
)(*strIt
) < (uint8
)'\x80' && isdigit(*strIt
); ++strIt
) {}
4270 if (strIt
== endStrIt
)
4273 fromString(numberStart
, ret
);
4282 // *********************************************************************************************************
4283 bool CEditor::isPostFixedByNumber(const ucstring
&baseName
)
4285 //H_AUTO(R2_CEditor_isPostFixedByNumber)
4286 // strip number & spaces at the end of the name
4287 sint lastIndex
= (sint
)baseName
.length() - 1;
4288 while (lastIndex
> 0)
4290 int currChar
= (int) baseName
[lastIndex
];
4291 if (((uint8
)currChar
>= (uint8
)'\x80' || !isdigit(currChar
)) &&
4299 return lastIndex
!= (sint
) baseName
.length() - 1;
4302 // *********************************************************************************************************
4303 ucstring
CEditor::genInstanceName(const ucstring
&baseName
)
4305 //H_AUTO(R2_CEditor_genInstanceName)
4308 // strip number & spaces at the end of the name
4309 ucstring strippedName
= baseName
;
4310 sint lastIndex
= (sint
)strippedName
.length() - 1;
4311 while (lastIndex
> 0)
4313 int currChar
= (int) strippedName
[lastIndex
];
4314 if (((uint8
)currChar
>= (uint8
)'\x80' || !isdigit(currChar
)) &&
4322 strippedName
= strippedName
.substr(0, lastIndex
+ 1);
4323 std::string baseNameUtf8
= strippedName
.toUtf8();
4325 for(TInstanceMap::const_iterator it
= _Instances
.begin(); it
!= _Instances
.end(); ++it
)
4327 maxIndex
= (uint
) std::max((sint
) maxIndex
, getGeneratedNameIndex(it
->second
->getName(), baseNameUtf8
));
4330 nlinfo("CEditor::genInstanceName newVersion");
4332 // Old part : used when there was a delay between net command and effect
4333 // did not work in some parts if genInstance is not followed by creation of an instance with that name
4336 // now, look in local generated names (instance that have not been already added to the scene)
4337 TGeneratedNameMap::iterator nameSetIt = _LocalGeneratedNames.find(baseNameUtf8);
4338 if (nameSetIt != _LocalGeneratedNames.end())
4340 if (!nameSetIt->second.empty())
4342 maxIndex = std::max(maxIndex, *(nameSetIt->second.rbegin())); // take bigger element of the set (the last element)
4345 // add max index in the map (will be removed when object is truly created)
4346 _LocalGeneratedNames[baseNameUtf8].insert(maxIndex + 1);
4348 return strippedName
+ " " + toString(maxIndex
+ 1);
4351 // *********************************************************************************************************
4352 void CEditor::setCookie(const TInstanceId
&instanceId
, const std::string
&key
, CLuaObject
&value
)
4354 //H_AUTO(R2_CEditor_setCookie)
4356 TCookieList
&cl
= _Cookies
[instanceId
];
4357 cl
.push_front(CCookie());
4358 CCookie
&cookie
= cl
.front(); // don't build struct and push to avoid costly copy of a CLuaObject
4360 cookie
.Value
= value
;
4363 // *********************************************************************************************************
4364 void CEditor::setCookie(const TInstanceId
&instanceId
, const std::string
&key
, bool value
)
4366 //H_AUTO(R2_CEditor_setCookie)
4368 getLua().push(value
);
4369 CLuaObject
obj(getLua());
4370 setCookie(instanceId
, key
, obj
);
4373 // *********************************************************************************************************
4374 void CEditor::setCurrentTool(CTool
*tool
)
4376 //H_AUTO(R2_CEditor_setCurrentTool)
4380 _CurrentTool
->cancel();
4386 // setting a tool in non R2 mode force to change the contextual cursor
4387 ContextCur
.release();
4388 ContextCur
.add(false, "STAND BY", DEFAULT_CURSOR
, 0.0f
, CEditor::checkCursor
, CEditor::mouseClick
);
4389 ContextCur
.context("STAND BY");
4392 CTool::setContextHelp(ucstring(""));
4395 if (_Mode
== EditionMode
)
4397 _CurrentTool
= new CToolSelectMove
;
4401 _CurrentTool
= NULL
;
4402 ContextCur
.release();
4403 ::initContextualCursor();
4404 ContextCur
.context("STAND BY");
4405 CTool::setMouseCursor(DEFAULT_CURSOR
);
4410 _CurrentTool
= tool
;
4414 _CurrentTool
->onActivate();
4417 CLuaStackChecker
lsc(&getLua());
4418 // activate tool in the ui
4419 getLua().push(_CurrentTool
? _CurrentTool
->getToolUIName() : "");
4420 getEnv()["ToolUI"].callMethodByNameNoThrow("setActiveToolUIByName", 1, 0);
4424 // *********************************************************************************************************
4425 CLuaObject
CEditor::getClasses()
4427 //H_AUTO(R2_getClasses_throw)
4429 return getEnv().at("Classes");
4433 // *********************************************************************************************************
4434 bool CEditor::callEnvFunc(const char *funcName
, int numArgs
, int numRet
/*=0*/)
4436 //H_AUTO(R2_CEditor_callEnvFunc)
4438 static volatile bool dumpStackWanted
= false;
4439 if (dumpStackWanted
) getLua().dumpStack();
4441 nlassert(getLua().getTop() >= numArgs
);
4442 int initialStackSize
= getLua().getTop();
4444 if (dumpStackWanted
) getLua().dumpStack();
4445 getLua().insert(-1 - numArgs
); // put the table before the args
4446 if (dumpStackWanted
) getLua().dumpStack();
4447 int result
= getLua().pcallByName(funcName
, numArgs
, numRet
, -1 - numArgs
);
4448 if (dumpStackWanted
) getLua().dumpStack();
4451 nlwarning("Error while calling function %s : %s", funcName
, getLua().toString());
4452 getLua().setTop(initialStackSize
- numArgs
+ numRet
); // clean the stack
4455 // remove the R2 table from the stack
4456 int newSize
= getLua().getTop();
4457 if (dumpStackWanted
) getLua().dumpStack();
4458 nlassert(newSize
== initialStackSize
+ 1 - numArgs
+ numRet
); // -1 is because of the r2 table
4459 if (dumpStackWanted
) getLua().dumpStack();
4460 getLua().remove(- numRet
- 1); // remove the 'R2' table
4461 if (dumpStackWanted
) getLua().dumpStack();
4462 return true; // results remains on the stack
4465 // *********************************************************************************************************
4466 bool CEditor::callEnvMethod(const char *funcName
, int numArgs
, int numRet
/*= 0*/)
4468 //H_AUTO(R2_CEditor_callEnvMethod)
4471 nlassert(getLua().getTop() >= numArgs
);
4473 getLua().insert(-1 - numArgs
); // put the table before the args (self parameter)
4474 return callEnvFunc(funcName
, numArgs
+ 1, numRet
);
4477 // *********************************************************************************************************
4478 bool CEditor::doLuaScript(const char *filename
, const char *fileDescText
)
4480 //H_AUTO(R2_CEditor_doLuaScript)
4482 CVerboseClock
clock("parsing of " + std::string(filename
));
4483 // load the classes definition file
4484 std::string filePath
= NLMISC::CPath::lookup(filename
, false, true);
4485 if (filePath
.empty())
4487 nlwarning("Can't find %s : %s", fileDescText
, filename
);
4491 if( 0 && FINAL_VERSION
== 1) // disabled for the moment because there are lua file that must be loaded from example
4493 const static std::string path
= "data_common.bnp@";
4494 const static std::string::size_type len
= path
.size();
4496 if (filePath
.size() < len
|| filePath
.substr(0, len
) != path
)
4498 nlwarning("Can't find %s : %s in ('%s')", fileDescText
, filename
, path
.c_str());
4506 if (!getLua().executeFile(filePath
))
4508 nlwarning("Couldn't open file %s : %s for R2 is not loaded", filename
, fileDescText
);
4510 CLuaStackChecker
ls(&getLua());
4513 catch(const NLMISC::EStream
&e
)
4515 nlwarning("Error while loading R2 %s (file = %s) : %s", fileDescText
, filename
, e
.what());
4517 catch(const ELuaError
&e
)
4519 //char filename[MAX_PATH];
4520 std::string msg
= e
.what();
4521 if (testWildCard(msg
, "*.lua:*:*")) // TODO nico : more accurate testing for filename format
4523 std::string::size_type extPos
= msg
.find(".lua");
4524 nlassert(extPos
!= std::string::npos
);
4525 std::string filename
= msg
.substr(0, extPos
+ 4); // extract filename including extension
4527 fromString(&*(msg
.begin() + extPos
+ 5), line
); // line number follows
4528 nlwarning((CLuaIHMRyzom::createGotoFileButtonTag(filename
.c_str(), line
) + e
.what()).c_str());
4532 // no filename / line in the result, so maybe the parse error was in an 'inline' script
4533 nlwarning("Error in R2 %s (file = %s) : %s", fileDescText
, filename
, e
.what());
4542 ///////////////////////
4543 // CONTEXTUAL CURSOR //
4544 ///////////////////////
4548 // *********************************************************************************************************
4549 void CEditor::checkCursor()
4551 //H_AUTO(R2_CEditor_checkCursor)
4553 // no-op there : we delegate management of mouse to the CTool derived classes
4557 // *********************************************************************************************************
4558 void CEditor::mouseClick(bool rightButton
, bool /* dblClick */)
4560 //H_AUTO(R2_CEditor_mouseClick)
4562 CTool
*currentTool
= getEditor().getCurrentTool();
4563 if (!currentTool
) return;
4566 // nb : result not handled there (no defaut action for left click)
4567 currentTool
->onMouseLeftButtonClicked();
4571 bool handled
= currentTool
->onMouseRightButtonClicked();
4574 getEditor().displayContextMenu();
4581 // *********************************************************************************************************
4582 void CEditor::updatePreCamera()
4584 //H_AUTO(R2_CEditor_updatePreCamera)
4586 if (_Mode
== EditionMode
)
4588 static uint32 loop
= 0;
4590 if (loop
% 200 == 0) // minimal wait between to save = 20 seconds
4592 if ( (CTime::getLocalTime() -_LastAutoSaveTime
)/1000 > ClientCfg
.R2EDAutoSaveWait
) // 5 minutes if not change in Confile
4598 // if there's no pending action, then start a new one at each frame
4599 if (!_DMC
->getActionHistoric().isPendingActionInProgress())
4601 _DMC
->newAction(CI18N::get("uiR2EDUnamedAction"));
4605 _DMC
->getActionHistoric().flushPendingAction();
4610 // *********************************************************************************************************
4611 void CEditor::updatePrimitiveContextualVisibility()
4613 //H_AUTO(R2_CEditor_updatePrimitiveContextualVisibility)
4614 if (!_SelectedInstance
) return;
4615 // if selected instance remains in last contextual prim list, then they may remain visible
4617 for(uint k
= 0; k
< _LastContextualPrims
.size(); ++k
)
4619 if (_LastContextualPrims
[k
] == _SelectedInstance
||
4620 _SelectedInstance
->isSonOf(_LastContextualPrims
[k
])
4627 _LastContextualPrims
.clear();
4628 bool isLogicEntity
= _SelectedInstance
->isKindOf("LogicEntity");
4629 if (!ok
&& !isLogicEntity
) return;
4632 _LastContextualLogicEntity
= _SelectedInstance
;
4634 if (!_LastContextualLogicEntity
) return;
4636 CObject
*seq
= _LastContextualLogicEntity
->getGroupSelectedSequence();
4640 CObjectTable
*activities
= seq
->toTable("Components");
4643 // get first world object parent to get start position
4644 for(uint k
= 0; k
< activities
->getSize(); ++k
)
4646 // search next zone of activity
4647 CObjectTable
*activity
= activities
->getValueAtPos(k
)->toTable();
4648 if (!activity
) continue;
4649 std::string zoneId
= getString(activity
, "ActivityZoneId");
4650 CInstance
*primitive
= getInstanceFromId(zoneId
);
4653 CDisplayerVisualGroup
*primDisp
= dynamic_cast<CDisplayerVisualGroup
*>(primitive
->getDisplayerVisual());
4656 _LastContextualPrims
.push_back(primitive
);
4657 primDisp
->setContextualVisibilityDate(T1
);
4665 // *********************************************************************************************************
4666 CEntitySorter
*CEditor::getEntitySorter() const
4668 return _EntitySorter
;
4672 // *********************************************************************************************************
4673 void CEditor::updateBeforeRender()
4675 //H_AUTO(R2_CEditor_updateBeforeRender)
4678 _IslandCollision
.updateCurrPackedIsland();
4679 // update contextual visibility of primitive from current selection
4680 updatePrimitiveContextualVisibility();
4682 if (ConnectionWanted
) return; // TMP special case for connection
4685 _CurrentTool
->updateBeforeRender();
4687 for(TInstanceMap::iterator it
= _Instances
.begin(); it
!= _Instances
.end(); ++it
)
4689 if (it
->second
->getDisplayerVisual())
4691 it
->second
->getDisplayerVisual()->onPreRender();
4694 updateSelectingDecals();
4695 // hide or show user depending on the mode
4698 if (_Mode
== EditionMode
|| isDMing())
4700 updateDecalBlendRegion(_PionneerDecal
, UserEntity
->pos());
4701 showDecal(CVector2f((float) UserEntity
->pos().x
, (float) UserEntity
->pos().y
), 1.f
, _PionneerDecal
, _PionneerDecalAnim
);
4704 if ((_SelectedInstance
&& _SelectedInstance
->maxVisibleEntityExceeded()) ||
4705 (_FocusedInstance
&& _FocusedInstance
->maxVisibleEntityExceeded()))
4707 setMaxVisibleEntityExceededFlag(true);
4711 setMaxVisibleEntityExceededFlag(false);
4715 // *********************************************************************************************************
4716 void CEditor::updateDecalBlendRegion(CDecal
&decal
, const NLMISC::CVector
&pos
)
4718 //H_AUTO(R2_CEditor_updateDecalBlendRegion)
4719 float topBlendDist
= CV_DecalTopBlendStartDist
.get();
4720 float bottomBlendDist
= CV_DecalBottomBlendStartDist
.get();
4721 float blendLength
= CV_DecalBlendLength
.get();
4722 decal
.setBottomBlend(pos
.z
- bottomBlendDist
- blendLength
,
4723 pos
.z
- bottomBlendDist
);
4724 decal
.setTopBlend(pos
.z
+ topBlendDist
,
4725 pos
.z
+ topBlendDist
+ blendLength
);
4728 // *********************************************************************************************************
4729 void CEditor::updateBeforeSwapBuffer()
4731 //H_AUTO(R2_CEditor_updateBeforeSwapBuffer)
4733 if (_WaitScenarioScreenWanted
)
4736 _WaitScenarioScreenWanted
= false;
4740 // *********************************************************************************************************
4741 void CEditor::waitScenario()
4743 //H_AUTO(R2_CEditor_waitScenario)
4744 _EditionModeDisconnectedFlag
= false;
4745 _WaitScenarioScreenActive
= true;
4746 waitScenarioScreen();
4747 _WaitScenarioScreenActive
= false;
4750 if (_PostponeScenarioUpdated
)
4752 scenarioUpdated(_NewScenario
, false, _NewScenarioInitialAct
);
4753 _PostponeScenarioUpdated
= false;
4754 _NewScenario
= NULL
;
4760 // *********************************************************************************************************
4761 void CEditor::updateAfterRender()
4763 if (_EntitySorter
) _EntitySorter
->clipEntitiesByDist();
4764 //H_AUTO(R2_CEditor_updateAfterRender)
4765 _IslandCollision
.updateCurrPackedIsland();
4767 if (ConnectionWanted
)
4775 _CurrentTool
->updateAfterRender();
4777 if (!_LuaUIMainLoop
.isNil())
4779 _LuaUIMainLoop
.callMethodByNameNoThrow("onPostSceneRender", 0, 0);
4782 for(TInstanceMap::iterator it
= _Instances
.begin(); it
!= _Instances
.end(); ++it
)
4784 if (it
->second
->getDisplayerVisual())
4786 it
->second
->getDisplayerVisual()->onPostRender();
4795 // *********************************************************************************************************
4796 void CEditor::autoSave()
4798 //H_AUTO(R2_CEditor_autoSave)
4802 _LastAutoSaveTime
= NLMISC::CTime::getLocalTime();
4803 uint32 maxAutoSave
= ClientCfg
.R2EDAutoSaveSlot
;
4805 std::string lastFile
= toString("autosave_%u", maxAutoSave
);
4808 uint32 i
= maxAutoSave
-1;
4810 for ( ; i
!= 0 ; --i
)
4812 std::string current
= NLMISC::toString("autosave_%02u.r2", i
);
4813 std::string next
= NLMISC::toString("autosave_%02u.r2", i
+1);
4815 if (CFile::fileExists(current
))
4817 if (CFile::fileExists(next
)) // true only for i = maxAutoSave -1
4819 CFile::deleteFile(next
);
4821 CFile::moveFile(next
, current
);
4825 if (CFile::fileExists("save/r2_buffer.dat"))
4827 CFile::copyFile("autosave_01.r2", "save/r2_buffer.dat");
4830 R2::getEditor().getLua().executeScriptNoThrow("r2.Version.save(\"save/r2_buffer.dat\")");
4835 // *********************************************************************************************************
4836 bool CEditor::handleEvent (const NLGUI::CEventDescriptor
&eventDesc
)
4838 //H_AUTO(R2_CEditor_handleEvent )
4840 if (ConnectionWanted
|| !_CurrentTool
) return false; // TMP special case for connection
4841 if (eventDesc
.getType() == NLGUI::CEventDescriptor::system
)
4843 const NLGUI::CEventDescriptorSystem
&eds
= (const NLGUI::CEventDescriptorSystem
&) eventDesc
;
4844 if (eds
.getEventTypeExtended() == NLGUI::CEventDescriptorSystem::setfocus
)
4846 const NLGUI::CEventDescriptorSetFocus
&edsf
= (const NLGUI::CEventDescriptorSetFocus
&) eds
;
4847 if (edsf
.hasFocus() == false)
4849 // cancel current tool
4850 setCurrentTool(NULL
);
4857 return _CurrentTool
->handleEvent(eventDesc
);
4862 // *********************************************************************************************************
4863 void CEditor::copy()
4865 //H_AUTO(R2_CEditor_copy)
4867 callEnvMethod("copy", 0);
4870 // *********************************************************************************************************
4871 void CEditor::paste()
4873 //H_AUTO(R2_CEditor_paste)
4875 callEnvMethod("paste", 0);
4878 // *********************************************************************************************************
4880 void CEditor::updateEvents()
4882 if (!_CurrentTool) return;
4884 if(EventsListener.isMouseButtonPushed(leftButton))
4886 nlwarning("onMouseLeftButtonDown");
4887 _CurrentTool->onMouseLeftButtonDown();
4889 if(EventsListener.isMouseButtonReleased(leftButton))
4891 nlwarning("isMouseButtonReleased");
4892 _CurrentTool->onMouseLeftButtonUp();
4894 if(EventsListener.isMouseButtonPushed(rightButton))
4896 nlwarning("isMouseButtonPushed");
4897 _CurrentTool->onMouseRightButtonDown();
4899 if(EventsListener.isMouseButtonReleased(rightButton))
4901 nlwarning("onMouseRightButtonUp");
4902 _CurrentTool->onMouseRightButtonUp();
4906 // *********************************************************************************************************
4907 CEntityCL
*CEditor::createEntity(uint slot
, const NLMISC::CSheetId
&sheetId
, const NLMISC::CVector
&pos
, float heading
, const std::string
& permanentStatutIcon
)
4909 //H_AUTO(R2_CEditor_createEntity)
4911 if (sheetId
== NLMISC::CSheetId::Unknown
) return NULL
;
4912 CInterfaceManager
*im
= CInterfaceManager::getInstance();
4914 if (EntitiesMngr
.entity(slot
))
4916 EntitiesMngr
.remove(slot
, false);
4918 // Create the temporary entity in the entity manager
4919 TNewEntityInfo emptyEntityInfo
;
4920 emptyEntityInfo
.reset();
4921 CEntityCL
*entity
= EntitiesMngr
.create(slot
, sheetId
.asInt(), emptyEntityInfo
);
4924 nlwarning("Can't create entity");
4928 // Set the permanent statut icon
4929 entity
->setPermanentStatutIcon(permanentStatutIcon
);
4931 // TMP TMP : code taken from /entity command
4933 CCDBNodeLeaf
*node
= 0;
4934 // Set The property 'CLFECOMMON::PROPERTY_POSITION'.
4935 node
= NLGUI::CDBManager::getInstance()->getDbProp("SERVER:Entities:E" + NLMISC::toString("%d", slot
)+":P" + NLMISC::toString("%d", CLFECOMMON::PROPERTY_POSX
), false);
4938 sint64 x
= (sint64
)(pos
.x
*1000.0);
4939 sint64 y
= (sint64
)(pos
.y
*1000.0);
4940 sint64 z
= (sint64
)(pos
.z
*1000.0);
4941 node
->setValue64(x
);
4942 node
= NLGUI::CDBManager::getInstance()->getDbProp("SERVER:Entities:E"+toString("%d", slot
)+":P"+toString("%d", CLFECOMMON::PROPERTY_POSY
), false);
4945 node
->setValue64(y
);
4946 node
= NLGUI::CDBManager::getInstance()->getDbProp("SERVER:Entities:E"+toString("%d", slot
)+":P"+toString("%d", CLFECOMMON::PROPERTY_POSZ
), false);
4948 node
->setValue64(z
);
4951 // Set The property 'PROPERTY_ORIENTATION'.
4952 node
= NLGUI::CDBManager::getInstance()->getDbProp("SERVER:Entities:E"+toString("%d", slot
)+":P"+toString("%d", CLFECOMMON::PROPERTY_ORIENTATION
), false);
4956 parts
.f
[0] = heading
;
4958 node
->setValue64(parts
.i64
[0]);
4961 node
= NLGUI::CDBManager::getInstance()->getDbProp("SERVER:Entities:E"+toString("%d", slot
)+":P"+toString("%d", CLFECOMMON::PROPERTY_MODE
), false);
4964 node
->setValue64((sint64
)MBEHAV::NORMAL
);
4965 EntitiesMngr
.updateVisualProperty(0, slot
, CLFECOMMON::PROPERTY_MODE
);
4968 // Set Visual Properties
4969 SPropVisualA visualA
;
4970 //visualA.PropertySubData.LTrail = 1;
4972 // Set alternate look
4973 SAltLookProp altLookProp
;
4975 // fill infos for look
4976 prop
= (sint64
*)&visualA
;
4978 if(dynamic_cast<CPlayerCL
*>(entity
))
4980 // visual property A depends on the type of the entity
4981 visualA
.PropertySubData
.Sex
= ClientCfg
.Sex
;
4983 else if(dynamic_cast<CPlayerR2CL
*>(entity
) == NULL
)
4985 // Get the database entry.
4986 // Get the old value (not useful since we change the whole property).
4987 altLookProp
.Summary
= 0;
4988 altLookProp
.Element
.ColorTop
= 0;
4989 altLookProp
.Element
.ColorBot
= 2;
4990 altLookProp
.Element
.WeaponRightHand
= 0;
4991 altLookProp
.Element
.WeaponLeftHand
= 0;
4992 altLookProp
.Element
.Seed
= 100;
4993 altLookProp
.Element
.ColorHair
= 4;
4994 altLookProp
.Element
.Hat
= 0;
4996 altLookProp
.Element
.ColorGlove
= altLookProp
.Element
.ColorTop
;
4997 altLookProp
.Element
.ColorArm
= altLookProp
.Element
.ColorTop
;
4998 altLookProp
.Element
.ColorBoot
= altLookProp
.Element
.ColorBot
;
5000 // fill alt infos for look
5001 prop
= (sint64
*)&altLookProp
.Summary
;
5004 // Set the database.
5005 NLGUI::CDBManager::getInstance()->getDbProp("SERVER:Entities:E"+toString("%d", slot
)+":P"+toString("%d", CLFECOMMON::PROPERTY_VPA
))->setValue64(*prop
);
5007 // Set Visual Properties
5008 SPropVisualB visualB
;
5009 visualB
.PropertySubData
.LTrail
= 1;
5010 // fill infos for look
5012 propB
= (sint64
*)&visualB
;
5013 // Set the database.
5014 NLGUI::CDBManager::getInstance()->getDbProp("SERVER:Entities:E"+toString("%d", slot
)+":P"+toString("%d", CLFECOMMON::PROPERTY_VPB
))->setValue64(*propB
);
5017 EntitiesMngr
.updateVisualProperty(0, slot
, CLFECOMMON::PROPERTY_VPA
);
5018 EntitiesMngr
.updateVisualProperty(0, slot
, CLFECOMMON::PROPERTY_VPB
);
5023 // *********************************************************************************************************
5024 CInstance
*CEditor::getInstanceFromEntity(CEntityCL
*entity
) const
5026 //H_AUTO(R2_CEditor_getInstanceFromEntity)
5028 for(TInstanceMap::const_iterator it
= _Instances
.begin(); it
!= _Instances
.end(); ++it
)
5030 if (it
->second
->getEntity() == entity
) return it
->second
;
5035 // *********************************************************************************************************
5036 void CEditor::displayContextMenu()
5038 //H_AUTO(R2_CEditor_displayContextMenu)
5040 if (!_SelectedInstance
)
5042 // launch standard context menu (for free look & move options)
5043 getUI().launchContextMenuInGame("ui:interface:game_context_menu_edition");
5046 if (getCurrentTool() && getCurrentTool()->isCreationTool())
5048 setCurrentTool(NULL
);
5050 // retrieve the context menu depending on the type of the entity
5051 CLuaObject classDesc
= _SelectedInstance
->getClass();
5052 if (classDesc
.isNil())
5054 nlwarning("Can't retrieve object class");
5057 std::string menu
= classDesc
["Menu"];
5058 if (menu
.empty()) return; // no menu for that instance ?
5060 CLuaObject menuSetupFunction
= classDesc
["onSetupMenu"];
5061 if (menuSetupFunction
.isFunction())
5063 _SelectedInstance
->getLuaProjection().push();
5064 menuSetupFunction
.callNoThrow(1, 0);
5067 getUI().launchContextMenuInGame(menu
);
5072 // *********************************************************************************************************
5073 void CEditor::triggerInstanceObserver(const TInstanceId
&id
, IObserverAction
&action
)
5075 //H_AUTO(R2_CEditor_triggerInstanceObserver)
5076 TInstanceObserverMap::iterator lb
= _InstanceObservers
.lower_bound(id
);
5077 TInstanceObserverMap::iterator ub
= _InstanceObservers
.upper_bound(id
);
5078 if (lb
== ub
) return;
5079 // must do a copy, because an observer may erase himself from the list when it is triggered
5080 static std::vector
<IInstanceObserver::TRefPtr
> dest
;
5082 for (TInstanceObserverMap::iterator it
= lb
; it
!= ub
; ++it
)
5084 dest
.push_back(it
->second
);
5086 for (std::vector
<IInstanceObserver::TRefPtr
>::iterator it
= dest
.begin(); it
!= dest
.end(); ++it
)
5088 if (*it
) action
.doAction(**it
);
5092 // *********************************************************************************************************
5093 void CEditor::onErase(CObject
*object
)
5095 //H_AUTO(R2_CEditor_onErase)
5096 bool dummyFoundInBase
;
5097 std::string dummyNameInParent
;
5098 onErase(object
, dummyFoundInBase
, dummyNameInParent
);
5101 // *********************************************************************************************************
5102 void CEditor::onErase(CObject
*root
, bool &foundInBase
, std::string
&nameInParent
)
5104 //H_AUTO(R2_CEditor_onErase)
5105 foundInBase
= false;
5108 CInstance
*inst
= getInstanceFromObject(root
);
5110 if (root
->isTable())
5112 for(uint k
= 0; k
< root
->getSize(); ++k
)
5114 CObject
*obj
= root
->getValueAtPos(k
);
5122 CObject
*parent
= NULL
;
5126 // Add an 'Erased' flag to the object so that
5127 // any pending property in the property sheet
5128 // won't send a 'requestSetNode' when it is closed
5131 (*inst
).getLuaProjection()["User"].setValue("Erased", true);
5133 catch (const ELuaNotATable
&e
)
5135 nlwarning(e
.what());
5138 // if object is selected or focused, then clear these flags
5139 if (inst
== getSelectedInstance())
5141 setSelectedInstance(NULL
);
5143 if (inst
== getFocusedInstance())
5145 setFocusedInstance(NULL
);
5149 // if object can be found in its base, then not really a deletion, but
5150 // rather a change of attribute to the "default value' (may happen in an undo operation)
5151 parent
= root
->getParent();
5154 sint32 sonIndex
= parent
->findIndex(root
);
5157 nameInParent
= parent
->getKey(sonIndex
);
5158 if (!nameInParent
.empty() && getDMC().getPropertyAccessor().hasValueInBase(parent
, nameInParent
))
5165 if (inst
&& !foundInBase
)
5167 // send event to instance & displayers
5169 // trigger observers
5170 class CEraseNotification
: public IObserverAction
5173 CEraseNotification(CInstance
&instance
) : Instance(instance
) {}
5174 virtual void doAction(IInstanceObserver
&obs
)
5176 obs
.onInstanceErased(Instance
);
5178 CInstance
&Instance
;
5180 CEraseNotification
eraseNotification(*inst
);
5181 triggerInstanceObserver(inst
->getId(), eraseNotification
);
5184 // if object has a user environment attached to it, remove it from lua
5187 CLuaStackChecker
lsc(&getLua());
5188 getLua().pushLightUserData((void *) root
);
5189 getLua().getTable(LUA_REGISTRYINDEX
);
5190 if (!getLua().isNil())
5192 getLua().pushLightUserData((void *) root
); // key
5193 getLua().pushNil(); // value
5194 getLua().setTable(LUA_REGISTRYINDEX
); // erase
5199 if (root
->isTable())
5201 // special patch: ref ids under this object should not be triggered any more for that object
5202 CObjectTable
*rootTable
= root
->toTable();
5203 for (uint32 k
= 0; k
< rootTable
->getSize(); ++k
)
5205 CObject
*obj
= rootTable
->getValueAtPos(k
);
5206 CObjectRefIdClient
*objRefId
= dynamic_cast<CObjectRefIdClient
*>(obj
);
5209 objRefId
->enable(false); // don't observe anything
5214 if (!_ClearingContent
)
5218 nlassert(_Instances
.count((const CObjectTable
*) root
) == 1);
5219 //nlwarning("Instance with id %s deleted, but not inserted", inst->getId().c_str());
5222 // really remove object
5223 //nlwarning("Removing instance with id %s (table = 0x%s)", inst->getId().c_str(), (int) root);
5226 _Instances
.erase((const CObjectTable
*) root
);
5231 // *********************************************************************************************************
5232 void CEditor::nodeErased(const std::string
& instanceId
, const std::string
& attrName
, sint32 position
)
5234 //H_AUTO(R2_CEditor_nodeErased)
5236 CObject
*obj
= _DMC
->find(instanceId
, attrName
, position
);
5239 std::string nameInParent
;
5240 onErase(obj
, foundInBase
, nameInParent
);
5241 CObject
*parent
= obj
->getParent();
5242 _DMC
->CDynamicMapClient::nodeErased(instanceId
, attrName
, position
);
5246 // erased, but reading in the base will give a new value, so the real
5247 // action from observers standpoint is 'modified'
5248 CInstance
*parentInstance
= getInstanceFromObject(parent
);
5251 onAttrModified(*parentInstance
, nameInParent
);
5255 nlwarning("Can't found instance in which %s was modified", nameInParent
.c_str());
5258 // warn the parent that it has been modified
5259 onAttrModified(parent
);
5260 // NB : msg for deleted attribute does not exist yet, so the parent is warned that it is modified, but
5261 // 'onTableModified' is not called (because key doesn't exist any more)
5265 void CEditor::onResetEditionMode()
5267 //H_AUTO(R2_CEditor_onResetEditionMode)
5269 // called when a scenario just before a scenario is created
5273 void CEditor::onEditionModeConnected( uint32 userSlotId
, uint32 adventureId
, CObject
* highLevel
, const std::string
& versionName
, bool willTP
, uint32 initialActIndex
)
5275 //H_AUTO(R2_CEditor_onEditionModeConnected)
5277 if (!_WaitScenarioScreenActive
)
5279 setMode(EditionMode
);
5281 CInterfaceGroup
*currentSessionGroup
= dynamic_cast<CInterfaceGroup
*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:r2ed_current_session"));
5282 if (currentSessionGroup
)
5284 CViewText
*text
= dynamic_cast<CViewText
*>(currentSessionGroup
->getView("current_session"));
5287 text
->setText(toString("Edition Session = %d (%s)", adventureId
, versionName
.c_str()));
5290 setDefaultChatWindow(PeopleInterraction
.ChatGroup
.Window
);
5291 _DMC
->CDynamicMapClient::onEditionModeConnected(userSlotId
, adventureId
, highLevel
, versionName
, willTP
, initialActIndex
);
5294 void CEditor::setAccessMode(TAccessMode mode
)
5296 //H_AUTO(R2_CEditor_setAccessMode)
5300 case AccessEditor
: _Env
.setValue("AccessMode", "Editor"); break;
5302 _Env
.setValue("AccessMode", "DM");
5303 if (_Mode
== AnimationModePlay
)
5308 case AccessOutlandOwner
: _Env
.setValue("AccessMode", "OutlandOwner"); break;
5315 void CEditor::onAnimationModeConnected(const CClientMessageAdventureUserConnection
& connected
)
5317 //H_AUTO(R2_CEditor_onAnimationModeConnected)
5318 _ScenarioReceivedFlag
= true; // end wait screen
5322 switch(connected
.Mode
)
5324 case 0: setMode(AnimationModeLoading
); break;
5325 case 1: setMode(AnimationModeWaitingForLoading
); break;
5326 case 2: setMode(AnimationModeDm
); break;
5327 case 3: setMode(AnimationModePlay
); break;
5328 default: nlwarning("Unhandled %u in Animation Session", connected
.Mode
);
5332 CInterfaceGroup
*currentSessionGroup
= dynamic_cast<CInterfaceGroup
*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:r2ed_current_session"));
5333 if (currentSessionGroup
)
5335 CViewText
*text
= dynamic_cast<CViewText
*>(currentSessionGroup
->getView("current_session"));
5338 text
->setText(toString("Animation Session = %d (%s)", connected
.SessionId
.asInt(), connected
.VersionName
.c_str()));
5341 setDefaultChatWindow(PeopleInterraction
.ChatGroup
.Window
);
5342 _DMC
->CDynamicMapClient::onAnimationModeConnected(connected
);
5345 void CEditor::onEditionModeDisconnected()
5347 //H_AUTO(R2_CEditor_onEditionModeDisconnected)
5348 _EditionModeDisconnectedFlag
= true;
5349 delete _NewScenario
;
5350 _NewScenario
= NULL
;
5352 // Useful only for the pionner that does not do requestTranslateFeatures()
5353 // Because avec using the button the currentScenario = 0
5356 R2::getEditor().getLua().executeScript("r2.Version.save(\"save/r2_buffer.dat\")");
5358 catch (const std::exception
& e
)
5360 nlwarning("Can't start Edition Mode", e
.what());
5362 _DMC
->CDynamicMapClient::onEditionModeDisconnected();
5365 void CEditor::onTestModeConnected()
5367 //H_AUTO(R2_CEditor_onTestModeConnected)
5369 // TODO nico : change the name of the function : should rather be 'onAnimationModeConnected'
5371 CAHManager::getInstance()->runActionHandler("r2ed_anim_dm_mode", NULL
, "");
5372 _DMC
->CDynamicMapClient::onTestModeConnected();
5375 void CEditor::onTestModeDisconnected(TSessionId sessionId
, uint32 lastAct
, TScenarioSessionType sessionType
)
5377 //H_AUTO(R2_CEditor_onTestModeDisconnected)
5379 _DMC
->CDynamicMapClient::onTestModeDisconnected(sessionId
, lastAct
, sessionType
);
5382 // *********************************************************************************************************
5383 void CEditor::nodeInserted(const std::string
& instanceId
, const std::string
& attrName
, sint32 position
, const std::string
& key
, CObject
* value
)
5385 //H_AUTO(R2_CEditor_nodeInserted)
5387 _DMC
->CDynamicMapClient::nodeInserted(instanceId
, attrName
, position
, key
, value
);
5388 if (value
->isTable())
5390 std::string id
= getString(value
, "InstanceId");
5393 const CObject
*clonedValue
= _DMC
->find(id
);
5397 createNewInstanceForObjectTable(clonedValue
);
5399 onAttrModified(clonedValue
->getParent()); // parent table is modified
5400 // so -> only parent of parent table will be notified of change
5401 // maybe we need another msg "onInsert" that is sent
5402 // to the parent table.
5408 // *********************************************************************************************************
5409 void CEditor::createNewInstanceForObjectTable(const CObject
*obj
)
5411 //H_AUTO(R2_CEditor_createNewInstanceForObjectTable)
5413 createNewInstanceForObjectTableInternal(obj
);
5417 // *********************************************************************************************************
5418 void CEditor::notifyInstanceObserversOfCreation(CInstance
&inst
)
5420 //H_AUTO(R2_CEditor_notifyInstanceObserversOfCreation)
5422 // if there are observers watching this instance, warn them
5423 const std::string
&id
= inst
.getId();
5424 // trigger observers
5425 class CCreationNotification
: public IObserverAction
5428 CCreationNotification(CInstance
&instance
) : Instance(instance
) {}
5429 virtual void doAction(IInstanceObserver
&obs
)
5431 obs
.onInstanceCreated(Instance
);
5433 CInstance
&Instance
;
5435 CCreationNotification
creationNotification(inst
);
5436 triggerInstanceObserver(id
, creationNotification
);
5439 // *********************************************************************************************************
5440 void CEditor::onPostCreate(const CObject
*obj
)
5442 //H_AUTO(R2_CEditor_onPostCreate)
5444 struct CPostCreateVisitor
: public IObjectVisitor
5446 virtual void visit(CObjectTable
&obj
)
5448 // if table has a "InstanceId" field there is a matching editor object
5449 CInstance
*inst
= getEditor().getInstanceFromObject(&obj
);
5452 inst
->onPostCreate();
5453 getEditor().notifyInstanceObserversOfCreation(*inst
);
5459 CPostCreateVisitor postCreateVisitor
;
5460 const_cast<CObject
*>(obj
)->visit(postCreateVisitor
);
5464 // *********************************************************************************************************
5465 sint
CEditor::getLeftQuota()
5467 //H_AUTO(R2_CEditor_getLeftQuota)
5468 CLuaState
&ls
= getLua();
5469 CLuaStackChecker
lsc(&ls
);
5470 callEnvMethod("getLeftQuota", 0, 1);
5471 if (!ls
.isInteger(-1))
5476 sint result
= (sint
) ls
.toInteger(-1);
5481 // *********************************************************************************************************
5482 bool CEditor::checkRoomLeft()
5484 //H_AUTO(R2_CEditor_checkRoomLeft)
5485 return getLeftQuota() > 0;
5488 // *********************************************************************************************************
5489 void CEditor::makeRoomMsg()
5491 //H_AUTO(R2_CEditor_makeRoomMsg)
5492 // delegate ui display to lua
5493 callEnvMethod("makeRoomMsg", 0, 0);
5497 // *********************************************************************************************************
5498 bool CEditor::verifyRoomLeft(uint aiCost
, uint staticCost
)
5500 //H_AUTO(R2_CEditor_verifyRoomLeft)
5502 CLuaState
&ls
= getLua();
5505 CLuaStackChecker
lsc(&ls
);
5506 getEditor().getLua().push(aiCost
);
5507 callEnvMethod("checkAiQuota", 1, 1);
5508 if (!ls
.isBoolean(-1))
5513 sint result
= (sint
) ls
.toBoolean(-1);
5519 CLuaStackChecker
lsc(&ls
);
5520 getEditor().getLua().push(staticCost
);
5521 callEnvMethod("checkStaticQuota", 1, 1);
5522 if (!ls
.isBoolean(-1))
5527 sint result
= (sint
) ls
.toBoolean(-1);
5537 // *********************************************************************************************************
5538 void CEditor::createNewInstanceForObjectTableInternal(const CObject
*obj
)
5540 //H_AUTO(R2_CEditor_createNewInstanceForObjectTableInternal)
5543 if (!obj
->isTable()) return; // not a table ...
5544 const CObjectTable
*table
= (const CObjectTable
*) obj
;
5545 std::string id
= getString(obj
, "InstanceId");
5548 // CInstance is created only for objects with an instance id
5549 CInstance
*inst
= new CInstance(table
, getLua());
5550 nlassert(_Instances
.count(table
) == 0);
5551 _Instances
[table
] = inst
;
5552 // if a cookie was created, add in in the instance lua 'User' table
5553 TCookieMap::iterator cookieList
= _Cookies
.find(id
);
5554 if (cookieList
!= _Cookies
.end())
5558 CLuaState
&ls
= getLua();
5559 getLuaUserTableFromObject(ls
, * (CObjectTable
*) obj
);
5560 CLuaObject
userTable(ls
); // pop the table into a CLuaObject for convenience
5561 for (TCookieList::iterator it
= cookieList
->second
.begin(); it
!= cookieList
->second
.end(); ++it
)
5563 userTable
.setValue(it
->Key
, it
->Value
);
5566 _Cookies
.erase(cookieList
);
5568 // create displayers
5569 CLuaObject classDesc
= inst
->getClass();
5570 if (!classDesc
.isNil())
5572 CLuaStackChecker
lsc(&getLua());
5573 CDisplayerVisual
*dispViz
= createObjectFromClassName
<CDisplayerVisual
>(classDesc
["DisplayerVisual"].toString());
5576 bool ok
= dispViz
->init(classDesc
["DisplayerVisualParams"]);
5579 nlwarning("Error when calling init on visual displayer of class %s", classDesc
["Name"].toString().c_str());
5582 inst
->setDisplayerVisual(dispViz
);
5584 CDisplayerBase
*dispUI
= createObjectFromClassName
<CDisplayerBase
>(classDesc
["DisplayerUI"].toString());
5587 bool ok
= dispUI
->init(classDesc
["DisplayerUIParams"]);
5590 nlwarning("Error when calling init on ui displayer of class %s", classDesc
["Name"].toString().c_str());
5593 inst
->setDisplayerUI(dispUI
);
5595 CDisplayerBase
*dispProp
= createObjectFromClassName
<CDisplayerBase
>(classDesc
["DisplayerProperties"].toString());
5598 bool ok
= dispProp
->init(classDesc
["DisplayerPropertiesParams"]);
5601 nlwarning("Error when calling init on property displayer of class %s", classDesc
["Name"].toString().c_str());
5604 inst
->setDisplayerProperties(dispProp
);
5606 // prevent completion of the tree while an instance is being created
5607 //backupRequestCommands();
5609 //restoreRequestCommands();
5611 // if a name was generated locally, erase from the local name map.
5612 std::string className
= getString(obj
, "Class");
5613 std::string name
= getString(obj
, "Name");
5614 if (!className
.empty() && !name
.empty())
5616 for (TGeneratedNameMap::iterator it
= _LocalGeneratedNames
.begin(); it
!= _LocalGeneratedNames
.end(); ++it
)
5618 sint index
= getGeneratedNameIndex(name
, it
->first
);
5621 it
->second
.erase(index
);
5627 // do the same on sons
5628 for(uint k
= 0; k
< table
->getSize(); ++k
)
5630 createNewInstanceForObjectTableInternal(table
->getValueAtPos(k
));
5635 // *********************************************************************************************************
5636 void CEditor::onAttrModified(CInstance
&parentInstance
, const std::string
&attrName
, sint32 indexInArray
)
5638 //H_AUTO(R2_CEditor_onAttrModified)
5639 parentInstance
.onAttrModified(attrName
, indexInArray
);
5640 class CAttrModifiedNotification
: public IObserverAction
5643 CAttrModifiedNotification(CInstance
&instance
, const std::string
&key
, sint32 indexInArray
)
5644 : Instance(instance
), Key(key
), IndexInArray(indexInArray
) {}
5645 virtual void doAction(IInstanceObserver
&obs
)
5647 obs
.onAttrModified(Instance
, Key
, IndexInArray
);
5649 CInstance
&Instance
;
5650 const std::string
&Key
;
5651 sint32 IndexInArray
;
5653 CAttrModifiedNotification
attrModifiedNotification(parentInstance
, attrName
, indexInArray
);
5654 triggerInstanceObserver(parentInstance
.getId(), attrModifiedNotification
);
5657 // *********************************************************************************************************
5658 void CEditor::onAttrModified(const CObject
*value
)
5660 //H_AUTO(R2_CEditor_onAttrModified)
5663 const CObject
*son
= value
;
5664 const CObject
*parent
= value
->getParent();
5665 sint32 indexInArray
= -1;
5668 CInstance
*parentInstance
= getInstanceFromObject(parent
);
5669 sint32 indexInParent
= parent
->findIndex(son
);
5670 nlassert(indexInParent
!= -1);
5673 // we are in an instance (a CObjectTable with an instance id)
5674 // TODO nico : a cache for the 'name' in the parent like with CObjectRefId ...
5675 std::string key
= parent
->getKey(indexInParent
);
5676 onAttrModified(*parentInstance
, key
, indexInArray
);
5681 // we are in an array in an instance -> memorize index in that array for next call to "onAttrModified"...
5682 indexInArray
= indexInParent
;
5685 parent
= parent
->getParent();
5690 // *********************************************************************************************************
5691 void CEditor::nodeSet(const std::string
& instanceId
, const std::string
& attrName
, CObject
* value
)
5693 //H_AUTO(R2_CEditor_nodeSet)
5695 CObject
*obj
= _DMC
->find(instanceId
);
5697 // erase previous object
5698 nlassert(obj
->isTable());
5700 if (!attrName
.empty())
5702 obj
= obj
->findAttr(attrName
);
5708 // change the actual value
5709 _DMC
->CDynamicMapClient::nodeSet(instanceId
, attrName
, value
);
5711 nlassert(!getInstanceFromObject(value
)); // this must be a new object...
5714 if (value
->isTable())
5716 std::string id
= getString(value
, "InstanceId");
5719 const CObject
*clonedValue
= _DMC
->find(id
);
5722 createNewInstanceForObjectTable(clonedValue
); // if the created object is a table, warn him that he has been created
5723 onAttrModified(clonedValue
);
5728 // no instance id for object, retrieve object pointer from parent
5729 const CObject
*parent
= _DMC
->find(instanceId
);
5730 if (!parent
) return;
5731 onAttrModified(parent
->getAttr(attrName
));
5734 // *********************************************************************************************************
5735 void CEditor::eraseScenario()
5737 //H_AUTO(R2_CEditor_eraseScenario)
5741 backupRequestCommands();
5743 restoreRequestCommands();
5749 // *********************************************************************************************************
5750 void CEditor::scenarioUpdated(CObject
* highLevel
, bool willTP
, uint32 initialActIndex
)
5752 //H_AUTO(R2_CEditor_scenarioUpdated)
5754 _ScenarioReceivedFlag
= true;
5756 if (_WaitScenarioScreenActive
)
5758 // defer scenario update to the end of the wait screen
5759 nlassert(!_NewScenario
);
5760 _NewScenario
= highLevel
? highLevel
->clone() : NULL
;
5761 _NewScenarioInitialAct
= initialActIndex
;
5762 _PostponeScenarioUpdated
= true;
5768 _IsStartingScenario
= false;
5770 callEnvFunc("onEmptyScenarioUpdated", 0);
5774 // _WillTP = willTP;
5775 _WillTP
= false; // TMP TMP
5776 _UpdatingScenario
= true;
5781 CLuaStackRestorer
lsc(&getLua(), getLua().getTop());
5782 //nlwarning("Scenario updated, start highlevel = ");
5783 //highLevel->dump();
5787 _IsStartingScenario
= false;
5788 if (_DMC
->getEditionModule().getMustStartScenario())
5790 _IsStartingScenario
= true;
5794 nlassert(_Instances
.empty());
5795 nlassert(CDisplayerBase::ObjCount
== 0);
5797 _DMC
->CDynamicMapClient::scenarioUpdated(highLevel
, willTP
, initialActIndex
);
5798 //nlwarning("Scenario updated, content is = ");
5800 if (_DMC->getHighLevel())
5802 _DMC->getHighLevel()->dump();
5809 createNewInstanceForObjectTableInternal(_DMC
->getHighLevel());
5810 nlassert(highLevel
->isTable());
5811 _Scenario
= (CObjectTable
*) _DMC
->getHighLevel();
5812 if (_Scenario
->getAttr("InstanceId"))
5814 _ScenarioInstance
= getInstanceFromId(_Scenario
->getAttr("InstanceId")->toString());
5818 _ScenarioInstance
= NULL
;
5819 nlwarning("Can't retrieve scenario (no instance id)");
5823 static volatile bool forceDump
= false;
5829 projectInLua(_Scenario
); // push on the lua stack
5830 getLua().push(initialActIndex
); // example reconnect after test in act4
5831 // update value in the framework
5832 callEnvFunc("onScenarioUpdated", 2);
5833 //nlwarning("Instance list now is :");
5835 CObject
*acts
= _Scenario
->getAttr("Acts");
5838 CObject
*baseAct
= acts
->getValueAtPos(0);
5841 _BaseAct
= getInstanceFromId(baseAct
->toString("InstanceId"));
5846 nlwarning("Base act not found at scenario update");
5848 if (_WantedActOnInit
.empty())
5850 if (!_CurrentAct
) // if act not currently setted at scenario creation ...
5852 setCurrentAct(_BaseAct
); // ...then default to the base act
5857 setCurrentActFromTitle(_WantedActOnInit
);
5858 _WantedActOnInit
.clear();
5861 _DMC
->getActionHistoric().clear(highLevel
); // reinit the undo / redo stack
5862 onPostCreate(_Scenario
); // post creation require that current act has been set
5864 //TP is done via the onTpPositionSimulated message
5866 // teleport in good island
5867 if (ClientCfg.Local)
5869 sint locationId = (uint) _ScenarioInstance->getLuaProjection()["Description"]["LocationId"].toInteger();
5871 CScenarioEntryPoints &sep = CScenarioEntryPoints::getInstance();
5872 _IslandCollision.loadEntryPoints();
5873 if (sep.getCompleteIslands().empty())
5875 nlwarning("Entry points not loaded, teleport not done (local mode)");
5877 else if (locationId >= (sint) sep.getCompleteIslands().size())
5879 nlwarning("Bad location id %d", locationId);
5883 // check if already in this entry point (no tp if so)
5884 const CScenarioEntryPoints::CCompleteIsland &ci = sep.getCompleteIslands()[locationId];
5885 CVectorD playerPos = UserEntity->pos();
5887 if (playerPos.x <= ci.XMin ||
5888 playerPos.x >= ci.XMax ||
5889 playerPos.y <= ci.YMin ||
5890 playerPos.y >= ci.YMax)
5892 if(!ci.EntryPoints.empty())
5894 const CScenarioEntryPoints::CShortEntryPoint & shortEntryPoint = ci.EntryPoints[0];
5895 CVector dest((float) shortEntryPoint.X, (float) shortEntryPoint.Y, 0.f);
5897 UserEntity->pos(dest); // change position in pacs
5898 // Select the closest continent from the new position.
5899 beginLoading (LoadingBackground);
5900 #define BAR_STEP_TP 2 // fixme : this define is duplicated....
5901 ProgressBar.reset (BAR_STEP_TP);
5902 ucstring nmsg("Loading...");
5903 ProgressBar.newMessage ( ClientCfg.buildLoadingString(nmsg) );
5904 ProgressBar.progress(0);
5905 ContinentMngr.select(dest, ProgressBar);
5907 // Teleport the User.
5908 UserEntity->tp(dest);
5915 _UpdatingScenario
= false;
5918 if (_DMC
->getEditionModule().getMustStartScenario()
5919 && _DMC
->getEditionModule().getScenarioUpToDate())
5921 _DMC
->getEditionModule().setMustStartScenario( false);
5922 if ( _DMC
->getCurrentScenario()->getHighLevel())
5926 if (ClientCfg
.R2EDMustVerifyRingAccessWhileLoadingAnimation
)
5928 CLuaState
&ls
= getLua();
5929 CLuaStackChecker
lsc(&ls
);
5930 callEnvFunc( "verifyScenario", 0, 1);
5931 if (!ls
.isBoolean(-1))
5933 nlassert(0 && "verifyScenario return wrong type");
5935 result
= ls
.toBoolean(-1);
5939 if (result
) //Start scenario only if allowed
5941 ConnectionWanted
= true; // ugly
5947 // *********************************************************************************************************
5948 CInstance
*CEditor::getDefaultFeature(CInstance
*act
)
5950 //H_AUTO(R2_CEditor_getDefaultFeature)
5952 if (!act
) return NULL
;
5953 CObject
*defaultFeature
= act
->getObjectTable()->getAttr("Features");
5954 if (!defaultFeature
) return NULL
;
5955 defaultFeature
= defaultFeature
->getValueAtPos(0);
5956 if (!defaultFeature
) return NULL
; // 0 should be the default feature
5957 CInstance
*result
= getInstanceFromId(defaultFeature
->toString("InstanceId"));
5958 if (!result
) return NULL
;
5959 if (!result
->isKindOf("DefaultFeature"))
5961 nlwarning("Can't retrieve default feature.");
5966 // *********************************************************************************************************
5967 CInstance
*CEditor::getDefaultFeature()
5969 //H_AUTO(R2_CEditor_getDefaultFeature)
5971 return getDefaultFeature(getCurrentAct());
5974 // *********************************************************************************************************
5975 void CEditor::nodeMoved(const std::string
& instanceId
, const std::string
& attrName
, sint32 position
, const std::string
& destInstanceId
, const std::string
& destAttrName
, sint32 destPosition
)
5977 //H_AUTO(R2_CEditor_nodeMoved)
5979 const CObject
*src
= _DMC
->find(instanceId
, attrName
, position
);
5982 CObject
*oldParent
= src
->getParent();
5984 CInstance
*inst
= getInstanceFromObject(src
);
5985 // tells object that he is about to move
5988 inst
->onPreHrcMove();
5989 // notify possible observers that this instance will move
5990 class CPreHrcMoveNotification
: public IObserverAction
5993 CPreHrcMoveNotification(CInstance
&instance
) : Instance(instance
) {}
5994 virtual void doAction(IInstanceObserver
&obs
)
5996 obs
.onPreHrcMove(Instance
);
5998 CInstance
&Instance
;
6000 CPreHrcMoveNotification
preHrcMoveNotification(*inst
);
6001 triggerInstanceObserver(inst
->getId(), preHrcMoveNotification
);
6004 _DMC
->CDynamicMapClient::nodeMoved(instanceId
, attrName
, position
, destInstanceId
, destAttrName
, destPosition
);
6005 // warn the previous parent that it has been modified
6006 if (src
->getParent() != oldParent
)
6008 onAttrModified(oldParent
); // the old parent is modified so send appropriate msg
6010 // else ... if new parent is the same then send message only at the end (else object believe it has been modified twice in a row)
6011 // tells object that he has moved
6014 inst
->onPostHrcMove();
6015 // notify possible observers that this instance has moved
6016 class CPostHrcMoveNotification
: public IObserverAction
6019 CPostHrcMoveNotification(CInstance
&instance
) : Instance(instance
) {}
6020 virtual void doAction(IInstanceObserver
&obs
)
6022 obs
.onPostHrcMove(Instance
);
6024 CInstance
&Instance
;
6026 CPostHrcMoveNotification
postHrcMoveNotification(*inst
);
6027 triggerInstanceObserver(inst
->getId(), postHrcMoveNotification
);
6029 onAttrModified(src
); // the new parent is modified so send appropriate msg
6032 // *********************************************************************************************************
6033 void CEditor::dumpInstances()
6035 //H_AUTO(R2_CEditor_dumpInstances)
6037 for(TInstanceMap::iterator it
= _Instances
.begin(); it
!= _Instances
.end(); ++it
)
6039 nlwarning("Obj = %p, id = %s, instance = %p", it
->first
, it
->second
->getId().c_str(), &(*it
->second
));
6043 // ***************************************************************
6044 struct CSortSelectableObject
6046 ISelectableObject
*Object
;
6048 CVector RayStart
, RayStartClipped
, RayEndClipped
;
6049 NLMISC::CAABBox SelectBox
;
6050 bool SelectBoxInWorld
;
6051 bool operator<(const CSortSelectableObject
&o
) const
6053 return Depth
<o
.Depth
;
6056 // special selectable object to detect that mouse is over user
6057 class CSelectableUser
: public ISelectableObject
6060 virtual bool isSelectable() const { return true; }
6061 virtual bool getLastClip() const { return UserEntity
->getLastClip(); }
6062 virtual NLMISC::CAABBox
getSelectBox() const
6064 return UserEntity
->localSelectBox();
6066 virtual const NLMISC::CMatrix
&getInvertedMatrix() const
6068 static CMatrix invertedMatrix
;
6069 invertedMatrix
= UserEntity
->dirMatrix();
6070 invertedMatrix
.setPos(UserEntity
->pos());
6071 invertedMatrix
.invert();
6072 return invertedMatrix
;
6074 virtual float preciseIntersectionTest(const NLMISC::CVector
&worldRayStart
, const NLMISC::CVector
&worldRayDir
) const
6076 if (!UserEntity
) return FLT_MAX
;
6077 return CEditor::preciseEntityIntersectionTest(*UserEntity
, worldRayStart
, worldRayDir
);
6079 virtual CInstance
*getInstanceInEditor() const { return NULL
; }
6082 // ***************************************************************
6083 static CSelectableUser SelectableUser
;
6085 CInstance
*CEditor::getInstanceUnderPos(float x
, float y
, float distSelection
, bool &isPlayerUnderCursor
)
6087 static volatile bool ignore
= false;
6092 //H_AUTO(R2_CEditor_getInstanceUnderPos)
6094 // TODO nico: this code was copied from CEntityManager::getEntityUnderPos
6095 // then modified, so some factoring could be made ...
6101 // valid only if bbox still intersect
6102 CInstance
*precInstanceUnderPos
= _LastInstanceUnderPos
;
6103 bool precInstanceUnderPosValid
= false;
6107 isPlayerUnderCursor
= false;
6108 _LastInstanceUnderPos
= NULL
;
6112 CMatrix camMatrix
= MainCam
.getMatrix();
6113 NL3D::CFrustum camFrust
= MainCam
.getFrustum();
6114 NL3D::CViewport viewport
= Driver
->getViewport();
6116 // Get the Ray made by the mouse.
6117 CTool::CWorldViewRay worldViewRay
;
6118 worldViewRay
.OnMiniMap
= false;
6119 worldViewRay
.Valid
= true;
6121 viewport
.getRayWithPoint(x
, y
, worldViewRay
.Origin
, worldViewRay
.Dir
, camMatrix
, camFrust
);
6122 worldViewRay
.Dir
.normalize();
6123 worldViewRay
.Right
= camMatrix
.getI().normed();
6124 worldViewRay
.Up
= camMatrix
.getK().normed();
6127 // **** Get entities with box intersecting the ray.
6128 static std::vector
<ISelectableObject
*> validObjects
;
6129 validObjects
.clear();
6130 static std::vector
<CSortSelectableObject
> intersectedObjects
;
6131 intersectedObjects
.clear();
6134 ISelectableObject
*precSelectableObject
= NULL
;
6136 validObjects
.push_back(&SelectableUser
); // add fake object for test with user entity
6137 for(TInstanceMap::iterator it
= _Instances
.begin(); it
!= _Instances
.end(); ++it
)
6139 CInstance
*instance
= it
->second
;
6140 CDisplayerVisual
*vd
= instance
->getDisplayerVisual();
6142 if (!vd
->isSelectable()) continue;
6143 if (instance
== getEditor().getSelectedInstance())
6145 precSelectableObject
= vd
;
6147 validObjects
.push_back(vd
);
6150 // compute intersection of mouse with landscape / batiments for test with projected object like region & decals
6152 CTool::TRayIntersectionType rayInterType
= CTool::computeLandscapeRayIntersection(worldViewRay
, sceneInter
);
6154 CSortSelectableObject selectObj
;
6155 ISelectableObject
*borderSelected
= NULL
;
6156 for(uint k
= 0; k
< validObjects
.size(); ++k
)
6158 ISelectableObject
*object
= validObjects
[k
];
6159 // if entity not visible, skip
6160 if(object
->getLastClip())
6162 float depth
= FLT_MAX
;
6163 ISelectableObject::TSelectionType selectionType
= object
->getSelectionType();
6164 bool borderSelection
= false;
6165 switch(selectionType
)
6167 case ISelectableObject::GroundProjected
:
6168 if (rayInterType
!= CTool::NoIntersection
)
6170 CVector2f
testPos(sceneInter
.x
, sceneInter
.y
);
6171 borderSelection
= object
->isInProjectionBorder(testPos
);
6172 if (borderSelection
|| object
->isInProjection(testPos
))
6174 depth
= (worldViewRay
.Origin
- sceneInter
).norm();
6178 case ISelectableObject::LocalSelectBox
:
6179 case ISelectableObject::WorldSelectBox
:
6181 const CMatrix
&rayMatrix
= (selectionType
== ISelectableObject::LocalSelectBox
) ? object
->getInvertedMatrix()
6182 : CMatrix::Identity
;
6183 selectObj
.RayStart
= rayMatrix
* worldViewRay
.Origin
;
6184 selectObj
.RayStartClipped
= selectObj
.RayStart
;
6185 selectObj
.RayEndClipped
= rayMatrix
* (worldViewRay
.Origin
+ worldViewRay
.Dir
* distSelection
);
6186 // if intersect the bbox
6187 selectObj
.SelectBox
= object
->getSelectBox();
6188 selectObj
.SelectBoxInWorld
= false;
6189 if (selectObj
.SelectBox
.clipSegment(selectObj
.RayStartClipped
, selectObj
.RayEndClipped
))
6191 depth
= (selectObj
.RayStartClipped
- selectObj
.RayStart
).norm();
6192 // is it the last entity under pos?
6193 if(object
->getInstanceInEditor() ==precInstanceUnderPos
)
6194 precInstanceUnderPosValid
= true;
6205 if (depth
!= FLT_MAX
)
6207 selectObj
.Object
= object
;
6208 selectObj
.Depth
= depth
;
6209 if (borderSelection
)
6211 borderSelected
= object
;
6213 // add this entity to the list of possible entities
6214 intersectedObjects
.push_back(selectObj
);
6218 // if no intersected entities, quit
6219 if(intersectedObjects
.empty())
6222 // Compute startDistBox: nearest entity distance, but the user
6225 if(intersectedObjects
[0].Object
== &SelectableUser
)
6227 // if the nearest entity is the user, set res
6228 isPlayerUnderCursor
= true;
6229 // if only player intersected, return NULL!
6230 if(intersectedObjects
.size()==1)
6232 // so take the second for startDistBox
6233 startDistBox
= intersectedObjects
[1].Depth
;
6238 startDistBox
= intersectedObjects
[0].Depth
;
6243 /*static std::vector<ISelectableObject *> projectedObjects;
6244 projectedObjects.clear();*/
6246 // **** get best entity according to distance face-camera or box-ray if no face intersection
6247 ISelectableObject
*objectSelected
= NULL
;
6248 float bestDistBox
= FLT_MAX
;
6249 float bestDistZ
= FLT_MAX
;
6250 for(i
=0;i
<intersectedObjects
.size();i
++)
6252 ISelectableObject
*object
= intersectedObjects
[i
].Object
;
6254 // If this entity is the UserEntity, skip!!
6255 if(object
== &SelectableUser
)
6259 bool preciseInterFound
= false;
6260 ISelectableObject::TSelectionType selectionType
= object
->getSelectionType();
6261 switch(selectionType
)
6263 case ISelectableObject::GroundProjected
:
6265 // if current selection remains selected, keep it
6266 bool keepSelection
= objectSelected
&&
6267 objectSelected
->getSelectionType() == ISelectableObject::GroundProjected
&&
6268 objectSelected
== precSelectableObject
;
6271 preciseInterFound
= true;
6272 distZ
= intersectedObjects
[i
].Depth
;
6276 case ISelectableObject::LocalSelectBox
:
6277 case ISelectableObject::WorldSelectBox
:
6278 // if (!object->intersectionTest(bbox, pos, dir, dist2D, distZ, distSelection)) continue;
6279 distZ
= object
->preciseIntersectionTest(worldViewRay
.Origin
, worldViewRay
.Dir
);
6280 if (distZ
!= FLT_MAX
)
6282 preciseInterFound
= true;
6291 // *** if intersect face, then take the best face-intersection, else use box-ray cost
6292 // true face-col found?
6293 if(preciseInterFound
)
6295 // yes, get the nearest
6296 if(distZ
<=bestDistZ
)
6300 objectSelected
= object
;
6301 /*if (selectionType == ISelectableObject::GroundProjected)
6303 projectedObjects.push_back(object);
6310 // if a true face-intersection has not been found for others entities
6311 if(bestDistZ
==FLT_MAX
)
6313 // get the "distance to camera" contribution.
6314 // NB: ray & select box are in the same space (local or world)
6315 CVector c
= selectObj
.SelectBox
.getCenter();
6316 float distCamCost
= intersectedObjects
[i
].Depth
;
6317 // get relative to the nearest intersected entity
6318 distCamCost
-= startDistBox
;
6319 // take the middle of the clipped segment. suppose that this middle is the "nearest ray point to center"
6320 // This is false, but gives better results.
6321 CVector m
= (selectObj
.RayStartClipped
+ selectObj
.RayEndClipped
) / 2;
6322 // get the distance to center. NB: small entities are preferred since smaller mean lower cost
6323 float outBBoxCost
= (m
- c
).norm();
6325 // the final cost is a weighted sum of the both. NB: distCamCost is in meter,
6326 // and outBBBoxCost is meters. Hence ClientCfg.SelectionOutBBoxWeight is a factor
6327 float boxCost
= distCamCost
+ outBBoxCost
* ClientCfg
.SelectionOutBBoxWeight
;
6329 // take the lowest cost
6330 if(boxCost
<bestDistBox
)
6332 objectSelected
= object
;
6333 bestDistBox
= boxCost
;
6339 // If precise intersection not found
6340 if(bestDistZ
==FLT_MAX
)
6342 // if the last entity under pos is valid, prefer it among all other approximate ones
6343 if(precInstanceUnderPos
&& precInstanceUnderPosValid
)
6344 objectSelected
= precInstanceUnderPos
->getDisplayerVisual();
6347 if (objectSelected
&& objectSelected
->getSelectionType() == ISelectableObject::GroundProjected
)
6349 if (borderSelected
&& borderSelected
!= objectSelected
)
6351 if (!objectSelected
|| !objectSelected
->isInProjectionBorder(CVector2f(sceneInter
.x
, sceneInter
.y
)))
6353 // when mouse over zone border, preffered over other zones
6354 objectSelected
= borderSelected
;
6357 // TODO nico: list not really needed here (comes from old code)
6359 for(k = 0; k < projectedObjects.size(); ++k)
6361 if (projectedObjects[k] == objectSelected) break;
6363 objectSelected = projectedObjects[(k + 1) % projectedObjects.size()];
6368 // return the best entity
6369 _LastInstanceUnderPos
= objectSelected
? objectSelected
->getInstanceInEditor() : NULL
;
6370 return _LastInstanceUnderPos
;
6371 }// getEntityUnderPos //
6374 // *********************************************************************************************************
6375 float CEditor::preciseEntityIntersectionTest(CEntityCL
&entity
, const NLMISC::CVector
&worldRayStart
, const NLMISC::CVector
&worldRayDir
)
6377 //H_AUTO(R2_CEditor_preciseEntityIntersectionTest)
6379 // if entity skeleton model was clipped, skip
6380 NL3D::USkeleton
*skeleton
= entity
.skeleton();
6381 if(!ClientCfg
.Light
&& skeleton
&& !skeleton
->getLastClippedState())
6384 H_AUTO(RZ_Client_GEUP_face_intersect
)
6387 // *** Try get face-intersection, result in distZ
6388 // if the entity support fast and precise intersection (and if it succeeds)
6389 // bool trueIntersectComputed= false;
6390 float dist2D
, distZ
;
6391 if(!ClientCfg
.Light
)
6395 if(skeleton
->supportFastIntersect() && skeleton
->fastIntersect(worldRayStart
, worldRayDir
, dist2D
, distZ
, false))
6403 // get the intersection with the instance (bot object)
6404 else if(!entity
.instances().empty() && !entity
.instances()[0].Current
.empty())
6406 NL3D::UInstance inst
= entity
.instances()[0].Current
;
6407 if(inst
.supportFastIntersect())
6409 if (inst
.fastIntersect(worldRayStart
, worldRayDir
, dist2D
, distZ
, false))
6420 // precise test was asked, but there's no better test than bbox, so return the dist for bbox middle
6421 return (entity
.pos().asVector() + entity
.localSelectBox().getCenter() - worldRayStart
).norm();
6428 // *********************************************************************************************************
6429 const NLMISC::CAABBox
&CEditor::getLocalSelectBox(CEntityCL
&entity
) const
6431 //H_AUTO(R2_CEditor_getLocalSelectBox)
6433 const TEntityCustomSelectBoxMap
&boxMap
= getEditor().getEntityCustomSelectBoxMap();
6434 TEntityCustomSelectBoxMap::const_iterator it
= boxMap
.find(CSheetId(entity
.sheetId()).toString());
6435 if (it
!= boxMap
.end())
6437 if (it
->second
.Enabled
)
6439 return it
->second
.Box
;
6442 return entity
.localSelectBox();
6445 // *********************************************************************************************************
6446 NLMISC::CAABBox
CEditor::getSelectBox(CEntityCL
&entity
) const
6448 //H_AUTO(R2_CEditor_getSelectBox)
6450 const TEntityCustomSelectBoxMap
&boxMap
= getEditor().getEntityCustomSelectBoxMap();
6451 TEntityCustomSelectBoxMap::const_iterator it
= boxMap
.find(CSheetId(entity
.sheetId()).toString());
6452 if (it
!= boxMap
.end())
6454 if (it
->second
.Enabled
)
6456 // box is local, transform in world
6457 CMatrix modelMatrix
;
6458 modelMatrix
= entity
.dirMatrix();
6459 modelMatrix
.setPos(entity
.pos().asVector());
6460 return CAABBox::transformAABBox(modelMatrix
, it
->second
.Box
);
6463 return entity
.selectBox();
6466 // *********************************************************************************************************
6467 void CEditor::connectionMsg(const std::string
&stringId
)
6469 //H_AUTO(R2_CEditor_connectionMsg)
6471 getEditor()._ConnectionMsg
= stringId
;
6472 // ignore if current ui desktop is not the third
6473 if (getUI().getMode() != 3) return;
6474 // show the connection window
6475 CInterfaceGroup
*r2ConnectWindow
= dynamic_cast<CInterfaceGroup
*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:r2ed_connect"));
6476 if (!r2ConnectWindow
) return;
6477 if (stringId
.empty())
6479 r2ConnectWindow
->setActive(false);
6484 if (!r2ConnectWindow
->getActive())
6486 // center for the first display
6487 r2ConnectWindow
->setActive(true);
6488 r2ConnectWindow
->center();
6490 CViewText
*vt
= dynamic_cast<CViewText
*>(r2ConnectWindow
->getView("connexionMsg"));
6493 vt
->setText(CI18N::get(stringId
));
6499 // *********************************************************************************************************
6500 void CEditor::connect()
6502 //H_AUTO(R2_CEditor_connect)
6504 if (_Mode
== EditionMode
|| _Mode
== AnimationModeLoading
)
6507 if (_ScenarioInstance
)
6512 if (_ScenarioInstance
->getLuaProjection().callMethodByNameNoThrow("validateForTesting", 0, 1))
6514 if (getLua().toBoolean(-1) == true)
6518 R2::getEditor().getDMC().getEditionModule().requestStartScenario();
6524 catch (const std::exception
& )
6526 // 'ok' still == false ...
6531 nlwarning("Can't go live");
6534 else if (_Mode
== TestMode
|| _Mode
== DMMode
)
6538 R2::getEditor().getLua().executeScript("r2.requestStopLive()");
6539 if (ClientCfg
.Local
)
6541 R2::getEditor().setMode(CEditor::EditionMode
);
6542 getLua().executeScriptNoThrow("r2.requestReconnection()");
6546 R2::getEditor().setMode(CEditor::GoingToEditionMode
);
6548 CEditor::connectionMsg("uimR2EDGoToEditingMode");
6550 catch (const std::exception
& e
)
6552 nlwarning("Can't go live: %s", e
.what());
6556 // TODO Nico : reset the good capture keyboard
6557 setDefaultChatWindow(PeopleInterraction
.ChatGroup
.Window
);
6558 ConnectionWanted
= false;
6562 // *********************************************************************************************************
6563 CEditor::TInstanceObserverHandle
CEditor::addInstanceObserver(const TInstanceId
&instanceId
, IInstanceObserver
*observer
)
6565 //H_AUTO(R2_CEditor_addInstanceObserver)
6567 //nlwarning("#adding instance observer 0x%x", (int) observer);
6568 nlassert(_InstanceObservers
.size() == _InstanceObserverHandles
.size());
6569 const TInstanceObserverMap::const_iterator lb
= _InstanceObservers
.lower_bound(instanceId
);
6570 const TInstanceObserverMap::const_iterator ub
= _InstanceObservers
.upper_bound(instanceId
);
6571 // NB nico : removed the inserted twice stuff below because observer pointers are not used as keys,
6572 // so sharing is possible
6573 // see if not inserted twice
6575 for (TInstanceObserverMap::const_iterator it = lb; it != ub; ++it)
6577 if (it->second == observer)
6579 nlwarning("addInstanceObserver : Instance observer inserted twice");
6580 return BadInstanceObserverHandle;
6584 // insert the handle
6585 TInstanceObserverHandle handle
= _InstanceObserverHandleCounter
++;
6586 if (_InstanceObserverHandleCounter
== BadInstanceObserverHandle
)
6588 ++ _InstanceObserverHandleCounter
; // avoid bad handle
6590 _InstanceObserverHandles
[handle
] = _InstanceObservers
.insert(TInstanceObserverMap::value_type(instanceId
, observer
));
6591 nlassert(_InstanceObservers
.size() == _InstanceObserverHandles
.size());
6595 // *********************************************************************************************************
6596 CEditor::IInstanceObserver
*CEditor::removeInstanceObserver(TInstanceObserverHandle handle
)
6598 //H_AUTO(R2_CEditor_removeInstanceObserver)
6600 nlassert(_InstanceObservers
.size() == _InstanceObserverHandles
.size());
6601 TInstanceObserverHandleMap::iterator it
= _InstanceObserverHandles
.find(handle
);
6602 if (it
== _InstanceObserverHandles
.end())
6604 nlwarning("removeInstanceObserver : Instance observer handle not found : %d", (int) handle
);
6607 IInstanceObserver
*observer
= it
->second
->second
;
6608 //nlwarning("#removing instance observer 0x%x", (int) observer);
6609 _InstanceObservers
.erase(it
->second
); // remove from observer map
6610 _InstanceObserverHandles
.erase(it
);
6611 nlassert(_InstanceObservers
.size() == _InstanceObserverHandles
.size());
6615 // *********************************************************************************************************
6616 CEditor::IInstanceObserver
*CEditor::getInstanceObserver(TInstanceObserverHandle handle
)
6618 //H_AUTO(R2_CEditor_getInstanceObserver)
6620 nlassert(_InstanceObservers
.size() == _InstanceObserverHandles
.size());
6621 TInstanceObserverHandleMap::iterator it
= _InstanceObserverHandles
.find(handle
);
6622 if (it
== _InstanceObserverHandles
.end())
6626 return it
->second
->second
;
6629 // *********************************************************************************************************
6630 CEditor::TSeason
CEditor::getSeason() const
6632 //H_AUTO(R2_CEditor_getSeason)
6633 if (_IsWaitingTPForSeasonChange
) return UnknownSeason
; // as long at the teleport message hasn't been received, don't change
6634 // the season for nothing -> pretend that we don't know the season so that it remains unchnged
6638 // *********************************************************************************************************
6639 void CEditor::tpReceived()
6641 //H_AUTO(R2_CEditor_tpReceived)
6642 _IsWaitingTPForSeasonChange
= false; // season can be changed now
6643 _TPReceivedFlag
= true;
6646 // *********************************************************************************************************
6647 void CEditor::checkMissingCollisions()
6649 //H_AUTO(R2_CEditor_checkMissingCollisions)
6650 CScenarioEntryPoints
&sep
= CScenarioEntryPoints::getInstance();
6651 sep
.loadCompleteIslands();
6652 const CScenarioEntryPoints::TCompleteIslands
&islands
= sep
.getCompleteIslands();
6653 for(uint k
= 0; k
< islands
.size(); ++k
)
6655 bool found
= !(CPath::lookup(islands
[k
].Island
+ ".packed_island", false, false).empty());
6658 nlwarning("ISLAND COLLISION MISSING FOR : %s", islands
[k
].Island
.c_str());
6660 found
= !(CPath::lookup(islands
[k
].Island
+ ".island_hm", false, false).empty());
6663 nlwarning("ISLAND HEIGHTMAP MISSING FOR : %s", islands
[k
].Island
.c_str());
6668 // *********************************************************************************************************
6670 class CAHEdContextMenu
: public IActionHandler
6672 virtual void execute(CCtrlBase
* /* pCaller */, const std::string
&/* sParams */)
6674 getEditor().displayContextMenu();
6677 REGISTER_ACTION_HANDLER(CAHEdContextMenu
, "r2ed_context_menu");
6680 // *********************************************************************************************************
6681 NLMISC::CVector
getVector(const CObject
*obj
)
6683 return getVectorD(obj
).asVector();
6686 // *********************************************************************************************************
6687 NLMISC::CVectorD
getVectorD(const CObject
*obj
)
6689 return CVectorD(getNumber(obj
, "x"), getNumber(obj
, "y"), getNumber(obj
, "z"));
6693 // *********************************************************************************************************
6694 CObject
*buildVector(const NLMISC::CVectorD
&vector
, const std::string
&instanceId
/*= ""*/)
6697 if (instanceId
.empty())
6699 table
= getEditor().getDMC().newComponent("Position");
6700 table
->set("x", vector
.x
);
6701 table
->set("y", vector
.y
);
6702 table
->set("z", vector
.z
);
6706 table
= new CObjectTableClient
;
6707 table
->insert("InstanceId", new CObjectString(instanceId
));
6708 table
->insert("Class", new CObjectString("Position"));
6709 table
->insert("x", new CObjectNumber(vector
.x
));
6710 table
->insert("y", new CObjectNumber(vector
.y
));
6711 table
->insert("z", new CObjectNumber(vector
.z
));
6716 // *********************************************************************************************************
6717 const CObject
*getObject(const CObject
*obj
,const std::string
&attrName
)
6719 if (!obj
) return NULL
;
6720 return getEditor().getDMC().getPropertyAccessor().getPropertyValue(obj
, attrName
);
6723 // *********************************************************************************************************
6724 std::string
getString(const CObject
*obj
, const std::string
&attrName
)
6726 obj
= getObject(obj
, attrName
);
6727 if (!obj
) return "";
6728 return obj
->isString() ? obj
->toString() : "";
6731 // *********************************************************************************************************
6732 double getNumber(const CObject
*obj
, const std::string
&attrName
)
6734 obj
= getObject(obj
, attrName
);
6735 if (!obj
) return 0.0;
6736 return obj
->isNumber() ? obj
->toNumber() : 0.0;
6739 sint64
getInteger(const CObject
*obj
, const std::string
&attrName
)
6741 obj
= getObject(obj
, attrName
);
6743 return obj
->isInteger() ? obj
->toInteger() : 0;
6746 bool isEditionCurrent()
6748 CEditor
&ed
= getEditor();
6749 return ClientCfg
.R2EDEnabled
&& ed
.getMode() == CEditor::EditionMode
;
6753 // *********************************************************************************************************
6754 void CEditor::onContinentChanged()
6756 //H_AUTO(R2_CEditor_onContinentChanged)
6757 if (_Mode
!= EditionMode
) return;
6758 // refresh all collisions
6759 if (_ScenarioInstance
)
6761 struct CContinentChangedVisitor
: public IInstanceVisitor
6763 virtual void visit(CInstance
&inst
)
6765 inst
.onContinentChanged();
6768 CContinentChangedVisitor continentChangedVisitor
;
6769 _ScenarioInstance
->visit(continentChangedVisitor
);
6773 //-----------------------------
6774 bool CEditor::getVisualPropertiesFromObject(CObject
* object
, SPropVisualA
& vA
, SPropVisualB
& vB
, SPropVisualC
& vC
)
6776 //H_AUTO(R2_CEditor_getVisualPropertiesFromObject)
6778 std::string sheetClient
= getString(object
, "SheetClient");
6780 const CEntitySheet
*entitySheet
= SheetMngr
.get(CSheetId(sheetClient
));
6783 nlwarning("Can't find client sheet %s", sheetClient
.c_str());
6787 CSheetId
sheetId(sheetClient
);
6788 if (sheetId
== CSheetId::Unknown
)
6790 nlwarning("Can't get sheet");
6795 //-------------------------random init npc visual properties
6797 std::map
< std::string
, sint64
> visualProps
;
6800 static const char* keys
[] = { "GabaritHeight", "GabaritTorsoWidth", "GabaritArmsWidth", "GabaritLegsWidth", "GabaritBreastSize"
6801 , "HairType", "HairColor", "Tattoo", "EyesColor"
6802 , "MorphTarget1", "MorphTarget2", "MorphTarget3", "MorphTarget4"
6803 , "MorphTarget5", "MorphTarget6", "MorphTarget7", "MorphTarget8"
6804 , "JacketModel", "TrouserModel", "FeetModel", "HandsModel"
6805 , "ArmModel", "WeaponRightHand", "WeaponLeftHand"
6806 , "JacketColor", "ArmColor", "HandsColor"
6807 , "TrouserColor", "FeetColor"};
6809 unsigned int first
= 0;
6810 unsigned int last
= sizeof(keys
) / sizeof(keys
[0]);
6811 for (; first
!= last
; ++first
)
6813 visualProps
[keys
[first
]] = getInteger(object
, keys
[first
]);
6816 //vA.PropertySubData.Sex = (uint) visualProps["Sex"];
6820 const CCharacterSheet
*chSheet
= dynamic_cast<const CCharacterSheet
*>(entitySheet
);
6823 vA
.PropertySubData
.Sex
= (chSheet
->Gender
== GSGENDER::female
);
6827 vC
.PropertySubData
.CharacterHeight
= (uint
) visualProps
["GabaritHeight"];
6828 vC
.PropertySubData
.ArmsWidth
= (uint
) visualProps
["GabaritArmsWidth"];
6829 vC
.PropertySubData
.TorsoWidth
= (uint
) visualProps
["GabaritTorsoWidth"];
6830 vC
.PropertySubData
.LegsWidth
= (uint
) visualProps
["GabaritLegsWidth"];
6831 vC
.PropertySubData
.BreastSize
= (uint
) visualProps
["GabaritBreastSize"];
6833 int itemNb
= (int) visualProps
["HairType"];
6834 std::string itemFileName
;
6837 itemFileName
= CSheetId(itemNb
).toString();
6838 vA
.PropertySubData
.HatModel
= (uint
) SheetMngr
.getVSIndex(itemFileName
, SLOTTYPE::HEAD_SLOT
);
6842 vA
.PropertySubData
.HatModel
= 0;
6845 vA
.PropertySubData
.HatColor
= (uint
) visualProps
["HairColor"];
6846 vC
.PropertySubData
.Tattoo
= (uint
) visualProps
["Tattoo"];
6847 vC
.PropertySubData
.EyesColor
= (uint
) visualProps
["EyesColor"];
6849 vC
.PropertySubData
.MorphTarget1
= (uint
) visualProps
["MorphTarget1"];
6850 vC
.PropertySubData
.MorphTarget2
= (uint
) visualProps
["MorphTarget2"];
6851 vC
.PropertySubData
.MorphTarget3
= (uint
) visualProps
["MorphTarget3"];
6852 vC
.PropertySubData
.MorphTarget4
= (uint
) visualProps
["MorphTarget4"];
6853 vC
.PropertySubData
.MorphTarget5
= (uint
) visualProps
["MorphTarget5"];
6854 vC
.PropertySubData
.MorphTarget6
= (uint
) visualProps
["MorphTarget6"];
6855 vC
.PropertySubData
.MorphTarget7
= (uint
) visualProps
["MorphTarget7"];
6856 vC
.PropertySubData
.MorphTarget8
= (uint
) visualProps
["MorphTarget8"];
6858 itemNb
= (int) visualProps
["JacketModel"];
6861 itemFileName
= CSheetId(itemNb
).toString();
6862 vA
.PropertySubData
.JacketModel
= (uint
) SheetMngr
.getVSIndex(itemFileName
, SLOTTYPE::CHEST_SLOT
);
6866 vA
.PropertySubData
.JacketModel
= 0;
6869 itemNb
= (int) visualProps
["TrouserModel"];
6872 itemFileName
= CSheetId(itemNb
).toString();
6873 vA
.PropertySubData
.TrouserModel
= (uint
) SheetMngr
.getVSIndex(itemFileName
, SLOTTYPE::LEGS_SLOT
);
6877 vA
.PropertySubData
.TrouserModel
= 0;
6880 itemNb
= (int) visualProps
["FeetModel"];
6883 itemFileName
= CSheetId(itemNb
).toString();
6884 vB
.PropertySubData
.FeetModel
= (uint
) SheetMngr
.getVSIndex(itemFileName
, SLOTTYPE::FEET_SLOT
);
6888 vB
.PropertySubData
.FeetModel
= 0;
6891 itemNb
= (int) visualProps
["HandsModel"];
6894 itemFileName
= CSheetId(itemNb
).toString();
6895 vB
.PropertySubData
.HandsModel
= (uint
) SheetMngr
.getVSIndex(itemFileName
, SLOTTYPE::HANDS_SLOT
);
6899 vB
.PropertySubData
.HandsModel
= 0;
6902 itemNb
= (int) visualProps
["ArmModel"];
6905 itemFileName
= CSheetId(itemNb
).toString();
6906 vA
.PropertySubData
.ArmModel
= (uint
) SheetMngr
.getVSIndex(itemFileName
, SLOTTYPE::ARMS_SLOT
);
6910 vA
.PropertySubData
.ArmModel
= 0;
6913 vA
.PropertySubData
.JacketColor
= (uint
) visualProps
["JacketColor"];
6914 vA
.PropertySubData
.TrouserColor
= (uint
) visualProps
["TrouserColor"];
6915 vB
.PropertySubData
.FeetColor
= (uint
) visualProps
["FeetColor"];
6916 vB
.PropertySubData
.HandsColor
= (uint
) visualProps
["HandsColor"];
6917 vA
.PropertySubData
.ArmColor
= (uint
) visualProps
["ArmColor"];
6919 itemNb
= (int) visualProps
["WeaponRightHand"];
6922 itemFileName
= CSheetId(itemNb
).toString();
6923 vA
.PropertySubData
.WeaponRightHand
= (uint
) SheetMngr
.getVSIndex(itemFileName
, SLOTTYPE::RIGHT_HAND_SLOT
);
6927 vA
.PropertySubData
.WeaponRightHand
= 0;
6930 itemNb
= (int) visualProps
["WeaponLeftHand"];
6933 itemFileName
= CSheetId(itemNb
).toString();
6934 vA
.PropertySubData
.WeaponLeftHand
= (uint
) SheetMngr
.getVSIndex(itemFileName
, SLOTTYPE::LEFT_HAND_SLOT
);
6938 vA
.PropertySubData
.WeaponLeftHand
= 0;
6946 // *********************************************************************************************************
6947 bool CEditor::CSortedInstances::contains(CInstance
*inst
) const
6949 TInstanceToIter::const_iterator it
= _InstanceToIter
.find(inst
);
6951 if (it
== _InstanceToIter
.end())
6953 for(TInstanceByName::const_iterator it
= _ByName
.begin(); it
!= _ByName
.end(); ++it
)
6955 nlassert(it
->second
!= inst
); // should be empty
6959 return it
!= _InstanceToIter
.end();
6962 // *********************************************************************************************************
6963 void CEditor::CSortedInstances::insert(const ucstring
&name
, CInstance
*inst
)
6967 static volatile bool doTest
= true;
6970 nlassert(!contains(inst
)); // inserted twice !!
6973 _InstanceToIter
[inst
] = _ByName
.insert(std::make_pair(name
, inst
));
6976 // *********************************************************************************************************
6977 void CEditor::CSortedInstances::remove(CInstance
*inst
)
6980 TInstanceToIter::iterator it
= _InstanceToIter
.find(inst
);
6981 nlassert(it
!= _InstanceToIter
.end());
6982 _ByName
.erase(it
->second
);
6983 _InstanceToIter
.erase(it
);
6985 nlassert(!contains(inst
));
6990 // *********************************************************************************************************
6991 bool CEditor::isRegisteredByDispName(CInstance
*inst
) const
6994 for (uint k
= 0; k
< _InstancesByDispName
.size(); ++k
)
6996 if (_InstancesByDispName
[k
].contains(inst
)) return true; // registered twice !!
7001 // *********************************************************************************************************
7002 void CEditor::registerInstanceDispName(const ucstring
&displayName
, CInstance
*inst
)
7005 sint currClass
= inst
->getClassIndex();
7008 nlwarning("Classindex not found for class %s", inst
->getClassName().c_str());
7012 nlassert(!isRegisteredByDispName(inst
));
7014 // for each class & subclass of the object, insert in the matching list
7015 while (currClass
>= 0)
7017 nlassert(currClass
< (sint
) _InstancesByDispName
.size());
7018 _InstancesByDispName
[currClass
].insert(displayName
, inst
);
7019 currClass
= getBaseClass(currClass
);
7023 nlassert(isRegisteredByDispName(inst
));
7027 // *********************************************************************************************************
7028 void CEditor::unregisterInstanceDispName(CInstance
*inst
)
7031 sint currClass
= inst
->getClassIndex();
7034 nlwarning("Classindex not found for class %s", inst
->getClassName().c_str());
7038 nlassert(isRegisteredByDispName(inst
));
7040 while (currClass
>= 0)
7042 nlassert(currClass
< (sint
) _InstancesByDispName
.size());
7043 _InstancesByDispName
[currClass
].remove(inst
);
7044 currClass
= getBaseClass(currClass
);
7047 nlassert(!isRegisteredByDispName(inst
));
7052 // *********************************************************************************************************
7054 // Creation of a new entity in scene
7056 class CAHCreateEntity
: public IActionHandler
7058 virtual void execute(CCtrlBase
* /* pCaller */, const std::string
&sParams
)
7061 if (getEditor().getMode() != CEditor::EditionMode
)
7063 nlwarning("Can't modify scenario while testing");
7067 CInterfaceManager
*im
= CInterfaceManager::getInstance();
7068 // Retrieve sheet for entity that is to be created.
7069 std::string paletteId
= getParam(sParams
, "PaletteId");
7070 CObject
*paletteNode
= getEditor().getDMC().getPaletteElement(paletteId
);
7073 nlwarning("Can't retrieve palette node for id %s", paletteId
.c_str());
7076 if (!paletteNode
->isTable())
7078 nlwarning("Bad type for palette node %s (should be a table)", paletteId
.c_str());
7082 std::string sheetClient
= getString(paletteNode
, "SheetClient");
7084 const CEntitySheet
*entitySheet
= SheetMngr
.get(CSheetId(sheetClient
));
7087 nlwarning("Can't find client sheet %s", sheetClient
.c_str());
7090 const CCharacterSheet
*chSheet
= dynamic_cast<const CCharacterSheet
*>(entitySheet
);
7093 getEditor().getLua().push(sheetClient
);
7094 if (getEditor().getEnv().callMethodByNameNoThrow("randomNPCSex", 1, 1))
7096 CLuaObject
result(getEditor().getLua());
7097 sheetClient
= result
.toString();
7100 CSheetId
sheetId(sheetClient
);
7101 if (sheetId
== CSheetId::Unknown
)
7103 nlwarning("Can't get sheet");
7106 getEditor().setCurrentTool(NULL
); // remove current to avoid to have ghost removed by that tool if it was a "CToolCreateEntity" too.
7107 uint ghostSlot
= 1; // TMP TMP
7108 CEntityCL
* entity
= NULL
;
7109 if (!(entity
=CEditor::createEntity(ghostSlot
, sheetId
, CVector::Null
, 0.f
)))
7114 //-------------------------random init npc visual properties
7115 if(dynamic_cast<CPlayerR2CL
*>(entity
))
7117 // push equipment id
7118 getEditor().getLua().push(getString(paletteNode
, "Equipment"));
7122 switch(entity
->people())
7124 case EGSPD::CPeople::Fyros
:
7128 case EGSPD::CPeople::Matis
:
7132 case EGSPD::CPeople::Tryker
:
7136 case EGSPD::CPeople::Zorai
:
7141 nlwarning("CAHCreateEntity::execute unknown people");
7143 getEditor().getLua().push(race
);
7145 if (getEditor().getEnv().callMethodByNameNoThrow("randomNPCProperties", 2, 1))
7147 CLuaObject
result(getEditor().getLua());
7148 std::map
< std::string
, sint64
> visualProps
;
7149 ENUM_LUA_TABLE(result
, it
)
7151 visualProps
[it
.nextKey().toString()] = it
.nextValue().toInteger();
7154 // visual property A depends on the type of the entity
7160 //vA.PropertySubData.Sex = (uint) visualProps["Sex"];
7161 const CEntitySheet
*entitySheet
= SheetMngr
.get((CSheetId
)sheetId
.asInt());
7164 const CCharacterSheet
*chSheet
= dynamic_cast<const CCharacterSheet
*>(entitySheet
);
7167 vA
.PropertySubData
.Sex
= (chSheet
->Gender
== GSGENDER::female
);
7171 vC
.PropertySubData
.CharacterHeight
= (uint
) visualProps
["GabaritHeight"];
7172 vC
.PropertySubData
.ArmsWidth
= (uint
) visualProps
["GabaritArmsWidth"];
7173 vC
.PropertySubData
.TorsoWidth
= (uint
) visualProps
["GabaritTorsoWidth"];
7174 vC
.PropertySubData
.LegsWidth
= (uint
) visualProps
["GabaritLegsWidth"];
7175 vC
.PropertySubData
.BreastSize
= (uint
) visualProps
["GabaritBreastSize"];
7177 int itemNb
= (int) visualProps
["HairType"];
7178 std::string itemFileName
;
7181 itemFileName
= CSheetId(itemNb
).toString();
7182 vA
.PropertySubData
.HatModel
= (uint
) SheetMngr
.getVSIndex(itemFileName
, SLOTTYPE::HEAD_SLOT
);
7186 vA
.PropertySubData
.HatModel
= 0;
7189 vA
.PropertySubData
.HatColor
= (uint
) visualProps
["HairColor"];
7190 vC
.PropertySubData
.Tattoo
= (uint
) visualProps
["Tattoo"];
7191 vC
.PropertySubData
.EyesColor
= (uint
) visualProps
["EyesColor"];
7193 vC
.PropertySubData
.MorphTarget1
= (uint
) visualProps
["MorphTarget1"];
7194 vC
.PropertySubData
.MorphTarget2
= (uint
) visualProps
["MorphTarget2"];
7195 vC
.PropertySubData
.MorphTarget3
= (uint
) visualProps
["MorphTarget3"];
7196 vC
.PropertySubData
.MorphTarget4
= (uint
) visualProps
["MorphTarget4"];
7197 vC
.PropertySubData
.MorphTarget5
= (uint
) visualProps
["MorphTarget5"];
7198 vC
.PropertySubData
.MorphTarget6
= (uint
) visualProps
["MorphTarget6"];
7199 vC
.PropertySubData
.MorphTarget7
= (uint
) visualProps
["MorphTarget7"];
7200 vC
.PropertySubData
.MorphTarget8
= (uint
) visualProps
["MorphTarget8"];
7202 itemNb
= (int) visualProps
["JacketModel"];
7205 itemFileName
= CSheetId(itemNb
).toString();
7206 vA
.PropertySubData
.JacketModel
= (uint
) SheetMngr
.getVSIndex(itemFileName
, SLOTTYPE::CHEST_SLOT
);
7210 vA
.PropertySubData
.JacketModel
= 0;
7213 itemNb
= (int) visualProps
["TrouserModel"];
7216 itemFileName
= CSheetId(itemNb
).toString();
7217 vA
.PropertySubData
.TrouserModel
= (uint
) SheetMngr
.getVSIndex(itemFileName
, SLOTTYPE::LEGS_SLOT
);
7221 vA
.PropertySubData
.TrouserModel
= 0;
7224 itemNb
= (int) visualProps
["FeetModel"];
7227 itemFileName
= CSheetId(itemNb
).toString();
7228 vB
.PropertySubData
.FeetModel
= (uint
) SheetMngr
.getVSIndex(itemFileName
, SLOTTYPE::FEET_SLOT
);
7232 vB
.PropertySubData
.FeetModel
= 0;
7235 itemNb
= (int) visualProps
["HandsModel"];
7238 itemFileName
= CSheetId(itemNb
).toString();
7239 vB
.PropertySubData
.HandsModel
= (uint
) SheetMngr
.getVSIndex(itemFileName
, SLOTTYPE::HANDS_SLOT
);
7243 vB
.PropertySubData
.HandsModel
= 0;
7246 itemNb
= (int) visualProps
["ArmModel"];
7249 itemFileName
= CSheetId(itemNb
).toString();
7250 vA
.PropertySubData
.ArmModel
= (uint
) SheetMngr
.getVSIndex(itemFileName
, SLOTTYPE::ARMS_SLOT
);
7254 vA
.PropertySubData
.ArmModel
= 0;
7257 vA
.PropertySubData
.JacketColor
= (uint
) visualProps
["JacketColor"];
7258 vA
.PropertySubData
.TrouserColor
= (uint
) visualProps
["TrouserColor"];
7259 vB
.PropertySubData
.FeetColor
= (uint
) visualProps
["FeetColor"];
7260 vB
.PropertySubData
.HandsColor
= (uint
) visualProps
["HandsColor"];
7261 vA
.PropertySubData
.ArmColor
= (uint
) visualProps
["ArmColor"];
7263 itemNb
= (int) visualProps
["WeaponRightHand"];
7266 itemFileName
= CSheetId(itemNb
).toString();
7267 vA
.PropertySubData
.WeaponRightHand
= (uint
) SheetMngr
.getVSIndex(itemFileName
, SLOTTYPE::RIGHT_HAND_SLOT
);
7271 vA
.PropertySubData
.WeaponRightHand
= 0;
7274 itemNb
= (int) visualProps
["WeaponLeftHand"];
7277 itemFileName
= CSheetId(itemNb
).toString();
7278 vA
.PropertySubData
.WeaponLeftHand
= (uint
) SheetMngr
.getVSIndex(itemFileName
, SLOTTYPE::LEFT_HAND_SLOT
);
7282 vA
.PropertySubData
.WeaponLeftHand
= 0;
7285 prop
= (sint64
*)&vA
;
7286 NLGUI::CDBManager::getInstance()->getDbProp("SERVER:Entities:E"+toString("%d", entity
->slot())+":P"+toString("%d", CLFECOMMON::PROPERTY_VPA
))->setValue64(*prop
);
7288 prop
= (sint64
*)&vB
;
7289 NLGUI::CDBManager::getInstance()->getDbProp("SERVER:Entities:E"+toString("%d", entity
->slot())+":P"+toString("%d", CLFECOMMON::PROPERTY_VPB
))->setValue64(*prop
);
7291 prop
= (sint64
*)&vC
;
7292 NLGUI::CDBManager::getInstance()->getDbProp("SERVER:Entities:E"+toString("%d", entity
->slot())+":P"+toString("%d", CLFECOMMON::PROPERTY_VPC
))->setValue64(*prop
);
7294 EntitiesMngr
.updateVisualProperty(0, entity
->slot(), CLFECOMMON::PROPERTY_VPA
);
7295 EntitiesMngr
.updateVisualProperty(0, entity
->slot(), CLFECOMMON::PROPERTY_VPB
);
7296 EntitiesMngr
.updateVisualProperty(0, entity
->slot(), CLFECOMMON::PROPERTY_VPC
);
7300 getEditor().setCurrentTool(new CToolCreateEntity(ghostSlot
, paletteId
, NLGUI::CDBManager::getInstance()->getDbProp("UI:TEMP:R2_DRAW_ARRAY")->getValueBool()));
7303 REGISTER_ACTION_HANDLER(CAHCreateEntity
, "r2ed_create_entity");
7306 // *********************************************************************************************************
7307 sint
CEditor::classToIndex(const std::string
&className
) const
7309 CHashMap
<std::string
, uint
>::const_iterator it
= _ClassNameToIndex
.find(className
);
7310 if (it
== _ClassNameToIndex
.end()) return -1;
7314 // *********************************************************************************************************
7315 bool CEditor::isKindOf(sint testedClassIndex
, sint kindClassIndex
) const
7317 if (testedClassIndex
< 0 || kindClassIndex
< 0) return false;
7318 return _KindOfTable(testedClassIndex
, kindClassIndex
) != 0;
7321 // *********************************************************************************************************
7322 void CEditor::initClassInheritanceTable()
7324 std::vector
<std::string
> classes
;
7325 std::map
<std::string
, std::string
> baseClasses
;
7327 ENUM_LUA_TABLE(getClasses(), it
)
7329 CLuaObject name
= it
.nextValue()["Name"];
7330 CLuaObject base
= it
.nextValue()["BaseClass"];
7331 std::string baseName
;
7332 if (base
.isString())
7334 baseName
= base
.toString();
7336 if (name
.isString())
7338 _ClassNameToIndex
[name
.toString()] = (uint
)classes
.size();
7339 classes
.push_back(name
.toString());
7340 baseClasses
[name
.toString()] = baseName
;
7344 _KindOfTable
.init((uint
)classes
.size(), (uint
)classes
.size(), 0);
7345 _BaseClassIndices
.resize(classes
.size());
7346 for (uint k
= 0; k
< classes
.size(); ++k
)
7348 //nlwarning("Class %d = %s", (int) k, classes[k].c_str());
7349 _BaseClassIndices
[k
] = classToIndex(baseClasses
[classes
[k
]]);
7350 for (uint l
= 0; l
< classes
.size(); ++l
)
7352 std::string currClass
= classes
[k
];
7353 while(!currClass
.empty())
7355 if (currClass
== classes
[l
])
7357 _KindOfTable(k
, l
) = 1;
7360 currClass
= baseClasses
[currClass
];
7364 _InstancesByDispName
.clear();
7365 _InstancesByDispName
.resize(classes
.size());
7369 // *********************************************************************************************************
7370 sint
CEditor::getBaseClass(sint derivedClass
) const
7372 if (derivedClass
< 0 || derivedClass
>= (sint
) _BaseClassIndices
.size()) return -1;
7373 return _BaseClassIndices
[derivedClass
];
7377 // *********************************************************************************************************
7378 void CEditor::setMaxVisibleEntityExceededFlag(bool on
)
7380 if (on
== _MaxVisibleEntityExceededFlag
) return;
7381 _MaxVisibleEntityExceededFlag
= on
;
7383 CLuaStackChecker
lsc(&getLua(), 0);
7385 callEnvMethod("setMaxVisibleEntityExceededFlag", 1, 0);
7388 // *********************************************************************************************************
7389 class CAHGoTest
: public IActionHandler
7391 virtual void execute(CCtrlBase
* /* pCaller */, const std::string
&/* sParams */)
7394 ConnectionWanted
= true;
7397 REGISTER_ACTION_HANDLER(CAHGoTest
, "r2ed_go_test");
7399 // *********************************************************************************************************
7400 class CAHStopTest
: public IActionHandler
7402 virtual void execute(CCtrlBase
* /* pCaller */, const std::string
&/* sParams */)
7405 if (getEditor().getAccessMode() != CEditor::AccessEditor
) return;
7406 ConnectionWanted
= true;
7409 REGISTER_ACTION_HANDLER(CAHStopTest
, "r2ed_stop_test");
7411 // *********************************************************************************************************
7412 class CAHOpenScenarioControl
: public IActionHandler
7414 virtual void execute(CCtrlBase
* /* pCaller */, const std::string
&sParams
)
7419 bool showHide
= (getParam(sParams
, "showHide")=="1");
7421 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
7422 CInterfaceGroup
* wnd
= NULL
;
7424 if(!R2::getEditor().isInitialized())
7425 wnd
= dynamic_cast<CInterfaceGroup
*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:ring_scenario_loading_window"));
7427 wnd
= dynamic_cast<CInterfaceGroup
*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:r2ed_scenario_control"));
7432 openUI
= !wnd
->getActive();
7434 wnd
->setActive(openUI
);
7439 REGISTER_ACTION_HANDLER(CAHOpenScenarioControl
, "open_scenario_control");
7441 // *********************************************************************************************************
7442 class CAHR2StopLive
: public IActionHandler
7444 virtual void execute(CCtrlBase
* /* pCaller */, const std::string
&sParams
)
7448 bool confirmStopLive
= getParam(sParams
, "confirmStopLive")=="1";
7450 if(!confirmStopLive
)
7452 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
7453 pIM
->validMessageBox(CInterfaceManager::QuestionIconMsg
, CI18N::get("uiR2EDconfirmStopLive"), "r2_stop_live", "confirmStopLive=1", "", "", "ui:interface");
7457 CSessionBrowserImpl
&sb
= CSessionBrowserImpl::getInstance();
7458 sb
.closeSession(sb
.getCharId(), R2::getEditor().getDMC().getEditionModule().getCurrentAdventureId());
7460 if(sb
.waitOneMessage(sb
.getMessageName("on_invokeResult")))
7462 if(R2::getEditor().getDMC().getEditionModule().getEditSessionLink()!=0)
7464 // Now we expect to receive an impulsion FAR_TP to mainland, triggered
7465 // by the DSS. We'll disobey it by FarTPing to the Edition session instead!
7466 nldebug( "Will return to editing session %u", R2::getEditor().getDMC().getEditionModule().getEditSessionLink().asInt() );
7467 FarTP
.hookNextFarTPForEditor();
7469 // otherwise, let accomplish the FAR_TP to mainland (returnToPreviousSession)
7470 // triggered by the DSS.
7474 nlwarning("closeSession callback return false");
7479 REGISTER_ACTION_HANDLER(CAHR2StopLive
, "r2_stop_live");
7481 // *********************************************************************************************************
7482 class CAHInviteCharacter
: public IActionHandler
7484 virtual void execute(CCtrlBase
*pCaller
, const std::string
&/* sParams */)
7488 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
7489 CAHManager::getInstance()->runActionHandler("leave_modal", pCaller
, "");
7493 CInterfaceGroup
*fatherGC
= pCaller
->getParent();
7496 // Look for the root parent
7499 CInterfaceGroup
*parent
= fatherGC
->getParent();
7500 if (!parent
|| (parent
->getId()=="ui:interface"))
7505 // Get the modal edit box
7506 CGroupEditBox
*geb
= dynamic_cast<CGroupEditBox
*>(fatherGC
->getGroup("add_contact_eb:eb"));
7507 if (geb
&& !geb
->getInputString().empty())
7509 string charName
= geb
->getInputString();
7510 CSessionBrowserImpl
& sessionBrowser
= CSessionBrowserImpl::getInstance();
7511 sessionBrowser
.inviteCharacterByName(sessionBrowser
.getCharId(), charName
);
7513 if(!sessionBrowser
.waitOneMessage(sessionBrowser
.getMessageName("on_invokeResult")))
7515 nlwarning("inviteCharacterByName callback return false");
7518 if(sessionBrowser
._LastInvokeResult
== 14)
7520 CViewText
* pVT
= dynamic_cast<CViewText
*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:warning_free_trial:text"));
7522 pVT
->setText(CI18N::get("uiRingWarningInviteFreeTrial"));
7524 CAHManager::getInstance()->runActionHandler("enter_modal", pCaller
, "group=ui:interface:warning_free_trial");
7526 else if(sessionBrowser
._LastInvokeResult
== 12)
7528 CAHManager::getInstance()->runActionHandler("enter_modal", pCaller
, "group=ui:interface:warning_newcomer");
7531 geb
->setInputString(std::string());
7537 REGISTER_ACTION_HANDLER(CAHInviteCharacter
, "r2ed_invite_character");
7539 // *********************************************************************************************************
7540 class CAHTryGoTest
: public IActionHandler
7542 virtual void execute(CCtrlBase
* /* pCaller */, const std::string
&/* sParams */)
7545 getEditor().callEnvMethod("tryGoTest", 0, 0);
7548 REGISTER_ACTION_HANDLER(CAHTryGoTest
, "r2ed_try_go_test");
7550 // *********************************************************************************************************
7551 class CAHCancelTool
: public IActionHandler
7553 virtual void execute(CCtrlBase
* /* pCaller */, const std::string
&/* sParams */)
7555 if (!ClientCfg
.R2EDEnabled
|| !getEditor().isInitialized()) return;
7557 getEditor().setCurrentTool(NULL
);
7560 REGISTER_ACTION_HANDLER(CAHCancelTool
, "r2ed_cancel_tool");
7563 //////////////////////////////////////////
7564 // SWITCH DM / TESTER AT ANIMATION TIME //
7565 //////////////////////////////////////////
7567 // *********************************************************************************************************
7568 class CAHAnimTestMode
: public IActionHandler
7570 virtual void execute(CCtrlBase
* /* pCaller */, const std::string
&/* sParams */)
7573 if (getEditor().getAccessMode() == CEditor::AccessDM
) return;
7574 getEditor().setMode(CEditor::TestMode
);
7577 REGISTER_ACTION_HANDLER(CAHAnimTestMode
, "r2ed_anim_test_mode");
7579 // *********************************************************************************************************
7580 class CAHAnimDMMode
: public IActionHandler
7582 virtual void execute(CCtrlBase
* /* pCaller */, const std::string
&/* sParams */)
7585 getEditor().setMode(CEditor::DMMode
);
7588 REGISTER_ACTION_HANDLER(CAHAnimDMMode
, "r2ed_anim_dm_mode");
7591 // *********************************************************************************************************
7592 class CAHR2ContextCommand
: public IActionHandler
7594 virtual void execute(CCtrlBase
* /* pCaller */, const std::string
&sParams
)
7597 // forward the call to lua
7598 // first param is the id of the command
7599 std::string commandId
= getParam(sParams
, "commandId");
7600 // if there's a current active tool, then see if it wants to handle it first
7601 if (commandId
== "delete")
7603 if (getEditor().getCurrentTool() && getEditor().getCurrentTool()->onDeleteCmd())
7606 getEditor().getLua().push(commandId
);
7607 getEditor().callEnvMethod("execContextCommand", 1, 0);
7610 REGISTER_ACTION_HANDLER(CAHR2ContextCommand
, "r2ed_context_command");
7613 // *********************************************************************************************************
7614 class CAHR2Teleport
: public IActionHandler
7616 virtual void execute(CCtrlBase
* /* pCaller */, const std::string
&/* sParams */)
7618 if (!ClientCfg
.R2EDEnabled
) return;
7619 if (R2::getEditor().getMode() != CEditor::EditionMode
&&
7620 R2::getEditor().getMode() != CEditor::DMMode
&&
7621 R2::getEditor().getMode() != CEditor::AnimationModeDm
) return;
7624 // just forward to lua
7625 getEditor().callEnvMethod("activeTeleportTool", 0, 0);
7628 REGISTER_ACTION_HANDLER(CAHR2Teleport
, "r2ed_teleport");
7630 // *********************************************************************************************************
7631 class CAHR2Undo
: public IActionHandler
7633 virtual void execute(CCtrlBase
* /* pCaller */, const std::string
&/* sParams */)
7635 // if an edit box currently has focus, then try undo on it first
7636 CGroupEditBox
*eb
= dynamic_cast<CGroupEditBox
*>( CWidgetManager::getInstance()->getCaptureKeyboard());
7637 if (eb
&& eb
->undo())
7641 CActionHistoric
&historic
= getEditor().getDMC().getActionHistoric();
7642 if (historic
.canUndo())
7644 getEditor().setCurrentTool(NULL
);
7645 const ucstring
*actionName
= historic
.getPreviousActionName();
7646 nlassert(actionName
);
7647 #ifdef RYZOM_LUA_UCSTRING
7648 CLuaIHM::push(getEditor().getLua(), *actionName
);
7650 getEditor().getLua().push((*actionName
).toUtf8());
7653 getEditor().callEnvMethod("onUndo", 1, 0);
7657 getEditor().callEnvMethod("onCantUndo", 0, 0);
7661 REGISTER_ACTION_HANDLER(CAHR2Undo
, "r2ed_undo");
7663 // *********************************************************************************************************
7664 class CAHR2Redo
: public IActionHandler
7666 virtual void execute(CCtrlBase
* /* pCaller */, const std::string
&/* sParams */)
7668 // if an edit box currently has focus, then try redo on it first
7669 CGroupEditBox
*eb
= dynamic_cast<CGroupEditBox
*>(CWidgetManager::getInstance()->getCaptureKeyboard());
7670 if (eb
&& eb
->redo())
7674 CActionHistoric
&historic
= getEditor().getDMC().getActionHistoric();
7675 if (historic
.canRedo())
7677 getEditor().setCurrentTool(NULL
);
7678 const ucstring
*actionName
= historic
.getNextActionName();
7679 nlassert(actionName
);
7680 #ifdef RYZOM_LUA_UCSTRING
7681 CLuaIHM::push(getEditor().getLua(), *actionName
);
7683 getEditor().getLua().push((*actionName
).toUtf8());
7686 getEditor().callEnvMethod("onRedo", 1, 0);
7690 getEditor().callEnvMethod("onCantRedo", 0, 0);
7694 REGISTER_ACTION_HANDLER(CAHR2Redo
, "r2ed_redo");
7696 // *********************************************************************************************************
7697 // signal the server that a dm gift has begun, so that the server can take note of the target entity (the current target)
7698 class CAHR2DMGiftBegin
: public IActionHandler
7700 virtual void execute(CCtrlBase
* /* pCaller */, const std::string
&/* sParams */)
7703 if(GenericMsgHeaderMngr
.pushNameToStream("DM_GIFT:BEGIN", out
))
7708 nlwarning("<CHandlerInvalidateExchange::execute> unknown message name 'DM_GIFT:BEGIN");
7711 REGISTER_ACTION_HANDLER(CAHR2DMGiftBegin
, "r2ed_dm_gift_begin");
7713 // *********************************************************************************************************
7714 // signal the server that a dm gift has begun, so that the server can take note of the target entity (the current target)
7715 class CAHR2DMGiftValidate
: public IActionHandler
7717 virtual void execute(CCtrlBase
* /* pCaller */, const std::string
&/* sParams */)
7719 CInterfaceManager
*im
= CInterfaceManager::getInstance();
7721 if(GenericMsgHeaderMngr
.pushNameToStream("DM_GIFT:VALIDATE", out
))
7723 for(uint k
= 0; k
< 8; ++k
)
7727 CCDBNodeLeaf
*sheetLeaf
= NLGUI::CDBManager::getInstance()->getDbProp(toString("LOCAL:R2:DM_GIFT:%d:SHEET", (int) k
));
7728 if (sheetLeaf
) sheetId
= (uint32
) sheetLeaf
->getValue32();
7729 CCDBNodeLeaf
*quantityLeaf
= NLGUI::CDBManager::getInstance()->getDbProp(toString("LOCAL:R2:DM_GIFT:%d:QUANTITY", (int) k
));
7730 if (quantityLeaf
) quantity
= (uint8
) quantityLeaf
->getValue8();
7731 out
.serial(sheetId
);
7732 out
.serial(quantity
);
7737 nlwarning("<CHandlerInvalidateExchange::execute> unknown message name 'DM_GIFT:VALIDATE");
7740 REGISTER_ACTION_HANDLER(CAHR2DMGiftValidate
, "r2ed_dm_gift_validate");
7743 // *********************************************************************************************************
7744 // freeze / unfreeze bot objects
7745 class CAHR2FreezeUnfreezeBotObjects
: public IActionHandler
7747 virtual void execute(CCtrlBase
* /* pCaller */, const std::string
&/* sParams */)
7749 CLuaManager::getInstance().executeLuaScript("r2:freezeUnfreezeBotObjects()");
7752 REGISTER_ACTION_HANDLER(CAHR2FreezeUnfreezeBotObjects
, "r2ed_freeze_unfreeze_botobjects");
7761 // *********************************************************************************************************
7762 // COMMAND TO REINITIALIZE THE EDITOR : useful to check scripts error
7763 NLMISC_COMMAND(resetEditor
, "reset R2 editor, reload all scripts (except ui xmls)", "")
7765 if (!args
.empty()) return false;
7766 R2::ResetWanted
= true;
7767 R2::ReloadUIFlag
= false;
7771 // *********************************************************************************************************
7772 // COMMAND TO REINITIALIZE THE EDITOR : useful to check scripts error
7773 NLMISC_COMMAND(resetEditorAndReloadUI
, "reset R2 editor, reload all scripts & xml (possibly preserving scenario)", "")
7775 if (!args
.empty()) return false;
7776 R2::ResetWanted
= true;
7777 R2::ReloadUIFlag
= true;
7780 // *********************************************************************************************************
7781 // write scenario rtdata to a file for debugging or stress testing by simulator_service
7782 NLMISC_COMMAND(saveScenarioRtData
, "save scenario RtData to file", "<filename>")
7784 const R2::CObject
*scenario
= R2::getEditor().getDMC().getHighLevel();
7787 nlinfo("No current scenario -- can't save rtdata");
7791 std::string fileName
= "outpout";
7794 // try to name file from title, then area+instance
7795 R2::CObject
*description
= scenario
->findAttr("Description");
7798 R2::CObject
*name
= description
->findAttr("Name");
7799 R2::CObject
*title
= 0;
7806 title
= description
->findAttr("Title"); //obsolete
7808 R2::CObject
*locationId
= description
->findAttr("LocationId");
7809 R2::CObject
*instanceId
= description
->findAttr("InstanceId");
7812 string sTitle
= title
->toString();
7813 if( !sTitle
.empty() )
7816 else if( locationId
&& instanceId
)
7817 fileName
= "area" + locationId
->toString() + "_" + instanceId
->toString();
7820 else // filename given
7825 nlinfo("translating current scenario");
7826 R2::CObject
*pHighLevel
= scenario
->clone();
7827 nlassert( pHighLevel
);
7829 R2::CObject
*pRtData
= R2::getEditor().getDMC().translateScenario( pHighLevel
);
7833 nlwarning("Failed to translate high-level scenario into rtdata");
7838 string fullFileName
= fileName
;
7839 fullFileName
+= ".rt.bin";
7840 nlinfo("writing rtdata to %s", fullFileName
.c_str());
7843 output
.open(fullFileName
);
7844 R2::CObjectSerializerClient
serializer( pRtData
);
7845 serializer
.serial(output
);
7852 fullFileName
= fileName
;
7853 fullFileName
+= ".rt.txt";
7856 //std::stringstream ss;
7858 output
.open(fullFileName
);
7859 pRtData
->serialize(ss
);
7860 //std::string str = ss.str();
7869 NLMISC_COMMAND(dumpValidPositions
, "dump valid position to create objects from the current camera viewpoint", "<filename>")
7871 if (args
.size() != 1) return false;
7874 COFile
output(args
[0]);
7876 Driver
->getBuffer(result
);
7877 if (result
.getWidth() == 0 || result
.getHeight() == 0) return false;
7878 CMatrix camMatrix
= MainCam
.getMatrix();
7879 NL3D::CFrustum fru
= MainCam
.getFrustum();
7880 R2::CTool::CWorldViewRay wvr
;
7881 wvr
.Right
= camMatrix
.getI().normed();
7882 wvr
.Up
= camMatrix
.getK().normed();
7883 wvr
.OnMiniMap
= false;
7884 wvr
.Origin
= camMatrix
.getPos();
7886 for (uint x
= 0; x
< result
.getWidth(); ++x
)
7888 for (uint y
= 0; y
< result
.getHeight(); ++y
)
7890 CVector
ray(fru
.Left
+ (fru
.Right
- fru
.Left
) * (x
/ (float) result
.getWidth()), fru
.Near
,
7891 fru
.Top
+ (fru
.Bottom
- fru
.Top
) * (y
/ (float) result
.getHeight()));
7893 ray
= camMatrix
.mulVector(ray
);
7896 R2::CTool::TRayIntersectionType rit
= R2::CTool::computeLandscapeRayIntersection(wvr
, inter
);
7900 case R2::CTool::NoIntersection
: resultCol
= CRGBA(0, 0, 0, 0); break;
7901 case R2::CTool::ValidPacsPos
: resultCol
= CRGBA(0, 0, 255, 100); break;
7902 default: resultCol
= CRGBA(255, 0, 0, 100); break;
7904 CRGBA
*dest
= ((CRGBA
*) &result
.getPixels(0)[0]) + x
+ y
* result
.getWidth();
7905 dest
->blendFromui(*dest
, resultCol
, resultCol
.A
);
7913 result
.writeTGA(output
, 32, false);
7922 // *********************************************************************************************************
7923 NLMISC_COMMAND(resetScenario, "reset R2 editor, reload all scripts & xml", "")
7925 if (!args.empty()) return false;
7926 R2::ResetScenarioWanted = true;
7930 // *********************************************************************************************************
7931 NLMISC_COMMAND(reloadScenario, "reset R2 editor, reload all scripts & xml (possibly preserving scenario)", "")
7933 if (!args.empty()) return false;
7935 R2::ReloadScenarioWanted = true;
7942 return R2::getEditor().getMode() != R2::CEditor::NotInitialized
;