File: Thing.cpp

package info (click to toggle)
cyphesis-cpp 0.5.16-1
  • links: PTS
  • area: main
  • in suites: lenny
  • size: 5,084 kB
  • ctags: 3,627
  • sloc: cpp: 30,418; python: 4,812; xml: 4,674; sh: 4,118; makefile: 902; ansic: 617
file content (712 lines) | stat: -rw-r--r-- 23,744 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
// Cyphesis Online RPG Server and AI Engine
// Copyright (C) 2000-2006 Alistair Riddoch
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software Foundation,
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

// $Id: Thing.cpp,v 1.228 2008-01-26 17:43:22 alriddoch Exp $

#include "Thing.h"

#include "Script.h"
#include "Motion.h"

#include "common/log.h"
#include "common/const.h"
#include "common/debug.h"
#include "common/compose.hpp"
#include "common/Property.h"

#include "common/Burn.h"
#include "common/Nourish.h"
#include "common/Update.h"
#include "common/Pickup.h"
#include "common/Drop.h"

#include <wfmath/atlasconv.h>

#include <Atlas/Objects/Operation.h>
#include <Atlas/Objects/Anonymous.h>

using Atlas::Objects::smart_dynamic_cast;

using Atlas::Message::Element;
using Atlas::Message::MapType;
using Atlas::Objects::Root;
using Atlas::Objects::Operation::Set;
using Atlas::Objects::Operation::Sight;
using Atlas::Objects::Operation::Delete;
using Atlas::Objects::Operation::Drop;
using Atlas::Objects::Operation::Move;
using Atlas::Objects::Operation::Nourish;
using Atlas::Objects::Operation::Pickup;
using Atlas::Objects::Operation::Appearance;
using Atlas::Objects::Operation::Disappearance;
using Atlas::Objects::Operation::Update;
using Atlas::Objects::Operation::Wield;
using Atlas::Objects::Entity::Anonymous;
using Atlas::Objects::Entity::RootEntity;

static const bool debug_flag = false;

/// \brief Constructor for physical or tangiable entities.
Thing::Thing(const std::string & id, long intId) :
       Identified(id, intId),
       Thing_parent(id, intId)
{
    m_motion = new Motion(*this);
}

Thing::~Thing()
{
    assert(m_motion != 0);
    delete m_motion;
}

void Thing::DeleteOperation(const Operation & op, OpVector & res)
{
    if (m_location.m_loc == 0) {
        log(ERROR, String::compose("Deleting %1(%2) when it is not "
                                   "in the world.", getType(), getId()));
        assert(m_location.m_loc != 0);
        return;
    }
    // The actual destruction and removal of this entity will be handled
    // by the WorldRouter
    Sight s;
    s->setArgs1(op);
    res.push_back(s);
}

