Fix css style order when using external css files
[ryzomcore.git] / ryzom / client / src / r2 / editor.cpp
blob8d0f14e02f79f87756e9cbd9a8803684f0b7d94e
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
6 // Copyright (C) 2013-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 //
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/>.
21 #include "stdpch.h"
22 #include <sstream>
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"
38 #include "r2_lua.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"
51 #include "editor.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"
89 #include "../input.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"
121 #ifdef DEBUG_NEW
122 #define new DEBUG_NEW
123 #endif
125 using namespace NLMISC;
126 using namespace NLNET;
127 using namespace NL3D;
128 using namespace NLGUI;
130 extern CEventsListener EventsListener;
131 extern CLog g_log;
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)
140 namespace R2
143 class CEditorCheck
145 public:
146 CEditorCheck() { check(); }
147 ~CEditorCheck() { check(); }
148 void 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;
162 #ifdef NL_DEBUG
163 #define CHECK_EDITOR CEditorCheck __ec;
164 #else
165 #define CHECK_EDITOR (void) 0;
166 #endif
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
186 public:
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");
219 return;
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");
231 return;
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");
244 return;
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");
258 return;
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");
271 return;
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 // *********************************************************************************************************
314 CEditor::CEditor()
316 //H_AUTO(R2_CEditor_CEditor)
317 _SelectedInstance = NULL;
318 _FocusedInstance = NULL;
319 _Scenario = NULL;
320 _EnteredInSetSelectedInstance = false;
321 _DecalRefTime = 0;
322 _Initialized = false;
323 //vianney?? _LastUIModificationDate = 0;
324 _InstanceObserverHandleCounter = 0;
325 // module are initialized one time and never reconnected
326 _DMC = NULL;
327 _DMS = NULL;
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;
338 _WillTP = false;
339 _FixedLighting = false;
341 _ScenarioReceivedFlag = false;
342 _TPReceivedFlag = false;
343 _WaitScenarioScreenWanted = false;
344 _WaitScenarioScreenActive = false;
345 _NewScenario = NULL;
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)
357 CHECK_EDITOR
358 std::fill(_ForceDesktopReset, _ForceDesktopReset + sizeofarray(_ForceDesktopReset), force);
361 // *********************************************************************************************************
362 void CEditor::autoConfigInit(bool serverIsRingSession)
364 //H_AUTO(R2_CEditor_autoConfigInit)
365 // R2ED enabled ?
366 if (ClientCfg.R2EDEnabled)
368 // Editor and Animator (DM) modes
369 initModules(true);
370 TMode initialMode;
371 TAccessMode initialAccessMode;
372 switch (UserRoleInSession.getValue())
374 case R2::TUserRole::ur_editor:
375 initialMode = R2::CEditor::EditionMode;
376 initialAccessMode = R2::CEditor::AccessEditor;
377 break;
378 case R2::TUserRole::ur_animator:
379 initialMode = R2::CEditor::AnimationModeDm;
380 initialAccessMode = R2::CEditor::AccessDM;
381 break;
382 case R2::TUserRole::ur_outland_owner:
383 initialMode = R2::CEditor::AnimationModeDm;
384 initialAccessMode = R2::CEditor::AccessOutlandOwner;
385 break;
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;
391 break;
392 default:
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);
399 else
401 // Normal player and Ring player modes
402 ActionsContext.setContext("game");
403 if (serverIsRingSession)
404 initModules(false);
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)
428 CHECK_EDITOR
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);
442 if (ClientCfg.Local)
444 _DMS = new CDynamicMapService(ClientCfg.ConfigFile, socketClientGw);
445 _DMS->init();
447 else
449 _DMS = 0;
451 if (connectDMC)
452 _DMC = new CDynamicMapClientEventForwarder("Client0",socketClientGw, getLua().getStatePointer());
453 else
454 _DMC = new CDynamicMapClient("Client0",socketClientGw, getLua().getStatePointer());
456 _DMC->setInstantFeedBackFlag(true);
460 // *********************************************************************************************************
462 void CEditor::releaseModules()
464 //H_AUTO(R2_CEditor_releaseModules)
465 CHECK_EDITOR
466 delete _DMC; // must have a virtual destructor
467 if (ClientCfg.Local)
468 delete _DMS;
469 _DMC = NULL;
470 _DMS = NULL;
472 IModuleManager &mm = IModuleManager::getInstance();
473 NLNET::IModule* clientGw = mm.getLocalModule("clientGw");
474 if (clientGw)
476 mm.deleteModule(clientGw);
479 _Initialized = false;
482 // *********************************************************************************************************
483 void CEditor::inGameSelection(const CLFECOMMON::TCLEntityId &/* slot */)
485 //H_AUTO(R2_CEditor_inGameSelection)
486 switch(_Mode)
488 case DMMode:
489 case AnimationModeDm:
490 // reset current selection options
491 getEditor().callEnvMethod("updateAnimBarActions", 0);
493 getLua().push("");
494 getEditor().callEnvMethod("dssTarget", 1);
495 break;
496 default:
497 // no-op
498 break;
502 // *********************************************************************************************************
503 CEditor::~CEditor()
505 release();
508 // ***************************************************************
509 void CEditor::requestSetLocalNode(const std::string& instanceId, const std::string& attrName, const CObject *value)
511 //H_AUTO(R2_CEditor_requestSetLocalNode)
512 CHECK_EDITOR
514 CObject* obj = NULL;
517 CObject *src = _DMC->find(instanceId);
518 if (!src)
520 nlwarning("Can't find object with id %s", instanceId.c_str());
521 return;
523 if (!attrName.empty())
525 CObject *subObj = src->getAttr(attrName);
526 if (!subObj)
528 CObject * valueBase = (CObject *) getObject(src, attrName); // from Base
529 if (!valueBase)
531 nlwarning("Can't find attribute %s inside object (or is base) with InstanceId = %s", attrName.c_str(), instanceId.c_str());
532 return;
534 CObject *valueClone = valueBase->clone();
535 valueClone->setParent(0);
536 src->setObject(attrName, valueClone);
537 subObj = src->getAttr(attrName);
539 if (!subObj)
541 nlwarning("Can't find attribute %s inside object with InstanceId = %s", attrName.c_str(), instanceId.c_str());
542 return;
545 obj = subObj;
549 getDMC().getPropertyAccessor().shadowValue(obj, value->clone());
550 // trigger handlers
551 onAttrModified(obj);
554 // *****************************************
556 void CEditor::requestCommitLocalNode(const std::string& instanceId, const std::string& attrName)
558 //H_AUTO(R2_CEditor_requestCommitLocalNode)
559 CHECK_EDITOR
560 CObject *obj = _DMC->find(instanceId, attrName);
561 if (!obj)
563 nlwarning("(while calling requestSetLocalNode");
564 return;
567 //nlwarning("**** current unshadowed value");
568 //obj->dump();
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();
575 // send net request
576 getDMC().getPropertyAccessor().commitValue(obj);
577 getDMC().requestSetNode(instanceId, attrName, obj);
579 CObject *localValue = getDMC().getPropertyAccessor().getShadowingValue(obj);
580 if (!localValue)
582 nlwarning("value is not shadowed : ");
583 obj->dump();
584 return;
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)
596 CHECK_EDITOR
597 CObject *obj = _DMC->find(instanceId, attrName);
598 if (!obj)
600 nlwarning("(while calling requestSetLocalNode");
601 return;
603 getDMC().getPropertyAccessor().rollbackValue(obj);
604 // force the displayer to update their state from the shadowed value in place of the local value
605 onAttrModified(obj);
608 // ***************************************************************
609 CInterfaceManager &CEditor::getUI()
611 //H_AUTO(R2_CEditor_getUI)
612 CHECK_EDITOR
613 CInterfaceManager *im = CInterfaceManager::getInstance();
614 nlassert(im);
615 return *im;
618 // *********************************************************************************************************
619 CLuaState &CEditor::getLua()
621 //H_AUTO(R2_CEditor_getLua)
622 CHECK_EDITOR
623 CLuaState *ls = CLuaManager::getInstance().getLuaState();
624 nlassert(ls);
625 return *ls;
628 // *********************************************************************************************************
629 CLuaObject &CEditor::getEnv()
631 //H_AUTO(R2_CEditor_getEnv)
632 nlassert(_Env.isValid());
633 return _Env;
636 // *********************************************************************************************************
637 CLuaObject CEditor::getConfig()
639 //H_AUTO(R2_CEditor_getConfig)
640 CHECK_EDITOR
641 return getEnv()["Config"];
644 // *********************************************************************************************************
645 void CEditor::clearDebugWindow()
647 //H_AUTO(R2_CEditor_clearDebugWindow)
648 CHECK_EDITOR
649 getUI().flushDebugWindow();
650 CGroupList *gl = dynamic_cast<CGroupList *>(CWidgetManager::getInstance()->getElementFromId("ui:interface:debug_info:content:cb:text_list"));
651 if (gl)
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)
662 CHECK_EDITOR
663 ResetWanted = true;
664 if (nlstricmp(CFile::getExtension(filename), "xml") == 0 ||
665 nlstricmp(CFile::getExtension(filename), "uxt") == 0)
667 ReloadUIFlag = true;
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)
684 CHECK_EDITOR
685 if (!getEditor().getSelectedInstance())
687 ls.pushNil();
689 else
691 ls.push(toString(getEditor().getSelectedInstance()->getId()));
693 return 1;
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);
706 return 1;
708 // *********************************************************************************************************
709 int CEditor::luaSetSelectedInstanceId(CLuaState &ls)
711 //H_AUTO(R2_CEditor_luaSetSelectedInstanceId)
712 CHECK_EDITOR
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);
718 return 0;
720 CInstance *inst = getEditor().getInstanceFromId(ls.toString(2));
721 if (!inst)
723 nlwarning("setSelectedInstance : Instance with Id %s not found", ls.toString(2));
724 return 0;
726 if (!inst->getSelectableFromRoot())
728 nlwarning("Instance with id %s or one of its ancestor is not selectable", ls.toString(2));
729 return 0;
731 getEditor().setSelectedInstance(inst);
732 return 0;
735 // *********************************************************************************************************
736 int CEditor::luaSetCurrentTool(CLuaState &ls)
738 //H_AUTO(R2_CEditor_luaSetCurrentTool)
739 CHECK_EDITOR
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);
746 else
748 CTool *tool = createObjectFromClassName<CTool>(ls.toString(2));
749 if (tool)
751 if (ls.getTop() == 3)
753 CLuaObject initParams(ls);
754 tool->init(initParams);
756 getEditor().setCurrentTool(tool);
759 return 0;
762 // *********************************************************************************************************
763 int CEditor::luaGetCurrentTool(CLuaState &ls)
765 //H_AUTO(R2_CEditor_luaGetCurrentTool)
766 CHECK_EDITOR
767 CLuaIHM::checkArgCount(ls, "getCurrentTool", 1); // 1 because of the method call
768 CLuaIHM::pushReflectableOnStack(ls, getEditor().getCurrentTool());
769 return 1;
772 // *********************************************************************************************************
773 int CEditor::luaGetSelectedInstance(CLuaState &ls)
775 //H_AUTO(R2_CEditor_luaGetSelectedInstance)
776 CHECK_EDITOR
777 if (!getEditor().getSelectedInstance())
779 ls.pushNil();
781 else
783 getEditor().projectInLua(getEditor().getSelectedInstance()->getObjectTable());
785 return 1;
788 // *********************************************************************************************************
789 int CEditor::luaGetInstanceFromId(CLuaState &ls)
791 //H_AUTO(R2_CEditor_luaGetInstanceFromId)
792 CHECK_EDITOR
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));
797 if (inst == NULL)
799 ls.pushNil();
800 return 1;
802 else
804 getEditor().projectInLua(inst->getObjectTable());
805 return 1;
807 return 0;
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; }
826 SPropVisualA vA;
827 SPropVisualB vB;
828 SPropVisualC vC;
830 bool ok = getEditor().getVisualPropertiesFromObject(object, vA, vB, vC);
832 if (!ok)
834 return 0; //no param
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 );
843 ls.push(strVPABC);
845 return 1; //3 string
848 // *********************************************************************************************************
849 int CEditor::luaDisplayContextMenu(CLuaState &ls)
851 //H_AUTO(R2_CEditor_luaDisplayContextMenu)
852 CHECK_EDITOR
853 CLuaIHM::checkArgCount(ls, "displayContextMenu", 1); // this is a method
854 getEditor().displayContextMenu();
855 return 0;
858 // *********************************************************************************************************
859 int CEditor::luaConnectAsCreator(CLuaState &ls)
861 //H_AUTO(R2_CEditor_luaConnectAsCreator)
862 CHECK_EDITOR
863 CLuaIHM::checkArgCount(ls, "connectAsCreator", 1); // this is a method
864 //getEditor().connectAsCreator();
865 return 0;
868 // *********************************************************************************************************
869 int CEditor::luaDofile(CLuaState &ls)
871 //H_AUTO(R2_CEditor_luaDofile)
872 CHECK_EDITOR
873 CLuaIHM::checkArgCount(ls, "doFile", 1);
874 CLuaIHM::checkArgType(ls, "doFile", 1, LUA_TSTRING);
875 getEditor().doLuaScript(ls.toString(-1), ls.toString(-1));
876 return 0;
879 // *********************************************************************************************************
880 int CEditor::luaTryFile(CLuaState &/* ls */)
882 //H_AUTO(R2_CEditor_luaTryFile)
883 /* CHECK_EDITOR
884 CLuaIHM::checkArgCount(ls, "doFile", 1);
885 CLuaIHM::checkArgType(ls, "doFile", 1, LUA_TSTRING);
886 getEditor().doLuaScript(ls.toString(-1), ls.toString(-1));*/
887 return 0;
890 // *********************************************************************************************************
891 int CEditor::luaSetEntityCustomSelectBox(CLuaState &ls)
893 //H_AUTO(R2_CEditor_luaSetEntityCustomSelectBox)
894 CHECK_EDITOR
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;
900 CLuaObject obj(ls);
901 selectBox.fromTable(obj);
902 TEntityCustomSelectBoxMap &boxMap = getEditor().getEntityCustomSelectBoxMap();
903 boxMap[sheetName] = selectBox;
905 static volatile bool dumpMap = false;
906 if (dumpMap)
908 for (TEntityCustomSelectBoxMap::const_iterator watchIt = boxMap.begin(); watchIt != boxMap.end(); ++ watchIt)
910 nlwarning(watchIt->first.c_str());
914 return 0;
917 // *********************************************************************************************************
918 int CEditor::luaGetEntityCustomSelectBox(CLuaState &ls)
920 //H_AUTO(R2_CEditor_luaGetEntityCustomSelectBox)
921 CHECK_EDITOR
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))
928 ls.newTable();
929 CLuaObject result(ls);
930 boxMap[sheetName].toTable(result);
931 result.push();
933 else
935 ls.pushNil();
937 return 1;
940 // *********************************************************************************************************
941 int CEditor::luaChoosePos(CLuaState &ls)
943 //H_AUTO(R2_CEditor_luaChoosePos)
944 CHECK_EDITOR
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
966 ls.pushValue(3);
967 CLuaObject validFunc(ls); // pop valid function
968 ls.pushValue(4);
969 CLuaObject cancelFunc(ls); // pop cancel function
971 sint ghostSlot;
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));
978 return 0;
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));
984 return 0;
987 else
989 ghostSlot = -1; // no representation in scene
991 // additionnal polys displayed by the choose pos
992 std::vector<NLMISC::CPolygon2D> polys;
993 CPrimLook validLook;
994 CPrimLook invalidLook;
995 if (ls.getTop() >= 8)
997 CLuaStackRestorer lsr(&ls, ls.getTop());
998 CLuaIHM::checkArgType(ls, funcName, 8, LUA_TTABLE);
999 ls.pushValue(8);
1000 CLuaObject poly;
1001 poly.pop(ls);
1002 ENUM_LUA_TABLE(poly, it)
1004 NLMISC::CPolygon2D newPoly;
1005 it.nextValue().push();
1006 CLuaIHM::getPoly2DOnStack(ls, -1, newPoly);
1007 ls.pop();
1008 polys.push_back(newPoly);
1011 if (ls.getTop() >= 9)
1013 ls.pushValue(9);
1014 CLuaObject look;
1015 look.pop(ls);
1016 validLook.init(look);
1018 if (ls.getTop() >= 10)
1020 ls.pushValue(10);
1021 CLuaObject look;
1022 look.pop(ls);
1023 invalidLook.init(look);
1026 getEditor().setCurrentTool(new CToolChoosePosLua(ghostSlot, validFunc, cancelFunc, toolName, cursValid, cursInvalid, polys, validLook, invalidLook));
1027 return 0;
1030 // *********************************************************************************************************
1031 int CEditor::luaSnapPosToGround(CLuaState &ls)
1033 //H_AUTO(R2_CEditor_luaSnapPosToGround)
1034 CHECK_EDITOR
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);
1047 return 3;
1049 else
1051 // default z to 0
1052 ls.push(0.f);
1053 return 3;
1056 // new algo : to avoid to snapping to a cliff, start from the approximate (valid) height found in the height map
1057 CVector inter;
1058 if (CTool::computeWorldMapIntersection((float) ls.toNumber(2), (float) ls.toNumber(3), inter) != CTool::NoIntersection)
1060 ls.push(inter.x);
1061 ls.push(inter.y);
1062 ls.push(inter.z);
1063 return 3;
1065 else
1067 // default z to 0
1068 ls.push(0.f);
1069 return 3;
1073 // *********************************************************************************************************
1074 int CEditor::luaGetUserEntityPosition(CLuaState &ls)
1076 //H_AUTO(R2_CEditor_luaGetUserEntityPosition)
1077 CHECK_EDITOR
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);
1083 return 3;
1086 // *********************************************************************************************************
1087 int CEditor::luaGetUserEntityFront(CLuaState &ls)
1089 //H_AUTO(R2_CEditor_luaGetUserEntityFront)
1090 CHECK_EDITOR
1091 const char *funcName = "getUserEntityPosition";
1092 CLuaIHM::checkArgCount(ls, funcName, 1);
1093 ls.push(UserEntity->front().x);
1094 ls.push(UserEntity->front().y);
1095 return 2;
1098 // *********************************************************************************************************
1099 int CEditor::luaRequestSetLocalNode(CLuaState &ls)
1101 //H_AUTO(R2_CEditor_luaRequestSetLocalNode)
1102 CHECK_EDITOR
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());
1108 if (!object)
1110 CLuaIHM::fails(ls, "%s : can't read object from parameter 3", funcName);
1112 getEditor().requestSetLocalNode(ls.toString(1), ls.toString(2), object);
1113 delete object;
1114 return 0;
1117 // *********************************************************************************************************
1118 int CEditor::luaRequestCommitLocalNode(CLuaState &ls)
1120 //H_AUTO(R2_CEditor_luaRequestCommitLocalNode)
1121 CHECK_EDITOR
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));
1127 return 0;
1130 // *********************************************************************************************************
1131 int CEditor::luaRequestRollbackLocalNode(CLuaState &ls)
1133 //H_AUTO(R2_CEditor_luaRequestRollbackLocalNode)
1134 CHECK_EDITOR
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));
1140 return 0;
1143 // *********************************************************************************************************
1144 int CEditor::luaSetCurrentActFromId(CLuaState &ls)
1146 //H_AUTO(R2_CEditor_luaSetCurrentActFromId)
1147 CHECK_EDITOR
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; }
1154 if (!act)
1156 nlwarning("%s : act with id %s not found", funcName, ls.toString(1));
1157 return 0;
1159 if (!act->isKindOf("Act"))
1161 nlwarning("%s : instance with id %s is not an act", funcName, ls.toString(1));
1162 return 0;
1164 getEditor().setCurrentAct(act);
1165 return 0;
1168 // *********************************************************************************************************
1169 int CEditor::luaGetCurrentAct(CLuaState &ls)
1171 //H_AUTO(R2_CEditor_luaGetCurrentAct)
1172 CHECK_EDITOR
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());
1179 else
1181 ls.pushNil();
1183 return 1;
1187 // *********************************************************************************************************
1188 int CEditor::luaGenInstanceName(CLuaState &ls)
1190 //H_AUTO(R2_CEditor_luaGenInstanceName)
1191 CHECK_EDITOR
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
1196 ucstring baseName;
1197 nlverify(CLuaIHM::getUCStringOnStack(ls, 2, baseName));
1198 CLuaIHM::push(ls, getEditor().genInstanceName(baseName));
1199 #else
1200 CLuaIHM::checkArgType(ls, funcName, 2, LUA_TSTRING);
1201 ls.push(getEditor().genInstanceName(ucstring::makeFromUtf8(ls.toString(2))).toUtf8()); // FIXME: Ring UTF-8
1202 #endif
1203 return 1;
1206 // *********************************************************************************************************
1207 int CEditor::luaIsPostFixedByNumber(CLuaState &ls)
1209 //H_AUTO(R2_CEditor_luaIsPostFixedByNumber)
1210 CHECK_EDITOR
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
1215 ucstring baseName;
1216 nlverify(CLuaIHM::getUCStringOnStack(ls, 2, baseName));
1217 ls.push(getEditor().isPostFixedByNumber(baseName));
1218 #else
1219 CLuaIHM::checkArgType(ls, funcName, 2, LUA_TSTRING);
1220 ls.push(getEditor().isPostFixedByNumber(ucstring::makeFromUtf8(ls.toString(2)))); // FIXME: Ring UTF-8
1221 #endif
1222 return 1;
1225 // *********************************************************************************************************
1226 int CEditor::luaIsClearingContent(CLuaState &ls)
1228 //H_AUTO(R2_CEditor_luaIsPostFixedByNumber)
1229 CHECK_EDITOR
1230 const char *funcName = "isClearingContent";
1231 CLuaIHM::checkArgCount(ls, funcName, 1); // this is a method
1232 ls.push(getEditor().isClearingContent());
1233 return 1;
1237 // *********************************************************************************************************
1238 int CEditor::luaSetCookie(CLuaState &ls)
1240 //H_AUTO(R2_CEditor_luaSetCookie)
1241 CHECK_EDITOR
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);
1249 return 0;
1252 // *********************************************************************************************************
1253 int CEditor::luaIsCreature(CLuaState &ls)
1255 //H_AUTO(R2_CEditor_luaIsCreature)
1256 CHECK_EDITOR
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)));
1273 ls.push(creature);
1275 return 1;
1278 // *********************************************************************************************************
1279 int CEditor::luaSetEditorSeason(CLuaState &ls)
1281 //H_AUTO(R2_CEditor_luaSetEditorSeason)
1282 CHECK_EDITOR
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;
1304 else
1306 getEditor()._IsWaitingTPForSeasonChange = false;
1308 return 0;
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));
1319 return 0;
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());
1329 return 1;
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);
1343 #else
1344 CLuaIHM::checkArgType(ls, funcName, 3, LUA_TSTRING);
1345 CLuaIHM::checkArgType(ls, funcName, 4, LUA_TSTRING);
1346 CLuaIHM::checkArgType(ls, funcName, 5, LUA_TSTRING);
1347 #endif
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);
1359 #else
1360 mi.Name = ucstring::makeFromUtf8(ls.toString(3));
1361 mi.Description = ucstring::makeFromUtf8(ls.toString(4));
1362 mi.Comment = ucstring::makeFromUtf8(ls.toString(5));
1363 #endif
1364 getEditor().setPlotItemInfos(mi);
1365 return 0;
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);
1376 return 1;
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);
1387 CVector result;
1388 if (getEditor().getIslandCollision().findEmptyPlace(CVector2f((float) ls.toNumber(2), (float) ls.toNumber(3)), result))
1390 ls.push(result.x);
1391 ls.push(result.y);
1392 ls.push(result.z);
1393 return 3;
1395 return 0;
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();
1407 if (!island)
1409 ls.push(true);
1410 return 1;
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);
1416 return 1;
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() : "");
1427 return 1;
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");
1445 return 0;
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");
1463 return 0;
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));
1477 return 0;
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;
1490 return 0;
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 );
1501 return 1;
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
1514 ls.pushValue(3);
1515 CLuaObject poly;
1516 NLMISC::CPolygon2D poly2D;
1517 poly.pop(luaState);
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);
1528 return 1;
1531 // *********************************************************************************************************
1532 int CEditor::luaIsValidPosition(CLuaState &ls)
1534 CHECK_EDITOR
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);
1547 return 3;
1549 else
1551 // default z to 0
1552 ls.push(0.f);
1553 return 3;
1556 // new algo : to avoid to snapping to a cliff, start from the approximate (valid) height found in the height map
1557 CVector inter;
1558 if (CTool::computeWorldMapIntersection((float) ls.toNumber(2), (float) ls.toNumber(3), inter) != CTool::NoIntersection)
1560 ls.push(inter.x);
1561 ls.push(inter.y);
1562 ls.push(inter.z);
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());
1575 return 1;
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());
1585 return 1;
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
1594 if (UserEntity)
1596 string name = UserEntity->getEntityName()+PlayerSelectedHomeShardNameWithParenthesis;
1597 ls.push( name );
1599 else
1601 ls.push(std::string());
1604 return 1;
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();
1639 ++ ie->Current;
1640 return 1;
1643 ++ ie->Current;
1645 return 0;
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...
1655 return 0;
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);
1666 return 1;
1668 return 0;
1671 sint classIndex = getEditor().classToIndex(ls.toString(2));
1672 if (classIndex < 0)
1674 CLuaIHM::fails(ls, "Trying to iterate over unknown class : %s", ls.toString(2));
1676 ls.newTable();
1677 CLuaObject mt;
1678 mt.pop(ls);
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));
1686 #ifdef new
1687 #undef new
1688 #endif
1690 CInstanceEnumerator *ie = new (newIter) CInstanceEnumerator;
1692 #ifdef DEBUG_NEW
1693 #define new DEBUG_NEW
1694 #endif
1696 ie->InstMap = &getEditor()._InstancesByDispName[classIndex];
1697 ie->Current = ie->InstMap->begin();
1698 mt.push();
1699 ls.setMetaTable(-2);
1701 return 1;
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"));
1715 if (waitScreen)
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();
1739 for (;;)
1741 switch(state)
1743 case WaitingScenario:
1744 if (getEditor()._ScenarioReceivedFlag)
1746 if (getEditor()._WillTP)
1748 state = WaitingTP;
1750 else
1752 state = DoExit;
1755 break;
1756 case WaitingTP:
1757 // no-op
1758 break;
1759 default:
1760 nlassert(0);
1761 break;
1764 if (state == DoExit)
1766 break;
1769 // Update network.
1772 if ( ! firewallTimeout )
1773 NetMngr.update();
1775 catch (const EBlockedByFirewall&)
1777 if ( NetMngr.getConnectionState() == CNetManager::Disconnect )
1779 firewallTimeout = true;
1781 else
1783 // Display the firewall alert string
1784 CViewText *pVT = dynamic_cast<CViewText*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:r2ed_connecting:title"));
1785 if (pVT != NULL)
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);
1803 else
1805 // Send dummy info
1806 NetMngr.send();
1809 // update module manager
1810 NLNET::IModuleManager::getInstance().updateModules();
1813 // Update the DT T0 and T1 global variables
1814 updateClientTime();
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();
1831 if (waitScreen)
1833 CWidgetManager::getInstance()->setTopWindow(waitScreen);
1836 if (sysInfo) sysInfo->setActive(false);
1838 getUI().updateFrameViews(NULL);
1839 IngameDbMngr.flushObserverCalls();
1840 NLGUI::CDBManager::getInstance()->flushObserverCalls();
1842 // Movie shooter
1843 globalMenuMovieShooter();
1845 // Force the client to sleep a bit.
1846 if(ClientCfg.Sleep >= 0)
1848 nlSleep(ClientCfg.Sleep);
1852 if (!waitScreen)
1854 TextContext->setShaded(true);
1855 TextContext->setShadeOutline(false);
1856 TextContext->setFontSize(40);
1857 TextContext->setColor(CRGBA::White);
1859 // TOP LEFT //
1860 //----------//
1861 TextContext->setHotSpot(NL3D::UTextContext::MiddleMiddle);
1862 TextContext->printfAt(0.5f, 0.5f, "(UI NOT FOUND) Waiting scenario from server.");
1866 // Display
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"));
1875 if (pVT != NULL)
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);
1890 return;
1893 // *********************************************************************************************************
1894 // lua instance observer
1895 class CInstanceObserverLua : public CEditor::IInstanceObserver
1897 public:
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);
1909 private:
1910 CLuaObject _Receiver; // table that will receive the notifications
1911 static uint _Count;
1915 uint CInstanceObserverLua::_Count = 0;
1918 CInstanceObserverLua::CInstanceObserverLua(CLuaObject &receiver) : _Receiver(receiver)
1920 ++ _Count;
1923 CInstanceObserverLua::~CInstanceObserverLua()
1925 #ifdef NL_DEBUG
1926 nlassert(!getEditor().isInstanceObserver(this));
1927 #endif
1928 nlassert(_Count < 1000000000);
1929 -- _Count;
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)
2002 CHECK_EDITOR
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)));
2009 return 1;
2012 // *********************************************************************************************************
2013 int CEditor::luaRemoveInstanceObserver(CLuaState &ls)
2015 //H_AUTO(R2_CEditor_luaRemoveInstanceObserver)
2016 CHECK_EDITOR
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();
2032 delete luaObserver;
2033 receiver.push();
2034 return 1;
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;
2045 return false;
2049 // *********************************************************************************************************
2050 const CObjectTable *CEditor::getObjectTableFromId(const TInstanceId &id) const
2052 //H_AUTO(R2_CEditor_getObjectTableFromId)
2053 CHECK_EDITOR
2054 nlassert(_DMC);
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)
2065 CHECK_EDITOR
2066 if (!obj->isTable()) return NULL;
2067 TInstanceMap::const_iterator it = _Instances.find((CObjectTable *) obj);
2068 if (it != _Instances.end())
2070 return it->second;
2072 return NULL;
2076 // *********************************************************************************************************
2077 void CEditor::registerEnvMethod(const char *name,TLuaWrappedFunction func)
2079 //H_AUTO(R2_CEditor_registerEnvMethod)
2080 CHECK_EDITOR
2081 nlassert(name);
2082 getEnv().setValue(name, func);
2085 // *********************************************************************************************************
2086 void CEditor::registerEnvFunction(const char *name, TLuaWrappedFunction func)
2088 //H_AUTO(R2_CEditor_registerEnvFunction)
2089 CHECK_EDITOR
2090 nlassert(name);
2091 getEnv().setValue(name, func);
2095 // *********************************************************************************************************
2096 void CEditor::registerLuaFunc()
2098 //H_AUTO(R2_CEditor_registerLuaFunc)
2099 CHECK_EDITOR
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()
2152 CPolygon2D poly;
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)
2178 CHECK_EDITOR
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);
2186 reload = true;
2190 // *********************************************************************************************************
2191 void CEditor::loadKeySet(const std::string &keySet)
2193 //H_AUTO(R2_CEditor_loadKeySet)
2194 CHECK_EDITOR
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);
2211 else
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();
2228 if (actionManager)
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)
2246 CHECK_EDITOR
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)
2262 CHECK_EDITOR
2263 switch(mode)
2265 case EditionMode: return "keys_r2ed";
2266 case GoingToDMMode:
2267 case GoingToEditionMode:
2268 case AnimationModeLoading:
2269 case AnimationModeWaitingForLoading:
2270 case AnimationModeGoingToDm:
2271 case AnimationModeGoingToPlay:
2272 return "";
2273 case AnimationModePlay:
2274 return "keys";
2275 default:
2276 return "keys";
2278 return std::string();
2281 // *********************************************************************************************************
2282 void CEditor::setUIMode(uint8 mode)
2284 //H_AUTO(R2_CEditor_setUIMode)
2285 CHECK_EDITOR
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)
2303 getUI().setMode(0);
2304 // force to reload the standard interface
2305 ClientCfg.R2EDEnabled = false;
2306 loadUIConfig("");
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)
2327 switch(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;
2341 default:
2342 nlwarning("Setting mode to 'unknown'");
2343 break;
2346 if (mode != EditionMode)
2348 delete _EntitySorter;
2349 _EntitySorter = NULL;
2351 //H_AUTO(R2_CEditor_setMode)
2352 CHECK_EDITOR
2353 //nlassert(_ModeEnabled[mode]);
2354 if (mode == _Mode && !_ForceDesktopReset[mode]) return;
2357 if (mode != _Mode)
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)
2398 saveUIConfig();
2401 getEditor().getDMC().getEditionModule().askUpdateCharMode(TCharMode::Player);
2402 // if access mode is DM, then load the whole ui
2403 if (_AccessMode == AccessDM)
2405 loadStandardUI();
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();
2425 _Mode = mode;
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;
2434 switch(_Mode)
2437 case EditionMode:
2438 if (!_EntitySorter)
2440 _EntitySorter = new CEntitySorter;
2442 ActionsContext.setContext("r2ed");
2443 // set new mode in lua
2444 _Env.setValue("Mode", "Edit");
2445 setUIMode(0);
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();
2460 break;
2461 case TestMode:
2462 ActionsContext.setContext("r2ed_anim_test");
2463 // set new mode in lua
2464 _Env.setValue("Mode", "Test");
2465 setUIMode(1);
2466 ::IgnoreEntityDbUpdates = false;
2467 ::initContextualCursor();
2468 nlassert(CDisplayerBase::ObjCount == 0);
2469 resetPlotItems();
2470 break;
2471 case DMMode:
2472 ActionsContext.setContext("r2ed_anim_dm");
2473 // set new mode in lua
2474 _Env.setValue("Mode", "DM");
2475 setUIMode(2);
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();
2481 break;
2482 case GoingToDMMode:
2483 ActionsContext.setContext("waiting_network");
2484 // set new mode in lua
2485 _Env.setValue("Mode", "GoingToDM");
2486 setUIMode(3);
2487 connectionMsg(_ConnectionMsg); // update connection window
2488 ::IgnoreEntityDbUpdates = false;
2489 ::initContextualCursor();
2490 nlassert(CDisplayerBase::ObjCount == 0);
2491 resetPlotItems();
2492 break;
2493 case GoingToEditionMode:
2494 nlassert(CDisplayerBase::ObjCount == 0);
2495 ActionsContext.setContext("waiting_network");
2496 // set new mode in lua
2497 _Env.setValue("Mode", "BackToEditing");
2498 setUIMode(3);
2499 connectionMsg(_ConnectionMsg); // update connection window
2500 ::IgnoreEntityDbUpdates = true;
2501 ::initContextualCursor();
2502 resetPlotItems();
2503 break;
2505 case AnimationModeLoading:
2506 nlassert(CDisplayerBase::ObjCount == 0);
2507 ActionsContext.setContext("waiting_network");
2508 // set new mode in lua
2509 _Env.setValue("Mode", "AnimationModeLoading");
2510 setUIMode(3);
2511 connectionMsg(_ConnectionMsg); // update connection window
2512 // ::IgnoreEntityDbUpdates = true;
2513 ::initContextualCursor();
2514 resetPlotItems();
2515 break;
2517 case AnimationModeWaitingForLoading:
2518 nlassert(CDisplayerBase::ObjCount == 0);
2519 ActionsContext.setContext("waiting_network");
2520 // set new mode in lua
2521 _Env.setValue("Mode", "AnimationModeWaitingForLoading");
2522 setUIMode(3);
2523 connectionMsg(_ConnectionMsg); // update connection window
2524 // ::IgnoreEntityDbUpdates = true;
2525 ::initContextualCursor();
2526 resetPlotItems();
2527 break;
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");
2535 setUIMode(2);
2536 ::IgnoreEntityDbUpdates = false;
2537 ::initContextualCursor();
2538 resetPlotItems();
2539 break;
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
2551 hideRingWindows();
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();
2556 resetPlotItems();
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);
2562 else
2564 callEnvMethod("playerModeUIFix", 0, 0);
2567 break;
2569 case AnimationModeGoingToDm:
2570 nlassert(CDisplayerBase::ObjCount == 0);
2571 ActionsContext.setContext("waiting_network");
2572 //set new mode in lua
2573 _Env.setValue("Mode", "AnimationModeGoingToDM");
2574 setUIMode(3);
2575 connectionMsg(_ConnectionMsg); // update connection window
2576 ::IgnoreEntityDbUpdates = false;
2577 ::initContextualCursor();
2578 resetPlotItems();
2579 break;
2583 default:
2584 nlassert(0);
2585 break;
2587 ClientCfg.ManualWeatherSetup = false;
2588 ContextCur.context("STAND BY");
2589 _Mode = mode;
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");
2604 else
2606 GameContextMenu.init("");
2611 // *********************************************************************************************************
2612 void CEditor::hideRingWindows()
2614 //H_AUTO(R2_CEditor_hideRingWindows)
2615 static const char *ringWindows[] =
2617 "r2ed_palette",
2618 "r2ed_connect",
2619 "r2ed_property_sheet_no_selection",
2620 "r2ed_property_sheet_no_properties",
2621 "r2ed_bbox_edit",
2622 "r2ed_toolbar",
2623 "r2ed_windows_dm_bar",
2624 "r2ed_toolbar_window",
2625 "r2ed_windows_bar",
2626 "r2ed_main_bl",
2627 "r2ed_animation_loading",
2628 "r2ed_animation_waiting",
2629 "dm_controlled_entities",
2630 "r2ed_current_session",
2631 "r2ed_toolbar_admin",
2632 "lua_inspector",
2633 "r2ed_npc",
2634 "r2ed_select_bar",
2635 "r2ed_main_menu_button",
2636 "r2ed_contextual_toolbar_new",
2637 "feature_help",
2638 "r2ed_logic_entities",
2639 "r2ed_events",
2640 "r2ed_activities",
2641 "r2ed_edit_activity_sequence",
2642 "r2ed_dialogs",
2643 "r2ed_edit_chat_sequence",
2644 "r2ed_mini_activity_view",
2645 "r2ed_acts",
2646 "r2ed_connecting",
2647 "r2ed_scenario",
2648 "r2ed_dm_gift",
2649 "r2ed_scenario_filter",
2650 "r2ed_testbar"
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);
2656 if (grp)
2658 grp->setActive(false);
2660 else
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 ...
2677 CHECK_EDITOR
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
2700 switch (accessMode)
2702 case AccessEditor: _Env.setValue("AccessMode", "Editor"); break;
2703 case AccessDM: _Env.setValue("AccessMode", "DM"); break;
2704 case AccessOutlandOwner: _Env.setValue("AccessMode", "OutlandOwner"); break;
2705 default:
2706 nlassert(0);
2707 break;
2710 // Load the UI files
2711 if (ReloadUIFlag)
2713 loadLanguageFile();
2714 reloadUI();
2715 // setForceDesktopReset is done below
2716 ReloadUIFlag = false;
2720 registerDisplayers();
2721 registerTools();
2723 std::vector<std::string> emptyArgsList;
2724 // Calling window init proc
2725 registerLuaFunc();
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)
2747 initDecals();
2749 // TMP nico : unit test for newpoly stuff
2750 //polyUnitTest();
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)
2765 loadStandardUI();
2767 else
2769 configLoaded = loadUIConfig(getUIPrefix(initialMode));
2773 // if not found then reset all virtual desktops (one for each mode of the editor)
2774 if (!configLoaded)
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)
2794 switch(mode)
2796 case AnimationModePlay:
2797 return "";
2798 break;
2799 default:
2800 return "r2ed_interface_";
2801 break;
2805 // *********************************************************************************************************
2806 uint CEditor::getMaxNumPlotItems()
2808 //H_AUTO(R2_CEditor_getMaxNumPlotItems)
2809 uint ret;
2810 fromString( CWidgetManager::getInstance()->getParser()->getDefine("r2ed_max_num_plot_item_sheets"), ret);
2811 return 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);
2834 if (leaf)
2836 leaf->setValue32(sheetId);
2838 leaf = NLGUI::CDBManager::getInstance()->getDbProp(toString("LOCAL:R2:AVAILABLE_PLOT_ITEMS:%d:SHEET", (int) index), false);
2839 if (leaf)
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);
2851 uint k;
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);
2890 uint currIndex = 0;
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);
2902 ++ currIndex;
2906 for (; currIndex < maxNumPlotItems; ++currIndex)
2908 setReferencePlotItemSheet(currIndex, 0);
2910 resetPlotItems();
2915 // *********************************************************************************************************
2916 bool CEditor::loadUIConfig(const std::string &prefix)
2918 //H_AUTO(R2_CEditor_loadUIConfig)
2919 CHECK_EDITOR
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)
2932 CHECK_EDITOR
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])
2942 setUIMode(k);
2943 restoreMode = true;
2944 _ForceDesktopReset[k] = false;
2946 if (restoreMode)
2948 setUIMode(oldMode);
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)
2965 CHECK_EDITOR
2966 // highlight
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);
2981 CPrimLook boxLook;
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)
2994 CHECK_EDITOR
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;
3012 dest.setLook(pl);
3013 dest.addDecalsToRenderList();
3014 static volatile bool showPoly = true;
3015 if (showPoly)
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)
3025 CHECK_EDITOR
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)
3034 CHECK_EDITOR
3035 showPrimRender(_HighlightBox, localBox, worldMat, _HighlightDecalAnim);
3038 // *********************************************************************************************************
3039 void CEditor::showSelectDecal(const NLMISC::CVector &pos, float scale)
3041 //H_AUTO(R2_CEditor_showSelectDecal)
3042 CHECK_EDITOR
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)
3052 CHECK_EDITOR
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)
3061 CHECK_EDITOR
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)
3072 CHECK_EDITOR
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];
3080 break;
3083 if (decal == NULL)
3085 _SelectingDecals.push_back(new CSelectingDecal);
3086 decal = _SelectingDecals.back();
3088 decal->EndDate = T1 + _SelectingDecalAnim.DurationInMs;
3089 decal->Pos = pos;
3090 decal->Scale = scale;
3092 updateDecalBlendRegion(decal->Decal, pos);
3093 _DecalRefTime = T1;
3096 // *********************************************************************************************************
3097 void CEditor::updateSelectingDecals()
3099 //H_AUTO(R2_CEditor_updateSelectingDecals)
3100 CHECK_EDITOR
3101 if (_SelectingDecalAnim.DurationInMs == 0) return;
3102 for(uint k = 0; k < _SelectingDecals.size(); ++k)
3104 CSelectingDecal *decal = _SelectingDecals[k];
3105 if (decal)
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 ..."));
3124 CHECK_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");
3134 else
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\")");
3147 release();
3148 clearDebugWindow();
3149 if (ReloadUIFlag)
3151 loadLanguageFile();
3152 reloadUI();
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"));
3169 // Show the window
3170 Driver->showWindow();
3173 getUI().displaySystemInfo(CI18N::get("uiR2EDEditorReseted"), "BC");
3176 // *********************************************************************************************************
3177 void CEditor::reloadUI()
3179 //H_AUTO(R2_CEditor_reloadUI)
3180 CHECK_EDITOR
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)
3193 CHECK_EDITOR
3194 CVerboseClock clock("Loading ui " + std::string(filename));
3195 CLuaStackChecker ls(&getLua());
3197 std::string path = CPath::lookup(filename, false);
3198 if (path.empty())
3200 nlwarning("File %s not found, r2 ui not (re)loaded.", filename);
3201 return;
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;
3215 else
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)
3230 CHECK_EDITOR
3231 nlassert(_DMC);
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)
3257 CHECK_EDITOR
3258 _ObjectProjectionMetatable = getEnv().newTable("_instance_projection_metatable");
3259 // projection functions
3261 struct CProjector
3263 static bool checkTag(CLuaState &ls)
3265 CLuaStackChecker lsc(&ls);
3266 ls.getMetaTable(1);
3267 ls.push("tag");
3268 ls.getTable(-2);
3269 bool ok = false;
3270 if (ls.isString(-1))
3272 if (strcmp(ls.toString(-1), "CObjectTable") == 0)
3274 ok = true;
3277 ls.pop(2);
3278 if (!ok)
3280 nlwarning("metatable error : Editor object expected");
3282 return ok;
3285 static int index(CLuaState &ls)
3287 nlassert(ls.getTop() == 2);
3288 #ifdef NL_DEBUG
3289 if (!checkTag(ls)) return false;
3290 #endif
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);
3296 // special members
3297 if ( index == "isNil")
3298 //if (std::operator==(index "isNil")
3300 ls.push(true);
3301 return 1;
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));
3312 if (other)
3314 pushValue(ls, other);
3315 return 1;
3317 else
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);
3328 return 0;
3331 const char *strId = ls.toString(2); // strings are shared in lua, so a pointer comparison is sufficient
3333 // special members
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))
3339 ls.push(false);
3340 return 1;
3342 else
3343 if (OPERATOR_EQUAL(strId, lstr_Parent))
3345 if (!obj->getParent())
3347 ls.pushNil();
3348 return 1;
3350 nlassert(obj->getParent()->isTable());
3351 getEditor().projectInLua((CObjectTable *) obj->getParent());
3352 return 1;
3354 else if (OPERATOR_EQUAL(strId, lstr_ParentInstance))
3356 // look for parent instance (that is, not the
3357 CObject *parent = obj->getParent();
3358 while (parent)
3360 if (parent->findAttr("InstanceId"))
3362 getEditor().projectInLua((CObjectTable *) parent);
3363 return 1;
3365 parent = parent->getParent();
3367 ls.pushNil();
3368 return 1;
3370 if (OPERATOR_EQUAL(strId, lstr_IndexInParent))
3372 if (!obj->getParent())
3374 ls.pushNil();
3375 return 1;
3377 sint32 index = obj->getParent()->findIndex(obj);
3378 if (obj->getParent()->getKey(index).empty())
3380 ls.push(index);
3382 else
3384 ls.push(-1);
3386 return 1;
3388 else if (OPERATOR_EQUAL(strId, lstr_User))
3390 // push user table on stack
3391 CEditor::getLuaUserTableFromObject(ls, *obj);
3392 return 1;
3394 else if (OPERATOR_EQUAL(strId, lstr_Size))
3396 if (obj->isTable())
3398 ls.push(obj->getSize());
3400 else
3402 ls.pushNil();
3404 return 1;
3406 else
3407 if (OPERATOR_EQUAL(strId, lstr_DisplayerUI))
3409 CInstance *instance = getEditor().getInstanceFromObject(obj);
3410 if (!instance)
3412 ls.pushNil();
3413 return 1;
3415 else
3417 if (instance->getDisplayerUI())
3419 instance->getDisplayerUI()->pushLuaAccess(ls);
3421 else
3423 ls.pushNil();
3425 return 1;
3428 else
3429 if (OPERATOR_EQUAL(strId, lstr_DisplayerVisual))
3431 CInstance *instance = getEditor().getInstanceFromObject(obj);
3432 if (!instance)
3434 ls.pushNil();
3435 return 1;
3437 else
3439 if (instance->getDisplayerVisual())
3441 instance->getDisplayerVisual()->pushLuaAccess(ls);
3443 else
3445 ls.pushNil();
3447 return 1;
3450 else
3451 if (OPERATOR_EQUAL(strId, lstr_DisplayerProperties))
3453 CInstance *instance = getEditor().getInstanceFromObject(obj);
3454 if (!instance)
3456 ls.pushNil();
3457 return 1;
3459 else
3461 if (instance->getDisplayerProperties())
3463 instance->getDisplayerProperties()->pushLuaAccess(ls);
3465 else
3467 ls.pushNil();
3469 return 1;
3472 // else tries with a string
3473 std::string index = ls.toString(2);
3474 const CObject *other = getObject(obj, index);
3475 if (other)
3477 pushValue(ls, other);
3478 return 1;
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");
3487 if (className)
3489 CLuaObject method = getEditor().getClasses()[className->toString()][index];
3490 if (method.isFunction())
3492 method.push();
3493 return 1;
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);
3502 if (instance)
3504 const CReflectedProperty *prop = instance->getReflectedProperty(index, false);
3505 if (prop)
3507 CLuaIHM::luaValueFromReflectedProperty(ls, *instance, *prop);
3508 return 1;
3512 // unknown attribute
3513 ls.pushNil();
3514 return 1;
3516 static int newIndex(CLuaState &ls)
3518 nlassert(ls.getTop() == 3);
3519 #ifdef NL_DEBUG
3520 if (!checkTag(ls)) return false;
3521 #endif
3522 CObjectTable::TRefPtrConst &obj= *(CObjectTable::TRefPtrConst *) ls.toUserData(1);
3523 if (obj == NULL)
3525 throw ELuaWrappedFunctionException(&ls, "Trying to set a property in an erased object, returning nil");
3527 #ifdef NL_DEBUG
3528 if (!checkTag(ls)) return false;
3529 #endif
3530 // try with a native (local ..) property exported from CInstance
3531 CInstance *instance = getEditor().getInstanceFromObject(obj);
3532 if (instance)
3534 const CReflectedProperty *prop = instance->getReflectedProperty(ls.toString(2));
3535 if (prop)
3537 CLuaIHM::luaValueToReflectedProperty(ls, 3, *instance, *prop);
3538 return 1;
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)
3546 #ifdef NL_DEBUG
3547 if (!checkTag(ls)) return false;
3548 #endif
3549 // TODO : maybe not useful ...
3550 CObjectTable::TRefPtrConst &obj= *(CObjectTable::TRefPtrConst *) ls.toUserData(1);
3551 typedef CObjectTable::TRefPtrConst TRefPtrConst;
3552 obj.~TRefPtrConst();
3553 return 0;
3555 // tool function used by 'next'
3556 // TODO : put this code in a better place ...
3557 static void pushValue(CLuaState &ls, const CObject *obj)
3559 if (!obj)
3561 ls.pushNil();
3562 return;
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);
3580 else
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)
3589 if (!obj)
3591 ls.pushNil();
3592 return;
3594 if (obj->getKey(index).empty())
3596 ls.push(index);
3598 else
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)");
3618 #ifdef NL_DEBUG
3619 if (!checkTag(ls)) return false;
3620 #endif
3621 CObjectTable::TRefPtrConst &obj= *(CObjectTable::TRefPtrConst *) ls.toUserData(1);
3622 if (obj == NULL)
3624 throw ELuaWrappedFunctionException(&ls, "editor object '__next' metatmethod : Attempt to access an erased object");
3626 if (ls.isNil(2))
3628 // key is nil -> start of traversal
3629 if(obj->getSize() == 0)
3631 ls.remove(-2);
3632 ls.pushNil();
3633 return 2; // let (nil, nil) on the stack
3635 else
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);
3642 if (!key.empty())
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.");
3651 keys.insert(key);
3654 ls.pop(2);
3655 pushKey(ls, obj, 0);
3656 pushValue(ls, obj->getValueAtPos(0));
3657 return 2;
3660 else
3662 // continuation of traversal
3663 // -> retrieve index from the key
3664 sint32 index;
3665 if (ls.isInteger(2))
3667 index = (uint32) ls.toInteger(2);
3669 else
3671 if (!ls.isString(2))
3673 nlwarning("__next metamethod : string expected");
3674 ls.pop();
3675 ls.pushNil();
3676 return 2;
3678 else
3680 index = obj->findIndex(ls.toString(2));
3683 if (index == -1)
3685 nlwarning("__next metamethod : key not found");
3686 ls.pop(2);
3687 ls.pushNil();
3688 ls.pushNil();
3689 return 2;
3691 // retrieve next key
3692 sint32 newIndex = (uint32) (index + 1);
3693 if (newIndex == (sint32) obj->getSize())
3695 // this was the last element, returns nil
3696 ls.pop(2);
3697 ls.pushNil();
3698 ls.pushNil();
3699 return 2;
3701 else
3703 ls.pop(2);
3704 pushKey(ls, obj, newIndex);
3705 pushValue(ls, obj->getValueAtPos(newIndex));
3706 return 2;
3709 return 0;
3711 static int equal(CLuaState &ls)
3713 // TMP TMP TMP
3714 static volatile bool from = false;
3715 if (from)
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));
3724 return 1;
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)
3746 CHECK_EDITOR
3747 CLuaStackChecker lsc(&ls, 1);
3748 // read write environement accessible from lua
3749 ls.pushLightUserData((void *) &table);
3750 ls.getTable(LUA_REGISTRYINDEX);
3751 if (ls.isNil())
3753 ls.pop();
3754 // no user table created yet ?... create it
3755 ls.pushLightUserData((void *) &table);
3756 ls.newTable();
3757 ls.pushValue(-1); // saves the table
3758 ls.insert(-3);
3759 ls.setTable(LUA_REGISTRYINDEX);
3760 // table remains on the stack
3764 // *********************************************************************************************************
3765 void CEditor::setCurrentAct(CInstance *act)
3767 //H_AUTO(R2_CEditor_setCurrentAct)
3768 CHECK_EDITOR
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);
3793 //TP if necesary
3796 // warn lua that current act has changed
3797 if (!previousAct)
3799 getLua().pushNil();
3801 else
3803 previousAct->getLuaProjection().push();
3806 if (!_CurrentAct)
3808 getLua().pushNil();
3810 else
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)
3827 CHECK_EDITOR
3828 if (!_Scenario)
3830 nlwarning("Scenario initialisation failed, can't set current act");
3831 return;
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);
3839 nlassert(act);
3840 std::string actTitle;
3841 if (act->isString("Name"))
3843 actTitle = act->toString("Name");
3845 else
3847 actTitle = act->toString("Title"); //obsolete
3850 if (actTitle == wantedTitle)
3852 setCurrentAct(getInstanceFromObject(act));
3853 break;
3857 else
3859 nlwarning("'Acts' field in scenario should be a table");
3863 // *********************************************************************************************************
3864 void CEditor::projectInLua(const CObjectTable *table)
3866 //H_AUTO(R2_CEditor_projectInLua)
3867 CHECK_EDITOR
3868 nlassert(table);
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);*/
3899 return 0;
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;
3947 CHECK_EDITOR
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;
3960 eraseScenario();
3962 _InstancesByDispName.clear();
3963 _InstancesByDispName.resize(_ClassNameToIndex.size());
3964 _InstanceObservers.clear();
3965 _InstanceObserverHandles.clear();
3966 _Cookies.clear();
3967 _LocalGeneratedNames.clear();
3968 _Instances.clear();
3969 _BaseAct = NULL;
3970 _CurrentAct = NULL;
3971 _SelectedInstance = NULL;
3972 _FocusedInstance = NULL;
3973 _ScenarioInstance = NULL;
3974 _Scenario = 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;
4006 return &it->second;
4010 // *********************************************************************************************************
4011 void CEditor::release()
4013 nlwarning("*R2* release");
4014 //H_AUTO(R2_CEditor_release)
4015 GameContextMenu.init("");
4016 setFixedLighting(false);
4017 CHECK_EDITOR
4019 if (_Mode == NotInitialized)
4021 // nothing more to do there
4022 return;
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();
4032 saveUIConfig();
4034 CWidgetManager::getInstance()->hideAllWindows(); // make sure all action handlers are called while the r2 lua environment is still active
4035 clearContent();
4036 _EntityCustomSelectBoxMap.clear();
4038 // must do this after clearContent, which sets the default tool
4039 if (_CurrentTool)
4041 _CurrentTool->cancel();
4042 _CurrentTool = NULL;
4045 // clear the environment
4046 if (CLuaManager::getInstance().getLuaState())
4048 getLua().pushGlobalTable();
4049 getLua().push(R2_LUA_PATH);
4050 getLua().pushNil();
4051 getLua().setTable(-3); // pop pop
4052 getLua().pop();
4053 _Globals.release();
4054 _Registry.release();
4055 _ObjectProjectionMetatable.release(); // AJM
4056 _Env.release();
4057 _Config.release();
4058 CEditorCheck::EditorCreated = false;
4059 // force a garbage collection to free the mem for real
4060 getLua().setGCThreshold(0);
4064 // stop at login
4065 if (_DMC)
4067 _DMC->release();
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)
4094 CHECK_EDITOR
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)
4108 CHECK_EDITOR
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)
4116 registered = true;
4119 // *********************************************************************************************************
4120 void CEditor::registerTools()
4122 //H_AUTO(R2_CEditor_registerTools)
4123 CHECK_EDITOR
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);
4130 registered = true;
4135 // *********************************************************************************************************
4136 void CEditor::setSelectedInstance(CInstance *inst)
4138 //H_AUTO(R2_CEditor_setSelectedInstance)
4139 CHECK_EDITOR
4140 if (inst == _SelectedInstance) return;
4141 forceSetSelectedInstance(inst);
4144 // *********************************************************************************************************
4145 void CEditor::forceSetSelectedInstance(CInstance *inst)
4147 //H_AUTO(R2_CEditor_forceSetSelectedInstance)
4148 CHECK_EDITOR
4149 if (_EnteredInSetSelectedInstance) return; // prevent recursive call (may happen because selection highlight an item in a menu, which trigger selection in turn)
4151 if (inst)
4153 nlassert(inst->getSelectableFromRoot());
4156 _EnteredInSetSelectedInstance = true;
4157 if (inst)
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)
4174 getLua().pushNil();
4176 else
4178 _SelectedInstance->getLuaProjection().push();
4180 callEnvMethod("onSelectInstance", 1, 0);
4181 _EnteredInSetSelectedInstance = false;
4185 // *********************************************************************************************************
4186 CInstance *CEditor::getSelectedInstance() const
4188 //H_AUTO(R2_CEditor_getSelectedInstance)
4189 CHECK_EDITOR
4190 return _SelectedInstance;
4193 // *********************************************************************************************************
4194 void CEditor::setFocusedInstance(CInstance *inst)
4196 //H_AUTO(R2_CEditor_setFocusedInstance)
4197 CHECK_EDITOR
4198 if (inst == _FocusedInstance) return;
4199 if (inst)
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)
4218 CHECK_EDITOR
4219 return _FocusedInstance;
4223 // *********************************************************************************************************
4224 bool CEditor::hasInstance(const CInstance *instance) const
4226 //H_AUTO(R2_CEditor_hasInstance)
4227 CHECK_EDITOR
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;
4233 return false;
4236 // *********************************************************************************************************
4237 bool CEditor::hasInstanceWithId(const TInstanceId &id) const
4239 //H_AUTO(R2_CEditor_hasInstanceWithId)
4240 CHECK_EDITOR
4241 return getInstanceFromId(id) != NULL;
4244 // *********************************************************************************************************
4245 CInstance *CEditor::getInstanceFromId(const TInstanceId &id) const
4247 //H_AUTO(R2_CEditor_getInstanceFromId)
4248 CHECK_EDITOR
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)
4258 CHECK_EDITOR
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();
4265 if (*strIt == ' ')
4267 ++ strIt;
4268 const char *numberStart = &*strIt;
4269 for (; strIt != endStrIt && (uint8)(*strIt) < (uint8)'\x80' && isdigit(*strIt); ++strIt) {}
4270 if (strIt == endStrIt)
4272 sint ret;
4273 fromString(numberStart, ret);
4274 return ret;
4279 return -1;
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)) &&
4292 currChar != ' ' &&
4293 currChar != '\t')
4295 break;
4297 -- lastIndex;
4299 return lastIndex != (sint) baseName.length() - 1;
4302 // *********************************************************************************************************
4303 ucstring CEditor::genInstanceName(const ucstring &baseName)
4305 //H_AUTO(R2_CEditor_genInstanceName)
4306 CHECK_EDITOR
4307 uint maxIndex = 0;
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)) &&
4315 currChar != ' ' &&
4316 currChar != '\t')
4318 break;
4320 -- lastIndex;
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
4334 // cf RT 11560
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)
4355 CHECK_EDITOR
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
4359 cookie.Key = key;
4360 cookie.Value = value;
4363 // *********************************************************************************************************
4364 void CEditor::setCookie(const TInstanceId &instanceId, const std::string &key, bool value)
4366 //H_AUTO(R2_CEditor_setCookie)
4367 CHECK_EDITOR
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)
4377 CHECK_EDITOR
4378 if (_CurrentTool)
4380 _CurrentTool->cancel();
4382 else
4384 if (tool)
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(""));
4393 if (tool == NULL)
4395 if (_Mode == EditionMode)
4397 _CurrentTool = new CToolSelectMove;
4399 else
4401 _CurrentTool = NULL;
4402 ContextCur.release();
4403 ::initContextualCursor();
4404 ContextCur.context("STAND BY");
4405 CTool::setMouseCursor(DEFAULT_CURSOR);
4408 else
4410 _CurrentTool = tool;
4412 if (_CurrentTool)
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)
4428 CHECK_EDITOR
4429 return getEnv().at("Classes");
4433 // *********************************************************************************************************
4434 bool CEditor::callEnvFunc(const char *funcName, int numArgs, int numRet /*=0*/)
4436 //H_AUTO(R2_CEditor_callEnvFunc)
4437 CHECK_EDITOR
4438 static volatile bool dumpStackWanted = false;
4439 if (dumpStackWanted) getLua().dumpStack();
4440 nlassert(funcName);
4441 nlassert(getLua().getTop() >= numArgs);
4442 int initialStackSize = getLua().getTop();
4443 getEnv().push();
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();
4449 if (result != 0)
4451 nlwarning("Error while calling function %s : %s", funcName, getLua().toString());
4452 getLua().setTop(initialStackSize - numArgs + numRet); // clean the stack
4453 return false;
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)
4469 CHECK_EDITOR
4470 nlassert(funcName);
4471 nlassert(getLua().getTop() >= numArgs);
4472 getEnv().push();
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)
4481 CHECK_EDITOR
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);
4488 return false;
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());
4499 return false;
4506 if (!getLua().executeFile(filePath))
4508 nlwarning("Couldn't open file %s : %s for R2 is not loaded", filename, fileDescText);
4510 CLuaStackChecker ls(&getLua());
4511 return true;
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
4526 int line;
4527 fromString(&*(msg.begin() + extPos + 5), line); // line number follows
4528 nlwarning((CLuaIHMRyzom::createGotoFileButtonTag(filename.c_str(), line) + e.what()).c_str());
4530 else
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());
4536 return false;
4542 ///////////////////////
4543 // CONTEXTUAL CURSOR //
4544 ///////////////////////
4548 // *********************************************************************************************************
4549 void CEditor::checkCursor()
4551 //H_AUTO(R2_CEditor_checkCursor)
4552 CHECK_EDITOR
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)
4561 CHECK_EDITOR
4562 CTool *currentTool = getEditor().getCurrentTool();
4563 if (!currentTool) return;
4564 if (!rightButton)
4566 // nb : result not handled there (no defaut action for left click)
4567 currentTool->onMouseLeftButtonClicked();
4569 else
4571 bool handled = currentTool->onMouseRightButtonClicked();
4572 if (!handled)
4574 getEditor().displayContextMenu();
4581 // *********************************************************************************************************
4582 void CEditor::updatePreCamera()
4584 //H_AUTO(R2_CEditor_updatePreCamera)
4586 if (_Mode == EditionMode)
4588 static uint32 loop = 0;
4589 ++loop;
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
4594 autoSave();
4596 loop = 0;
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"));
4603 else
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
4616 bool ok = false;
4617 for(uint k = 0; k < _LastContextualPrims.size(); ++k)
4619 if (_LastContextualPrims[k] == _SelectedInstance ||
4620 _SelectedInstance->isSonOf(_LastContextualPrims[k])
4623 ok = true;
4624 break;
4627 _LastContextualPrims.clear();
4628 bool isLogicEntity = _SelectedInstance->isKindOf("LogicEntity");
4629 if (!ok && !isLogicEntity) return;
4630 if (isLogicEntity)
4632 _LastContextualLogicEntity = _SelectedInstance;
4634 if (!_LastContextualLogicEntity) return;
4636 CObject *seq = _LastContextualLogicEntity->getGroupSelectedSequence();
4637 if (!seq) return;
4638 if (seq)
4640 CObjectTable *activities = seq->toTable("Components");
4641 if (activities)
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);
4651 if (primitive)
4653 CDisplayerVisualGroup *primDisp = dynamic_cast<CDisplayerVisualGroup *>(primitive->getDisplayerVisual());
4654 if (primDisp)
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)
4676 CHECK_EDITOR
4678 _IslandCollision.updateCurrPackedIsland();
4679 // update contextual visibility of primitive from current selection
4680 updatePrimitiveContextualVisibility();
4682 if (ConnectionWanted) return; // TMP special case for connection
4683 if (_CurrentTool)
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
4696 if (UserEntity)
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);
4709 else
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)
4732 CHECK_EDITOR
4733 if (_WaitScenarioScreenWanted)
4735 waitScenario();
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();
4766 CHECK_EDITOR
4767 if (ConnectionWanted)
4769 connect();
4770 return;
4773 if (_CurrentTool)
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 )
4839 CHECK_EDITOR
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);
4851 return true;
4855 if (_CurrentTool)
4857 return _CurrentTool->handleEvent(eventDesc);
4859 return false;
4862 // *********************************************************************************************************
4863 void CEditor::copy()
4865 //H_AUTO(R2_CEditor_copy)
4866 // forward to lua
4867 callEnvMethod("copy", 0);
4870 // *********************************************************************************************************
4871 void CEditor::paste()
4873 //H_AUTO(R2_CEditor_paste)
4874 // forward to lua
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)
4910 CHECK_EDITOR
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);
4922 if (!entity)
4924 nlwarning("Can't create entity");
4925 return NULL;
4928 // Set the permanent statut icon
4929 entity->setPermanentStatutIcon(permanentStatutIcon);
4931 // TMP TMP : code taken from /entity command
4932 sint64 *prop = 0;
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);
4936 if(node)
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);
4943 if(node)
4945 node->setValue64(y);
4946 node = NLGUI::CDBManager::getInstance()->getDbProp("SERVER:Entities:E"+toString("%d", slot)+":P"+toString("%d", CLFECOMMON::PROPERTY_POSZ), false);
4947 if(node)
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);
4953 if(node)
4955 C64BitsParts parts;
4956 parts.f[0] = heading;
4957 parts.f[1] = 0.f;
4958 node->setValue64(parts.i64[0]);
4960 // Set Mode
4961 node = NLGUI::CDBManager::getInstance()->getDbProp("SERVER:Entities:E"+toString("%d", slot)+":P"+toString("%d", CLFECOMMON::PROPERTY_MODE), false);
4962 if(node)
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;
4995 // old colors
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
5011 sint64 *propB = 0;
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);
5016 // Apply Changes.
5017 EntitiesMngr.updateVisualProperty(0, slot, CLFECOMMON::PROPERTY_VPA);
5018 EntitiesMngr.updateVisualProperty(0, slot, CLFECOMMON::PROPERTY_VPB);
5020 return entity;
5023 // *********************************************************************************************************
5024 CInstance *CEditor::getInstanceFromEntity(CEntityCL *entity) const
5026 //H_AUTO(R2_CEditor_getInstanceFromEntity)
5027 CHECK_EDITOR
5028 for(TInstanceMap::const_iterator it = _Instances.begin(); it != _Instances.end(); ++it)
5030 if (it->second->getEntity() == entity) return it->second;
5032 return NULL;
5035 // *********************************************************************************************************
5036 void CEditor::displayContextMenu()
5038 //H_AUTO(R2_CEditor_displayContextMenu)
5039 CHECK_EDITOR
5040 if (!_SelectedInstance)
5042 // launch standard context menu (for free look & move options)
5043 getUI().launchContextMenuInGame("ui:interface:game_context_menu_edition");
5044 return;
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");
5055 return;
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;
5081 dest.clear();
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;
5106 CHECK_EDITOR
5107 if (!root) return;
5108 CInstance *inst = getInstanceFromObject(root);
5109 // sons
5110 if (root->isTable())
5112 for(uint k = 0; k < root->getSize(); ++k)
5114 CObject *obj = root->getValueAtPos(k);
5115 if (obj->isTable())
5117 onErase(obj);
5122 CObject *parent = NULL;
5124 if (inst)
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();
5152 if (parent)
5154 sint32 sonIndex = parent->findIndex(root);
5155 if (sonIndex != -1)
5157 nameInParent = parent->getKey(sonIndex);
5158 if (!nameInParent.empty() && getDMC().getPropertyAccessor().hasValueInBase(parent, nameInParent))
5160 foundInBase = true;
5165 if (inst && !foundInBase)
5167 // send event to instance & displayers
5168 inst->onErase();
5169 // trigger observers
5170 class CEraseNotification : public IObserverAction
5172 public:
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
5185 if (inst)
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
5196 getLua().pop();
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);
5207 if (objRefId)
5209 objRefId->enable(false); // don't observe anything
5214 if (!_ClearingContent)
5216 if (inst)
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);
5224 if (inst)
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)
5235 CHECK_EDITOR
5236 CObject *obj = _DMC->find(instanceId, attrName, position);
5237 if (!obj) return;
5238 bool foundInBase;
5239 std::string nameInParent;
5240 onErase(obj, foundInBase, nameInParent);
5241 CObject *parent = obj->getParent();
5242 _DMC->CDynamicMapClient::nodeErased(instanceId, attrName, position);
5243 if (foundInBase)
5245 nlassert(parent);
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);
5249 if (parentInstance)
5251 onAttrModified(*parentInstance, nameInParent);
5253 else
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)
5268 CHECK_EDITOR
5269 // called when a scenario just before a scenario is created
5270 // no-op, to clean
5273 void CEditor::onEditionModeConnected( uint32 userSlotId, uint32 adventureId, CObject* highLevel, const std::string& versionName, bool willTP, uint32 initialActIndex)
5275 //H_AUTO(R2_CEditor_onEditionModeConnected)
5276 CHECK_EDITOR
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"));
5285 if (text)
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)
5297 _AccessMode = mode;
5298 switch ( mode)
5300 case AccessEditor: _Env.setValue("AccessMode", "Editor"); break;
5301 case AccessDM:
5302 _Env.setValue("AccessMode", "DM");
5303 if (_Mode == AnimationModePlay)
5305 loadStandardUI();
5307 break;
5308 case AccessOutlandOwner: _Env.setValue("AccessMode", "OutlandOwner"); break;
5309 default:
5310 nlassert(0);
5311 break;
5315 void CEditor::onAnimationModeConnected(const CClientMessageAdventureUserConnection& connected)
5317 //H_AUTO(R2_CEditor_onAnimationModeConnected)
5318 _ScenarioReceivedFlag = true; // end wait screen
5319 // TMP PATCH
5320 // _WillTP = true;
5321 CHECK_EDITOR
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"));
5336 if (text)
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;
5351 CHECK_EDITOR
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)
5368 CHECK_EDITOR
5369 // TODO nico : change the name of the function : should rather be 'onAnimationModeConnected'
5370 // start as a GM
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)
5378 CHECK_EDITOR
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)
5386 CHECK_EDITOR
5387 _DMC->CDynamicMapClient::nodeInserted(instanceId, attrName, position, key, value);
5388 if (value->isTable())
5390 std::string id = getString(value, "InstanceId");
5391 if (!id.empty())
5393 const CObject *clonedValue = _DMC->find(id);
5394 // bad insert
5395 if (clonedValue)
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)
5412 CHECK_EDITOR
5413 createNewInstanceForObjectTableInternal(obj);
5414 onPostCreate(obj);
5417 // *********************************************************************************************************
5418 void CEditor::notifyInstanceObserversOfCreation(CInstance &inst)
5420 //H_AUTO(R2_CEditor_notifyInstanceObserversOfCreation)
5421 CHECK_EDITOR
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
5427 public:
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)
5443 CHECK_EDITOR
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);
5450 if (inst)
5452 inst->onPostCreate();
5453 getEditor().notifyInstanceObserversOfCreation(*inst);
5457 if (obj)
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))
5473 ls.pop(1);
5474 return 0;
5476 sint result = (sint) ls.toInteger(-1);
5477 ls.pop(1);
5478 return result;
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();
5503 if (aiCost)
5505 CLuaStackChecker lsc(&ls);
5506 getEditor().getLua().push(aiCost);
5507 callEnvMethod("checkAiQuota", 1, 1);
5508 if (!ls.isBoolean(-1))
5510 ls.pop(1);
5511 return false;
5513 sint result = (sint) ls.toBoolean(-1);
5514 ls.pop(1);
5515 return result != 0;
5517 if (staticCost)
5519 CLuaStackChecker lsc(&ls);
5520 getEditor().getLua().push(staticCost);
5521 callEnvMethod("checkStaticQuota", 1, 1);
5522 if (!ls.isBoolean(-1))
5524 ls.pop(1);
5525 return false;
5527 sint result = (sint) ls.toBoolean(-1);
5528 ls.pop(1);
5529 return result != 0;
5531 return true;
5537 // *********************************************************************************************************
5538 void CEditor::createNewInstanceForObjectTableInternal(const CObject *obj)
5540 //H_AUTO(R2_CEditor_createNewInstanceForObjectTableInternal)
5541 CHECK_EDITOR
5542 if (!obj) return;
5543 if (!obj->isTable()) return; // not a table ...
5544 const CObjectTable *table = (const CObjectTable *) obj;
5545 std::string id = getString(obj, "InstanceId");
5546 if (!id.empty())
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())
5556 if (obj->isTable())
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());
5574 if (dispViz)
5576 bool ok = dispViz->init(classDesc["DisplayerVisualParams"]);
5577 if (!ok)
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());
5585 if (dispUI)
5587 bool ok = dispUI->init(classDesc["DisplayerUIParams"]);
5588 if (!ok)
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());
5596 if (dispProp)
5598 bool ok = dispProp->init(classDesc["DisplayerPropertiesParams"]);
5599 if (!ok)
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();
5608 inst->onCreate();
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);
5619 if (index != -1)
5621 it->second.erase(index);
5622 break;
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
5642 public:
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)
5661 CHECK_EDITOR
5662 if (!value) return;
5663 const CObject *son = value;
5664 const CObject *parent = value->getParent();
5665 sint32 indexInArray = -1;
5666 while (parent)
5668 CInstance *parentInstance = getInstanceFromObject(parent);
5669 sint32 indexInParent = parent->findIndex(son);
5670 nlassert(indexInParent != -1);
5671 if (parentInstance)
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);
5677 indexInArray = -1;
5679 else
5681 // we are in an array in an instance -> memorize index in that array for next call to "onAttrModified"...
5682 indexInArray = indexInParent;
5684 son = parent;
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)
5694 CHECK_EDITOR
5695 CObject *obj = _DMC->find(instanceId);
5696 if (!obj) return;
5697 // erase previous object
5698 nlassert(obj->isTable());
5700 if (!attrName.empty())
5702 obj = obj->findAttr(attrName);
5704 if (obj)
5706 onErase(obj);
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");
5717 if (!id.empty())
5719 const CObject *clonedValue = _DMC->find(id);
5720 if (clonedValue)
5722 createNewInstanceForObjectTable(clonedValue); // if the created object is a table, warn him that he has been created
5723 onAttrModified(clonedValue);
5724 return;
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)
5738 if (_Scenario)
5741 backupRequestCommands();
5742 onErase(_Scenario);
5743 restoreRequestCommands();
5744 _Scenario = NULL;
5749 // *********************************************************************************************************
5750 void CEditor::scenarioUpdated(CObject* highLevel, bool willTP, uint32 initialActIndex)
5752 //H_AUTO(R2_CEditor_scenarioUpdated)
5753 CHECK_EDITOR
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;
5763 return;
5766 if (!highLevel)
5768 _IsStartingScenario = false;
5769 _WillTP = false;
5770 callEnvFunc("onEmptyScenarioUpdated", 0);
5771 return;
5774 // _WillTP = willTP;
5775 _WillTP = false; // TMP TMP
5776 _UpdatingScenario = true;
5779 _BaseAct = NULL;
5780 _CurrentAct = NULL;
5781 CLuaStackRestorer lsc(&getLua(), getLua().getTop());
5782 //nlwarning("Scenario updated, start highlevel = ");
5783 //highLevel->dump();
5785 eraseScenario();
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();
5804 else
5806 nlwarning("NULL");
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());
5816 else
5818 _ScenarioInstance = NULL;
5819 nlwarning("Can't retrieve scenario (no instance id)");
5820 _Scenario->dump();
5823 static volatile bool forceDump = false;
5824 if (forceDump)
5826 _Scenario->dump();
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 :");
5834 //dumpInstances();
5835 CObject *acts = _Scenario->getAttr("Acts");
5836 if (acts)
5838 CObject *baseAct = acts->getValueAtPos(0);
5839 if (baseAct)
5841 _BaseAct = getInstanceFromId(baseAct->toString("InstanceId"));
5844 if (!_BaseAct)
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
5855 else
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);
5881 else
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);
5906 endLoading();
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())
5925 bool result = true;
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);
5936 ls.pop();
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)
5951 CHECK_EDITOR
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.");
5963 return result;
5966 // *********************************************************************************************************
5967 CInstance *CEditor::getDefaultFeature()
5969 //H_AUTO(R2_CEditor_getDefaultFeature)
5970 CHECK_EDITOR
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)
5978 CHECK_EDITOR
5979 const CObject *src = _DMC->find(instanceId, attrName, position);
5980 if (!src) return;
5982 CObject *oldParent = src->getParent();
5984 CInstance *inst = getInstanceFromObject(src);
5985 // tells object that he is about to move
5986 if (inst)
5988 inst->onPreHrcMove();
5989 // notify possible observers that this instance will move
5990 class CPreHrcMoveNotification : public IObserverAction
5992 public:
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);
6003 // do the move
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
6012 if (inst)
6014 inst->onPostHrcMove();
6015 // notify possible observers that this instance has moved
6016 class CPostHrcMoveNotification : public IObserverAction
6018 public:
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)
6036 CHECK_EDITOR
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;
6047 float Depth;
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
6059 public:
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;
6088 if (ignore)
6090 return NULL;
6092 //H_AUTO(R2_CEditor_getInstanceUnderPos)
6093 CHECK_EDITOR
6094 // TODO nico: this code was copied from CEntityManager::getEntityUnderPos
6095 // then modified, so some factoring could be made ...
6099 uint i;
6101 // valid only if bbox still intersect
6102 CInstance *precInstanceUnderPos= _LastInstanceUnderPos;
6103 bool precInstanceUnderPosValid= false;
6106 // reset result
6107 isPlayerUnderCursor= false;
6108 _LastInstanceUnderPos = NULL;
6111 // build the ray
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();
6141 if (!vd) continue;
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
6151 CVector sceneInter;
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())
6161 continue;
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();
6177 break;
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;
6197 break;
6198 default:
6199 nlassert(0);
6200 break;
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())
6220 return NULL;
6222 // Compute startDistBox: nearest entity distance, but the user
6223 float startDistBox;
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)
6231 return NULL;
6232 // so take the second for startDistBox
6233 startDistBox= intersectedObjects[1].Depth;
6235 else
6237 // ok, take it.
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)
6256 continue;
6258 float distZ = 0.f;
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;
6269 if (!keepSelection)
6271 preciseInterFound = true;
6272 distZ = intersectedObjects[i].Depth;
6275 break;
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;
6284 break;
6285 default:
6286 nlassert(0);
6287 break;
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)
6298 bestDistBox= 0;
6299 bestDistZ= distZ;
6300 objectSelected= object;
6301 /*if (selectionType == ISelectableObject::GroundProjected)
6303 projectedObjects.push_back(object);
6307 // else
6308 else
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)
6358 /*uint k;
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)
6378 CHECK_EDITOR
6379 // if entity skeleton model was clipped, skip
6380 NL3D::USkeleton *skeleton = entity.skeleton();
6381 if(!ClientCfg.Light && skeleton && !skeleton->getLastClippedState())
6382 return FLT_MAX;
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)
6393 if(skeleton)
6395 if(skeleton->supportFastIntersect() && skeleton->fastIntersect(worldRayStart, worldRayDir, dist2D, distZ, false))
6397 if (dist2D == 0.f)
6399 return distZ;
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))
6411 if (dist2D == 0.f)
6413 return distZ;
6417 else
6419 // TMP
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();
6425 return FLT_MAX;
6428 // *********************************************************************************************************
6429 const NLMISC::CAABBox &CEditor::getLocalSelectBox(CEntityCL &entity) const
6431 //H_AUTO(R2_CEditor_getLocalSelectBox)
6432 CHECK_EDITOR
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)
6449 CHECK_EDITOR
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)
6470 CHECK_EDITOR
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);
6480 return;
6482 else
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"));
6491 if (vt)
6493 vt->setText(CI18N::get(stringId));
6499 // *********************************************************************************************************
6500 void CEditor::connect()
6502 //H_AUTO(R2_CEditor_connect)
6503 CHECK_EDITOR
6504 if (_Mode == EditionMode || _Mode == AnimationModeLoading)
6506 bool ok = false;
6507 if (_ScenarioInstance)
6512 if (_ScenarioInstance->getLuaProjection().callMethodByNameNoThrow("validateForTesting", 0, 1))
6514 if (getLua().toBoolean(-1) == true)
6518 R2::getEditor().getDMC().getEditionModule().requestStartScenario();
6520 ok = true;
6524 catch (const std::exception& )
6526 // 'ok' still == false ...
6529 if (!ok)
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()");
6544 else
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;
6559 return;
6562 // *********************************************************************************************************
6563 CEditor::TInstanceObserverHandle CEditor::addInstanceObserver(const TInstanceId &instanceId, IInstanceObserver *observer)
6565 //H_AUTO(R2_CEditor_addInstanceObserver)
6566 CHECK_EDITOR
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());
6592 return handle;
6595 // *********************************************************************************************************
6596 CEditor::IInstanceObserver *CEditor::removeInstanceObserver(TInstanceObserverHandle handle)
6598 //H_AUTO(R2_CEditor_removeInstanceObserver)
6599 CHECK_EDITOR
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);
6605 return NULL;
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());
6612 return observer;
6615 // *********************************************************************************************************
6616 CEditor::IInstanceObserver *CEditor::getInstanceObserver(TInstanceObserverHandle handle)
6618 //H_AUTO(R2_CEditor_getInstanceObserver)
6619 CHECK_EDITOR
6620 nlassert(_InstanceObservers.size() == _InstanceObserverHandles.size());
6621 TInstanceObserverHandleMap::iterator it = _InstanceObserverHandles.find(handle);
6622 if (it == _InstanceObserverHandles.end())
6624 return NULL;
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
6635 return _Season;
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());
6656 if (!found)
6658 nlwarning("ISLAND COLLISION MISSING FOR : %s", islands[k].Island.c_str());
6660 found = !(CPath::lookup(islands[k].Island + ".island_hm", false, false).empty());
6661 if (!found)
6663 nlwarning("ISLAND HEIGHTMAP MISSING FOR : %s", islands[k].Island.c_str());
6668 // *********************************************************************************************************
6669 // move
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 /*= ""*/)
6696 CObject *table;
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);
6704 else
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));
6713 return table;
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);
6742 if (!obj) return 0;
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));
6781 if (!entitySheet)
6783 nlwarning("Can't find client sheet %s", sheetClient.c_str());
6784 return false;
6787 CSheetId sheetId(sheetClient);
6788 if (sheetId == CSheetId::Unknown)
6790 nlwarning("Can't get sheet");
6791 return false;
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"];
6818 if(entitySheet)
6820 const CCharacterSheet *chSheet = dynamic_cast<const CCharacterSheet *>(entitySheet);
6821 if(chSheet)
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;
6835 if(itemNb>0)
6837 itemFileName = CSheetId(itemNb).toString();
6838 vA.PropertySubData.HatModel = (uint) SheetMngr.getVSIndex(itemFileName, SLOTTYPE::HEAD_SLOT);
6840 else
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"];
6859 if(itemNb>0)
6861 itemFileName = CSheetId(itemNb).toString();
6862 vA.PropertySubData.JacketModel = (uint) SheetMngr.getVSIndex(itemFileName, SLOTTYPE::CHEST_SLOT);
6864 else
6866 vA.PropertySubData.JacketModel = 0;
6869 itemNb = (int) visualProps["TrouserModel"];
6870 if(itemNb>0)
6872 itemFileName = CSheetId(itemNb).toString();
6873 vA.PropertySubData.TrouserModel = (uint) SheetMngr.getVSIndex(itemFileName, SLOTTYPE::LEGS_SLOT);
6875 else
6877 vA.PropertySubData.TrouserModel = 0;
6880 itemNb = (int) visualProps["FeetModel"];
6881 if(itemNb>0)
6883 itemFileName = CSheetId(itemNb).toString();
6884 vB.PropertySubData.FeetModel = (uint) SheetMngr.getVSIndex(itemFileName, SLOTTYPE::FEET_SLOT);
6886 else
6888 vB.PropertySubData.FeetModel = 0;
6891 itemNb = (int) visualProps["HandsModel"];
6892 if(itemNb>0)
6894 itemFileName = CSheetId(itemNb).toString();
6895 vB.PropertySubData.HandsModel = (uint) SheetMngr.getVSIndex(itemFileName, SLOTTYPE::HANDS_SLOT);
6897 else
6899 vB.PropertySubData.HandsModel = 0;
6902 itemNb = (int) visualProps["ArmModel"];
6903 if(itemNb>0)
6905 itemFileName = CSheetId(itemNb).toString();
6906 vA.PropertySubData.ArmModel = (uint) SheetMngr.getVSIndex(itemFileName, SLOTTYPE::ARMS_SLOT);
6908 else
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"];
6920 if(itemNb>0)
6922 itemFileName = CSheetId(itemNb).toString();
6923 vA.PropertySubData.WeaponRightHand = (uint) SheetMngr.getVSIndex(itemFileName, SLOTTYPE::RIGHT_HAND_SLOT);
6925 else
6927 vA.PropertySubData.WeaponRightHand = 0;
6930 itemNb = (int) visualProps["WeaponLeftHand"];
6931 if(itemNb>0)
6933 itemFileName = CSheetId(itemNb).toString();
6934 vA.PropertySubData.WeaponLeftHand = (uint) SheetMngr.getVSIndex(itemFileName, SLOTTYPE::LEFT_HAND_SLOT);
6936 else
6938 vA.PropertySubData.WeaponLeftHand = 0;
6940 return true;
6946 // *********************************************************************************************************
6947 bool CEditor::CSortedInstances::contains(CInstance *inst) const
6949 TInstanceToIter::const_iterator it = _InstanceToIter.find(inst);
6950 #ifdef NL_DEBUG
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
6958 #endif
6959 return it != _InstanceToIter.end();
6962 // *********************************************************************************************************
6963 void CEditor::CSortedInstances::insert(const ucstring &name, CInstance *inst)
6965 nlassert(inst);
6966 #ifdef NL_DEBUG
6967 static volatile bool doTest = true;
6968 if (doTest)
6970 nlassert(!contains(inst)); // inserted twice !!
6972 #endif
6973 _InstanceToIter[inst] = _ByName.insert(std::make_pair(name, inst));
6976 // *********************************************************************************************************
6977 void CEditor::CSortedInstances::remove(CInstance *inst)
6979 nlassert(inst);
6980 TInstanceToIter::iterator it = _InstanceToIter.find(inst);
6981 nlassert(it != _InstanceToIter.end());
6982 _ByName.erase(it->second);
6983 _InstanceToIter.erase(it);
6984 #ifdef NL_DEBUG
6985 nlassert(!contains(inst));
6986 #endif
6990 // *********************************************************************************************************
6991 bool CEditor::isRegisteredByDispName(CInstance *inst) const
6993 nlassert(inst);
6994 for (uint k = 0; k < _InstancesByDispName.size(); ++k)
6996 if (_InstancesByDispName[k].contains(inst)) return true; // registered twice !!
6998 return false;
7001 // *********************************************************************************************************
7002 void CEditor::registerInstanceDispName(const ucstring &displayName, CInstance *inst)
7004 nlassert(inst);
7005 sint currClass = inst->getClassIndex();
7006 if (currClass < 0)
7008 nlwarning("Classindex not found for class %s", inst->getClassName().c_str());
7009 return;
7011 #ifdef NL_DEBUG
7012 nlassert(!isRegisteredByDispName(inst));
7013 #endif
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);
7022 #ifdef NL_DEBUG
7023 nlassert(isRegisteredByDispName(inst));
7024 #endif
7027 // *********************************************************************************************************
7028 void CEditor::unregisterInstanceDispName(CInstance *inst)
7030 nlassert(inst);
7031 sint currClass = inst->getClassIndex();
7032 if (currClass < 0)
7034 nlwarning("Classindex not found for class %s", inst->getClassName().c_str());
7035 return;
7037 #ifdef NL_DEBUG
7038 nlassert(isRegisteredByDispName(inst));
7039 #endif
7040 while (currClass >= 0)
7042 nlassert(currClass < (sint) _InstancesByDispName.size());
7043 _InstancesByDispName[currClass].remove(inst);
7044 currClass = getBaseClass(currClass);
7046 #ifdef NL_DEBUG
7047 nlassert(!isRegisteredByDispName(inst));
7048 #endif
7052 // *********************************************************************************************************
7054 // Creation of a new entity in scene
7056 class CAHCreateEntity : public IActionHandler
7058 virtual void execute(CCtrlBase * /* pCaller */, const std::string &sParams)
7060 CHECK_EDITOR
7061 if (getEditor().getMode() != CEditor::EditionMode)
7063 nlwarning("Can't modify scenario while testing");
7064 return;
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);
7071 if (!paletteNode)
7073 nlwarning("Can't retrieve palette node for id %s", paletteId.c_str());
7074 return;
7076 if (!paletteNode->isTable())
7078 nlwarning("Bad type for palette node %s (should be a table)", paletteId.c_str());
7079 return;
7082 std::string sheetClient = getString(paletteNode, "SheetClient");
7084 const CEntitySheet *entitySheet = SheetMngr.get(CSheetId(sheetClient));
7085 if (!entitySheet)
7087 nlwarning("Can't find client sheet %s", sheetClient.c_str());
7088 return;
7090 const CCharacterSheet *chSheet = dynamic_cast<const CCharacterSheet *>(entitySheet);
7091 if(chSheet->R2Npc)
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");
7104 return;
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)))
7111 return;
7114 //-------------------------random init npc visual properties
7115 if(dynamic_cast<CPlayerR2CL *>(entity))
7117 // push equipment id
7118 getEditor().getLua().push(getString(paletteNode, "Equipment"));
7120 // push race
7121 std::string race;
7122 switch(entity->people())
7124 case EGSPD::CPeople::Fyros:
7125 race = "Fyros";
7126 break;
7128 case EGSPD::CPeople::Matis:
7129 race = "Matis";
7130 break;
7132 case EGSPD::CPeople::Tryker:
7133 race = "Tryker";
7134 break;
7136 case EGSPD::CPeople::Zorai:
7137 race = "Zorai";
7138 break;
7140 default:
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
7155 SPropVisualA vA;
7156 SPropVisualB vB;
7157 SPropVisualC vC;
7158 sint64 *prop = 0;
7160 //vA.PropertySubData.Sex = (uint) visualProps["Sex"];
7161 const CEntitySheet *entitySheet = SheetMngr.get((CSheetId)sheetId.asInt());
7162 if(entitySheet)
7164 const CCharacterSheet *chSheet = dynamic_cast<const CCharacterSheet *>(entitySheet);
7165 if(chSheet)
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;
7179 if(itemNb>0)
7181 itemFileName = CSheetId(itemNb).toString();
7182 vA.PropertySubData.HatModel = (uint) SheetMngr.getVSIndex(itemFileName, SLOTTYPE::HEAD_SLOT);
7184 else
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"];
7203 if(itemNb>0)
7205 itemFileName = CSheetId(itemNb).toString();
7206 vA.PropertySubData.JacketModel = (uint) SheetMngr.getVSIndex(itemFileName, SLOTTYPE::CHEST_SLOT);
7208 else
7210 vA.PropertySubData.JacketModel = 0;
7213 itemNb = (int) visualProps["TrouserModel"];
7214 if(itemNb>0)
7216 itemFileName = CSheetId(itemNb).toString();
7217 vA.PropertySubData.TrouserModel = (uint) SheetMngr.getVSIndex(itemFileName, SLOTTYPE::LEGS_SLOT);
7219 else
7221 vA.PropertySubData.TrouserModel = 0;
7224 itemNb = (int) visualProps["FeetModel"];
7225 if(itemNb>0)
7227 itemFileName = CSheetId(itemNb).toString();
7228 vB.PropertySubData.FeetModel = (uint) SheetMngr.getVSIndex(itemFileName, SLOTTYPE::FEET_SLOT);
7230 else
7232 vB.PropertySubData.FeetModel = 0;
7235 itemNb = (int) visualProps["HandsModel"];
7236 if(itemNb>0)
7238 itemFileName = CSheetId(itemNb).toString();
7239 vB.PropertySubData.HandsModel = (uint) SheetMngr.getVSIndex(itemFileName, SLOTTYPE::HANDS_SLOT);
7241 else
7243 vB.PropertySubData.HandsModel = 0;
7246 itemNb = (int) visualProps["ArmModel"];
7247 if(itemNb>0)
7249 itemFileName = CSheetId(itemNb).toString();
7250 vA.PropertySubData.ArmModel = (uint) SheetMngr.getVSIndex(itemFileName, SLOTTYPE::ARMS_SLOT);
7252 else
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"];
7264 if(itemNb>0)
7266 itemFileName = CSheetId(itemNb).toString();
7267 vA.PropertySubData.WeaponRightHand = (uint) SheetMngr.getVSIndex(itemFileName, SLOTTYPE::RIGHT_HAND_SLOT);
7269 else
7271 vA.PropertySubData.WeaponRightHand = 0;
7274 itemNb = (int) visualProps["WeaponLeftHand"];
7275 if(itemNb>0)
7277 itemFileName = CSheetId(itemNb).toString();
7278 vA.PropertySubData.WeaponLeftHand = (uint) SheetMngr.getVSIndex(itemFileName, SLOTTYPE::LEFT_HAND_SLOT);
7280 else
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;
7311 return it->second;
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;
7358 break;
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;
7382 // lua ui update
7383 CLuaStackChecker lsc(&getLua(), 0);
7384 getLua().push(on);
7385 callEnvMethod("setMaxVisibleEntityExceededFlag", 1, 0);
7388 // *********************************************************************************************************
7389 class CAHGoTest : public IActionHandler
7391 virtual void execute(CCtrlBase * /* pCaller */, const std::string &/* sParams */)
7393 CHECK_EDITOR
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 */)
7404 CHECK_EDITOR
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)
7416 CHECK_EDITOR
7418 bool openUI = true;
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"));
7426 else
7427 wnd = dynamic_cast<CInterfaceGroup*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:r2ed_scenario_control"));
7429 if(wnd)
7431 if(showHide)
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)
7446 CHECK_EDITOR
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");
7455 else
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.
7472 else
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 */)
7486 CHECK_EDITOR
7488 CInterfaceManager *pIM = CInterfaceManager::getInstance();
7489 CAHManager::getInstance()->runActionHandler("leave_modal", pCaller, "");
7491 if(pCaller)
7493 CInterfaceGroup *fatherGC = pCaller->getParent();
7494 if (fatherGC)
7496 // Look for the root parent
7497 for(;;)
7499 CInterfaceGroup *parent = fatherGC->getParent();
7500 if (!parent || (parent->getId()=="ui:interface"))
7501 break;
7502 fatherGC = parent;
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"));
7521 if (pVT != NULL)
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 */)
7544 CHECK_EDITOR
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;
7556 CHECK_EDITOR
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 */)
7572 CHECK_EDITOR
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 */)
7584 CHECK_EDITOR
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)
7596 CHECK_EDITOR
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())
7604 return;
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;
7623 CHECK_EDITOR
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())
7639 return;
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);
7649 #else
7650 getEditor().getLua().push((*actionName).toUtf8());
7651 #endif
7652 historic.undo();
7653 getEditor().callEnvMethod("onUndo", 1, 0);
7655 else
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())
7672 return;
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);
7682 #else
7683 getEditor().getLua().push((*actionName).toUtf8());
7684 #endif
7685 historic.redo();
7686 getEditor().callEnvMethod("onRedo", 1, 0);
7688 else
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 */)
7702 CBitMemStream out;
7703 if(GenericMsgHeaderMngr.pushNameToStream("DM_GIFT:BEGIN", out))
7705 NetMngr.push(out);
7707 else
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();
7720 CBitMemStream out;
7721 if(GenericMsgHeaderMngr.pushNameToStream("DM_GIFT:VALIDATE", out))
7723 for(uint k = 0; k < 8; ++k)
7725 uint32 sheetId = 0;
7726 uint8 quantity = 0;
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);
7734 NetMngr.push(out);
7736 else
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");
7757 } // R2
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;
7768 return true;
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;
7778 return 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();
7785 if( !scenario )
7787 nlinfo("No current scenario -- can't save rtdata");
7788 return false;
7791 std::string fileName = "outpout";
7792 if( args.empty() )
7794 // try to name file from title, then area+instance
7795 R2::CObject *description = scenario->findAttr("Description");
7796 if( description )
7798 R2::CObject *name = description->findAttr("Name");
7799 R2::CObject *title = 0;
7800 if (name)
7802 title = name;
7804 else
7806 title = description->findAttr("Title"); //obsolete
7808 R2::CObject *locationId = description->findAttr("LocationId");
7809 R2::CObject *instanceId = description->findAttr("InstanceId");
7810 if( title )
7812 string sTitle = title->toString();
7813 if( !sTitle.empty() )
7814 fileName = sTitle;
7816 else if( locationId && instanceId )
7817 fileName = "area" + locationId->toString() + "_" + instanceId->toString();
7820 else // filename given
7822 fileName = args[0];
7825 nlinfo("translating current scenario");
7826 R2::CObject *pHighLevel = scenario->clone();
7827 nlassert( pHighLevel );
7829 R2::CObject *pRtData = R2::getEditor().getDMC().translateScenario( pHighLevel );
7830 delete pHighLevel;
7831 if( !pRtData )
7833 nlwarning("Failed to translate high-level scenario into rtdata");
7834 return false;
7837 // binary
7838 string fullFileName = fileName;
7839 fullFileName += ".rt.bin";
7840 nlinfo("writing rtdata to %s", fullFileName.c_str());
7842 COFile output;
7843 output.open(fullFileName);
7844 R2::CObjectSerializerClient serializer( pRtData );
7845 serializer.serial(output);
7846 output.flush();
7847 output.close();
7849 if( true ) // debug
7851 // text
7852 fullFileName = fileName;
7853 fullFileName += ".rt.txt";
7855 COFile output;
7856 //std::stringstream ss;
7857 std::string ss;
7858 output.open(fullFileName);
7859 pRtData->serialize(ss);
7860 //std::string str = ss.str();
7861 output.serial(ss);
7862 output.flush();
7863 output.close();
7865 return true;
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]);
7875 CBitmap result;
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();
7885 wvr.Valid = true;
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()));
7892 ray.normalize();
7893 ray = camMatrix.mulVector(ray);
7894 CVector inter;
7895 wvr.Dir = ray;
7896 R2::CTool::TRayIntersectionType rit = R2::CTool::computeLandscapeRayIntersection(wvr, inter);
7897 CRGBA resultCol;
7898 switch(rit)
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);
7915 catch(...)
7918 return true;
7922 // *********************************************************************************************************
7923 NLMISC_COMMAND(resetScenario, "reset R2 editor, reload all scripts & xml", "")
7925 if (!args.empty()) return false;
7926 R2::ResetScenarioWanted = true;
7927 return 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;
7936 return true;
7940 bool IsInRingMode()
7942 return R2::getEditor().getMode() != R2::CEditor::NotInitialized;