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
|
// Cyphesis Online RPG Server and AI Engine
// Copyright (C) 2000,2001 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: Creator.cpp,v 1.82 2008-01-26 17:43:21 alriddoch Exp $
#include "Creator.h"
#include "BaseMind.h"
#include "common/log.h"
#include "common/debug.h"
#include "common/serialno.h"
#include "common/compose.hpp"
#include "common/Setup.h"
#include "common/Tick.h"
#include "common/Unseen.h"
#include <Atlas/Objects/Operation.h>
#include <Atlas/Objects/Anonymous.h>
using Atlas::Objects::Root;
using Atlas::Objects::Operation::Delete;
using Atlas::Objects::Operation::Unseen;
using Atlas::Objects::Entity::Anonymous;
static const bool debug_flag = false;
Creator::Creator(const std::string & id, long intId) :
Identified(id, intId),
Creator_parent(id, intId)
{
debug( std::cout << "Creator::Creator" << std::endl << std::flush;);
}
void Creator::sendExternalMind(const Operation & op, OpVector & res)
{
debug(std::cout << "Creator::sendExternalMind(" << op->getParents().front()
<< ")" << std::endl << std::flush;);
// Simpified version of Character method sendMind() because local
// mind of Creator is irrelevant
if (0 != m_externalMind) {
debug( std::cout << "Sending to external mind" << std::endl
<< std::flush;);
m_externalMind->operation(op, res);
} else {
// If we do not have an external mind, and therefor a connection,
// there is no purpose to our existance, so we should die.
debug( std::cout << "NOTICE: Creator self destruct"
<< std::endl << std::flush;);
Delete d;
Anonymous del_arg;
del_arg->setId(getId());
d->setArgs1(del_arg);
d->setTo(getId());
res.push_back(d);
}
}
void Creator::operation(const Operation & op, OpVector & res)
{
debug( std::cout << "Creator::operation" << std::endl << std::flush;);
// FIXME Why not just call callOperation() to handle the type switch?
// The only real reason is that we avoid passing the Delete op to the
// mind, so we return early here. Could check for the Delete op in
// sendExternalMind() when the mind is gone, thus getting rid of the
// problem.
// To switch to using callOperation(), some more op handlers would
// need to be implemented, in particular SetupOperation() would need
// need to be implemented as below. Some might need to be blocked
// to prevent anyone from messing with us, like SetOperation().
OpNo op_no = op->getClassNo();
switch(op_no) {
case Atlas::Objects::Operation::CREATE_NO:
CreateOperation(op, res);
break;
case Atlas::Objects::Operation::LOOK_NO:
LookOperation(op, res);
break;
case Atlas::Objects::Operation::MOVE_NO:
MoveOperation(op, res);
break;
case Atlas::Objects::Operation::DELETE_NO:
DeleteOperation(op, res);
// Prevent Delete op from being sent to mind, so another delete
// is not created in response.
return;
break;
default:
if (op_no == Atlas::Objects::Operation::SETUP_NO) {
BaseWorld::instance().addPerceptive(this);
} else if (op_no == Atlas::Objects::Operation::TICK_NO) {
TickOperation(op, res);
}
break;
}
sendExternalMind(op, res);
}
void Creator::externalOperation(const Operation & op)
{
// If an admin connection specifies a TO on the op, we treat
// it specially, and make sure it goes direct, otherwise
// we handle it like a normal character.
debug( std::cout << "Creator::externalOperation("
<< op->getParents().front() << ")" << std::endl
<< std::flush;);
if (op->isDefaultTo()) {
debug( std::cout << "Creator handling op normally" << std::endl
<< std::flush;);
Creator_parent::externalOperation(op);
} else if (op->getTo() == getId() && op->isDefaultFutureSeconds()) {
debug( std::cout << "Creator handling op " << std::endl << std::flush;);
OpVector lres;
callOperation(op, lres);
OpVector::const_iterator Iend = lres.end();
for (OpVector::const_iterator I = lres.begin(); I != Iend; ++I) {
if (!op->isDefaultSerialno()) {
(*I)->setRefno(op->getSerialno());
}
sendWorld(*I);
// Don't delete lres as it has gone into World's queue
// World will deal with it.
}
} else {
Entity * to = BaseWorld::instance().getEntity(op->getTo());
if (to != 0) {
// Make it appear like it came from target itself;
to->sendWorld(op);
} else {
log(ERROR, String::compose("Creator operation from client "
"is to unknown ID \"%1\"",
op->getTo()));
Unseen u;
Anonymous unseen_arg;
unseen_arg->setId(op->getTo());
u->setArgs1(unseen_arg);
u->setTo(getId());
if (!op->isDefaultSerialno()) {
u->setRefno(op->getSerialno());
}
OpVector res;
sendExternalMind(u, res);
// We are not interested in anything the external mind might return
}
}
}
void Creator::mindLookOperation(const Operation & op, OpVector & res)
{
// This overriden version allows the Creator to search the world for
// entities by type or by name
debug(std::cout << "Got look up from prived mind from [" << op->getFrom()
<< "] to [" << op->getTo() << "]" << std::endl << std::flush;);
m_perceptive = true;
const std::vector<Root> & args = op->getArgs();
if (args.empty()) {
op->setTo(BaseWorld::instance().m_gameWorld.getId());
} else {
const Root & arg = args.front();
if (arg->hasAttrFlag(Atlas::Objects::ID_FLAG)) {
op->setTo(arg->getId());
} else if (arg->hasAttrFlag(Atlas::Objects::NAME_FLAG)) {
// Search by name
Entity * e = BaseWorld::instance().findByName(arg->getName());
if (e != NULL) {
op->setTo(e->getId());
} else {
Unseen u;
u->setTo(getId());
u->setArgs1(arg);
if (!op->isDefaultSerialno()) {
u->setRefno(op->getSerialno());
}
sendExternalMind(u, res);
return;
}
} else if (arg->hasAttrFlag(Atlas::Objects::PARENTS_FLAG)) {
// Search by name
if (!arg->getParents().empty()) {
Entity * e = BaseWorld::instance().findByType(arg->getParents().front());
if (e != NULL) {
op->setTo(e->getId());
} else {
Unseen u;
u->setTo(getId());
u->setArgs1(arg);
if (!op->isDefaultSerialno()) {
u->setRefno(op->getSerialno());
}
sendExternalMind(u, res);
return;
}
}
}
// FIXME Need to ensure that a broadcast Look insn't sent, and
// an Unseen is sent back, in once place if no match is found.
// Probably most easlier done by checking TO on op by flag.
}
debug( std::cout <<" now to ["<<op->getTo()<<"]"<<std::endl<<std::flush;);
res.push_back(op);
}
|