void Thing::MoveOperation(const Operation & op, OpVector & res)
{
    debug( std::cout << "Thing::move_operation" << std::endl << std::flush;);

    if (m_location.m_loc == 0) {
        log(ERROR, String::compose("Moving %1(%2) when it is not in the world.",
                                   getType(), getId()));
        assert(m_location.m_loc != 0);
        return;
    }

    // Check the validity of the operation.
    const std::vector<Root> & args = op->getArgs();
    if (args.empty()) {
        error(op, "Move has no argument", res, getId());
        return;
    }
    RootEntity ent = smart_dynamic_cast<RootEntity>(args.front());
    if (!ent.isValid()) {
        error(op, "Move op arg is malformed", res, getId());
        return;
    }
    if (getId() != ent->getId()) {
        error(op, "Move op does not have correct id in argument", res, getId());
        return;
    }

    if (!ent->hasAttrFlag(Atlas::Objects::Entity::LOC_FLAG)) {
        error(op, "Move op has no loc", res, getId());
        return;
    }
    const std::string & new_loc_id = ent->getLoc();
    Entity * new_loc = 0;
    if (new_loc_id != m_location.m_loc->getId()) {
        // If the LOC has not changed, we don't need to look it up, or do
        // any of the following checks.
        new_loc = BaseWorld::instance().getEntity(new_loc_id);
        if (new_loc == 0) {
            error(op, "Move op loc does not exist", res, getId());
            return;
        }
        debug(std::cout << "LOC: " << new_loc_id << std::endl << std::flush;);
        LocatedEntity * test_loc = new_loc;
        for (; test_loc != 0; test_loc = test_loc->m_location.m_loc) {
            if (test_loc == this) {
                error(op, "Attempt to move into itself", res, getId());
                return;
            }
        }
        assert(new_loc != 0);
        assert(m_location.m_loc != new_loc);
    }

    if (!ent->hasAttrFlag(Atlas::Objects::Entity::POS_FLAG)) {
        error(op, "Move op has no pos", res, getId());
        return;
    }

    // Up until this point nothing should have changed, but the changes
    // have all now been checked for validity.

    // Check if the location has changed
    if (new_loc != 0) {
        // new_loc should only be non-null if the LOC specified is
        // different from the current LOC
        assert(m_location.m_loc != new_loc);
        // Check for pickup, ie if the new LOC is the actor, and the
        // previous LOC is the actor's LOC.
        if (new_loc->getId() == op->getFrom() &&
            m_location.m_loc == new_loc->m_location.m_loc) {

            Pickup p;
            p->setFrom(op->getFrom());
            p->setTo(getId());
            Sight s;
            s->setArgs1(p);
            res.push_back(s);

            Anonymous wield_arg;
            wield_arg->setId(getId());
            Wield w;
            w->setTo(op->getFrom());
            w->setArgs1(wield_arg);
            res.push_back(w);
        }
        // Check for drop, ie if the old LOC is the actor, and the
        // new LOC is the actor's LOC.
        if (m_location.m_loc->getId() == op->getFrom() &&
            new_loc == m_location.m_loc->m_location.m_loc) {

            Drop d;
            d->setFrom(op->getFrom());
            d->setTo(getId());
            Sight s;
            s->setArgs1(d);
            res.push_back(s);
        }

        // Update loc
        changeContainer(new_loc);
    }

    std::string mode;

    if (hasAttr("mode")) {
        Element mode_attr;
        getAttr("mode", mode_attr);
        if (mode_attr.isString()) {
            mode = mode_attr.String();
        } else {
            log(ERROR, String::compose("Mode on entity is a \"%1\" in "
                                       "Thing::MoveOperation",
                                       Element::typeName(mode_attr.getType())));
        }
    }

    // Move ops often include a mode change, so we handle it here, even
    // though it is not a special attribute for efficiency. Otherwise
    // an additional Set op would be required.
    Element attr_mode;
    if (ent->copyAttr("mode", attr_mode) == 0) {
        if (!attr_mode.isString()) {
            log(ERROR, "Non string mode set in Thing::MoveOperation");
        } else {
            // Update the mode
            setAttr("mode", attr_mode);
            m_motion->setMode(attr_mode.String());
            mode = attr_mode.String();
        }
    }

    const double & current_time = BaseWorld::instance().getTime();

    Point3D old_pos = m_location.pos();

    // Update pos
    fromStdVector(m_location.m_pos, ent->getPos());
    // FIXME Quick height hack
    m_location.m_pos.z() = BaseWorld::instance().constrainHeight(m_location.m_loc,
                                                    m_location.pos(),
                                                    mode);
    m_location.update(current_time);
    m_update_flags |= a_pos;

    if (ent->hasAttrFlag(Atlas::Objects::Entity::VELOCITY_FLAG)) {
        // Update velocity
        fromStdVector(m_location.m_velocity, ent->getVelocity());
        // Velocity is not persistent so has no flag
    }

    Element attr_orientation;
    if (ent->copyAttr("orientation", attr_orientation) == 0) {
        // Update orientation
        m_location.m_orientation.fromAtlas(attr_orientation.asList());
        m_update_flags |= a_orient;
    }

    // At this point the Location data for this entity has been updated.

    bool moving = false;

    if (m_location.velocity().isValid() &&
        m_location.velocity().sqrMag() > WFMATH_EPSILON) {
        moving = true;
    }

    // Take into account terrain following etc.
    // Take into account mode also.
    // m_motion->adjustNewPostion();

    float update_time = consts::move_tick;

    if (moving) {
        // If we are moving, check for collisions
        update_time = m_motion->checkCollisions();

        if (m_motion->collision()) {
            if (update_time < WFMATH_EPSILON) {
                moving = m_motion->resolveCollision();
            } else {
                m_motion->m_collisionTime = current_time + update_time;
            }
        }
    }

    Operation m(op.copy());
    RootEntity marg = smart_dynamic_cast<RootEntity>(m->getArgs().front());
    assert(marg.isValid());
    m_location.addToEntity(marg);

    Sight s;
    s->setArgs1(m);

    res.push_back(s);

    // Serial number must be changed regardless of whether we will use it
    ++m_motion->serialno();

    // If we are moving, schedule an update to track the movement
    if (moving) {
        debug(std::cout << "Move Update in " << update_time << std::endl << std::flush;);

        Update u;
        u->setFutureSeconds(update_time);
        u->setTo(getId());

        u->setRefno(m_motion->serialno());

        res.push_back(u);
    }

    // This code handles sending Appearance and Disappearance operations
    // to this entity and others to indicate if one has gained or lost
    // sight of the other because of this movement

    // FIXME Why only for a perceptive moving entity? Surely other entities
    // must gain/lose sight of this entity if it's moving?
    if (isPerceptive()) {
        checkVisibility(old_pos, res);
    }
    m_seq++;
    updated.emit();
}

/// \brief Check changes in visibility of this entity
///
/// Check how this entity's position has changed since the last update
/// and how this has affected which entities it can see, and which can see
/// it. Return Appearance and Disappearance operations as required.
/// @param old_pos The coordinates of this entity before the update
/// @param res Resulting operations are returned here
void Thing::checkVisibility(const Point3D & old_pos, OpVector & res)
{
    debug(std::cout << "testing range" << std::endl;);
    float fromSquSize = m_location.squareBoxSize();
    std::vector<Root> appear, disappear;

    Anonymous this_ent;
    this_ent->setId(getId());
    this_ent->setStamp(m_seq);

    assert(m_location.m_loc != 0);
    assert(m_location.m_loc->m_contains != 0);
    LocatedEntitySet::const_iterator I = m_location.m_loc->m_contains->begin();
    LocatedEntitySet::const_iterator Iend = m_location.m_loc->m_contains->end();
    for(; I != Iend; ++I) {
        float old_dist = squareDistance((*I)->m_location.pos(), old_pos),
              new_dist = squareDistance((*I)->m_location.pos(), m_location.pos()),
              squ_size = (*I)->m_location.squareBoxSize();

        // Build appear and disappear lists, and send operations
        // Also so operations to (dis)appearing perceptive
        // entities saying that we are (dis)appearing
        // FIXME Should this be Entity *
        Entity * viewer = dynamic_cast<Entity *>(*I);
        assert(viewer != 0);
        if (viewer->isPerceptive()) {
            bool was_in_range = ((fromSquSize / old_dist) > consts::square_sight_factor),
                 is_in_range = ((fromSquSize / new_dist) > consts::square_sight_factor);
            if (was_in_range != is_in_range) {
                if (was_in_range) {
                    // Send operation to the entity in question so it
                    // knows it is losing sight of us.
                    Disappearance d;
                    d->setArgs1(this_ent);
                    d->setTo((*I)->getId());
                    res.push_back(d);
                } else /*if (is_in_range)*/ {
                    // Send operation to the entity in question so it
                    // knows it is gaining sight of us.
                    // FIXME We don't need to do this, cos its about
                    // to get our Sight(Move)
                    Appearance a;
                    a->setArgs1(this_ent);
                    a->setTo((*I)->getId());
                    res.push_back(a);
                }
            }
        }
        
        bool could_see = ((squ_size / old_dist) > consts::square_sight_factor),
             can_see = ((squ_size / new_dist) > consts::square_sight_factor);
        if (could_see ^ can_see) {
            Anonymous that_ent;
            that_ent->setId((*I)->getId());
            that_ent->setStamp((*I)->getSeq());
            if (could_see) {
                // We are losing sight of that object
                disappear.push_back(that_ent);
                debug(std::cout << getId() << ": losing site of "
                                << (*I)->getId() << std::endl;);
            } else /*if (can_see)*/ {
                // We are gaining sight of that object
                appear.push_back(that_ent);
                debug(std::cout << getId() << ": gaining site of "
                                << (*I)->getId() << std::endl;);
            }
        }
    }
    if (!appear.empty()) {
        // Send an operation to ourselves with a list of entities
        // we are losing sight of
        Appearance a;
        a->setArgs(appear);
        a->setTo(getId());
        res.push_back(a);
    }
    if (!disappear.empty()) {
        // Send an operation to ourselves with a list of entities
        // we are gaining sight of
        Disappearance d;
        d->setArgs(disappear);
        d->setTo(getId());
        res.push_back(d);
    }
}

void Thing::SetOperation(const Operation & op, OpVector & res)
{
    const std::vector<Root> & args = op->getArgs();
    if (args.empty()) {
        error(op, "Set has no argument", res, getId());
        return;
    }
    const Root & ent = args.front();
    merge(ent->asMessage());
    Sight s;
    s->setArgs1(op);
    res.push_back(s);
    m_seq++;
    if (m_update_flags != 0) {
        updated.emit();
    }
}

/// \brief Generate a Sight(Set) operation giving an update on named attributes
///
/// When another operation causes the properties of an entity to be changed,
/// it can trigger propagation of this change by sending an Update operation
/// nameing the attributes or properties that need to be updated. This
/// member function handles the Operation, sending a Sight(Set) for
/// any perceptible changes, and will in future handle persisting those
/// changes. Should this also handle side effects?
/// The main reason for this up is that if other ops need to generate a
/// Set op to update attributes, there are race conditions all over the
/// place.
/// @param op Update operation that notifies of the changes.
/// @param res The result of the operation is returned here.
void Thing::updateProperties(const Operation & op, OpVector & res) const
{
    const std::vector<Root> & args = op->getArgs();
    if (args.empty()) {
       return;
    }

    RootEntity arg = smart_dynamic_cast<RootEntity>(args.front());
    if (!arg.isValid()) {
        error(op, "Update op has malformed args", res, getId());
        return;
    }

    debug(std::cout << "Generating property update" << std::endl << std::flush;);

    Anonymous set_arg;
    set_arg->setId(getId());

    // Check if any of the hard attributes on RootEntity of changed.
    // All other hard attributes cannot be changed this way. Location related
    // attrs can only be changed by a Move or move relate update.
    // ID and PARENTS are immutable.
    if (!arg->isDefaultName()) {
        // Update the name
        // FIXME How?
    }
    if (!arg->isDefaultContains()) {
        // Update the contains
        // FIXME Really?
        // Surely better to go through the Property?
    }

    // FIXME SLOW!
    MapType attrs = arg->asMessage();
    MapType::const_iterator I = attrs.begin();
    MapType::const_iterator Iend = attrs.end();

    PropertyDict::const_iterator J;
    PropertyDict::const_iterator Jend = m_properties.end();

    for (; I != Iend; ++I) {
        const std::string & attr = I->first;
        debug(std::cout << "  " << attr << std::endl << std::flush;);

        J = m_properties.find(attr);
        if (J != Jend) {
            // Dump the property value into the Sight(Set()) arg
            J->second->add(attr, set_arg);
        } else {
            error(op, String::compose("Got update for non-existant property "
                                      "\"%1\"", attr), res, getId());
        }
    }

    Set set;
    set->setTo(getId());
    set->setFrom(getId());
    set->setSeconds(op->getSeconds());
    set->setArgs1(set_arg);

    Sight sight;
    sight->setArgs1(set);
    res.push_back(sight);
}

void Thing::UpdateOperation(const Operation & op, OpVector & res)
{
    // If it has no refno, then it is a generic request to broadcast
    // an update of some properties which have changed.
    if (op->isDefaultRefno()) {
        updateProperties(op, res);
        return;
    }

    // If LOC is null, this cannot be part of the world, or must be the
    // world itself, so should not be involved in any movement.
    if (m_location.m_loc == 0) {
        log(ERROR, String::compose("Updating %1(%2) when it is not in the world.",
                                   getType(), getId()));
        return;
    }

    // If it has a refno, then it is a movement update. If it does not
    // match the current movement serialno, then its obsolete, and can
    // be discarded.
    if (op->getRefno() != m_motion->serialno()) {
        return;
    }

    // If somehow a movement update arrives with the correct refno, but
    // we are not moving, then something has gone wrong.
    if (!m_location.velocity().isValid() ||
        m_location.velocity().sqrMag() < WFMATH_EPSILON) {
        log(ERROR, "Update got for entity not moving");
        return;
    }

    // This is where we will handle movement simulation from now on, rather
    // than in the mind interface. The details will be sorted by a new type
    // of object which will handle the specifics.

    const double & current_time = BaseWorld::instance().getTime();
    double time_diff = current_time - m_location.timeStamp();

    std::string mode;

    if (hasAttr("mode")) {
        Element mode_attr;
        getAttr("mode", mode_attr);
        if (mode_attr.isString()) {
            mode = mode_attr.String();
        } else {
            log(ERROR, String::compose("Mode on entity is a \"%1\" "
                                       "in Thing::UpdateOperation",
                                       Element::typeName(mode_attr.getType())));
        }
    }

    Point3D old_pos = m_location.pos();

    bool moving = true;

    // Check if a predicted collision is due.
    if (m_motion->collision()) {
        if (current_time >= m_motion->m_collisionTime) {
            time_diff = m_motion->m_collisionTime - m_location.timeStamp();
            // This flag signals that collision resolution is required later.
            // Whether or not we are actually moving is determined by the
            // collision resolution.
            moving = false;
        }
    }

    // Update entity position
    m_location.m_pos += (m_location.velocity() * time_diff);

    // Collision resolution has to occur after position has been updated.
    if (!moving) {
        moving = m_motion->resolveCollision();
    }

    // Adjust the position to world constraints - essentially fit
    // to the terrain height at this stage.
    m_location.m_pos.z() = BaseWorld::instance().constrainHeight(m_location.m_loc,
                                                    m_location.pos(),
                                                    mode);
    m_location.update(current_time);
    m_update_flags |= a_pos;

    float update_time = consts::move_tick;

    if (moving) {
        // If we are moving, check for collisions
        update_time = m_motion->checkCollisions();

        if (m_motion->collision()) {
            if (update_time < WFMATH_EPSILON) {
                moving = m_motion->resolveCollision();
            } else {
                m_motion->m_collisionTime = current_time + update_time;
            }
        }
    }

    Move m;
    Anonymous move_arg;
    move_arg->setId(getId());
    m_location.addToEntity(move_arg);
    m->setArgs1(move_arg);
    m->setFrom(getId());
    m->setTo(getId());

    Sight s;
    s->setArgs1(m);

    res.push_back(s);

    if (moving) {
        debug(std::cout << "New Update in " << update_time << std::endl << std::flush;);

        Update u;
        u->setFutureSeconds(update_time);
        u->setTo(getId());

        // If the update op has no serial number, we need our own
        // ref number
        if (op->isDefaultSerialno()) {
            u->setRefno(++m_motion->serialno());
        } else {
            // We should respect the serial number if it is present
            // as the core code will set the reference number
            // correctly.
            m_motion->serialno() = op->getSerialno();
        }

        res.push_back(u);
    }

    // This code handles sending Appearance and Disappearance operations
    // to this entity and others to indicate if one has gained or lost
    // sight of the other because of this movement

    // FIXME Why only for a perceptive moving entity? Surely other entities
    // must gain/lose sight of this entity if it's moving?
    if (isPerceptive()) {
        checkVisibility(old_pos, res);
    }
    updated.emit();
}

void Thing::LookOperation(const Operation & op, OpVector & res)
{
    Sight s;

    Anonymous new_ent;
    addToEntity(new_ent);
    s->setArgs1(new_ent);

    s->setTo(op->getFrom());

    res.push_back(s);
}

void Thing::CreateOperation(const Operation & op, OpVector & res)
{
    const std::vector<Root> & args = op->getArgs();
    if (args.empty()) {
       return;
    }
    try {
        RootEntity ent = smart_dynamic_cast<RootEntity>(args.front());
        if (!ent.isValid()) {
            error(op, "Entity to be created is malformed", res, getId());
            return;
        }
        const std::list<std::string> & parents = ent->getParents();
        if (parents.empty()) {
            error(op, "Entity to be created has empty parents", res, getId());
            return;
        }
        if (!ent->hasAttrFlag(Atlas::Objects::Entity::LOC_FLAG) &&
            (m_location.m_loc != 0)) {
            ent->setLoc(m_location.m_loc->getId());
            if (!ent->hasAttrFlag(Atlas::Objects::Entity::POS_FLAG)) {
                ::addToEntity(m_location.pos(), ent->modifyPos());
            }
        }
        const std::string & type = parents.front();
        debug( std::cout << getId() << " creating " << type;);

        Entity * obj = BaseWorld::instance().addNewEntity(type,ent);

        if (obj == 0) {
            error(op, "Create op failed.", res, op->getFrom());
            return;
        }

        Operation c(op.copy());

        Anonymous new_ent;
        obj->addToEntity(new_ent);
        c->setArgs1(new_ent);

        Sight s;
        s->setArgs1(c);
        res.push_back(s);
    }
    catch (Atlas::Message::WrongTypeException&) {
        log(ERROR, "EXCEPTION: Malformed object to be created");
        error(op, "Malformed object to be created", res, getId());
        return;
    }
}