cyphesis/client/ClientConnection.cpp
Al Riddoch 2fd239e63c * tools/cycmd.cpp: Ensure that login op is flushed after it is sent.
* server/Player.cpp: Arg order of std::string.compare() is
	  incompatable between recent libstdc++ versions. Switch
	  back to old version, still in most common use.

	* rulesets/Thing.cpp: Set refno on ops handled in game.

	* rulesets/Python_API.cpp: Modify Entity() python constructor
	  so that commonly used attributes from old atlas are translated
	  to their modern equivalents.

	* rulesets/Py_Thing.cpp, rulesets/Py_Mind.cpp: Differentiate
	  between previously identical error messages in several places.

	* rulesets/Py_Object.cpp: Rework conversion of python dict to
	  Atlas map to be more efficient and clean.

	* rulesets/Py_Location.cpp: Rework setting of vector parts of
	  location so that it can accept vectors from python in more
	  formats, including lists and tuples.

	* rulesets/Creator.h, rulesets/Character.h, common/BaseEntity.h:
	  Re-order virtual methods declarations to fit a convention.

	* common/stringstream.h: Hardcode use of local stringstream class,
	  as the version provided with older libstdc++ seems to be broken.

	* common/database.cpp: Use the common header to pick the right
	  stringstream implementation.

	* common/BaseWorld.cpp, server/Persistance.cpp: Removed unused
	  stringstream include.

	* rulesets/Creator.cpp: Added extra debug output.

	* client/define_world.h, client/define_world.cpp, client/CommClient.h:
	  Use CreatorClient to store Creators mind, instead of BaseMind.

	* client/client.cpp,
	  client/ObserverClient.h, client/ObserverClient.cpp,
	  client/CreatorClient.h, client/CommClient.h, client/CommClient.cpp:
	  Modify method names to fit capitalisation conventions.

	* client/CreatorClient.cpp: Implement creation of in-game entities,
	  using creator entity.

	* client/CommClient.cpp: Added correct client side monitoring of
	  creator entity.

	* client/ClientConnection.h, client/ClientConnection.cpp: Added
	  pending method to establish if ops are in the queue. Switched send()
	  method so we only send ops. Add setting of serialno of sent
	  ops, starting with an offset of 512.

	* client/CharacterClient.h: Removed unused member, opFound.

	* client/CharacterClient.cpp: Debugged sendAndWait() method.

Al Riddoch  <alriddoch@zepler.org>
2001-08-16 17:39:42 +00:00

402 lines
8.8 KiB
C++

// This file may be redistributed and modified only under the terms of
// the GNU Lesser General Public License (See COPYING for details).
// Copyright (C) 2001 Alistair Riddoch
#include <Atlas/Codec.h>
#include <Atlas/Message/Object.h>
#include <Atlas/Net/Stream.h>
#include <Atlas/Objects/Decoder.h>
#include <Atlas/Objects/Encoder.h>
#include <varconf/Config.h>
#include <skstream.h>
extern "C" {
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include <unistd.h>
#include <netdb.h>
}
#include "ClientConnection.h"
#include "common/debug.h"
#include "config.h"
static bool debug_flag = true;
using Atlas::Message::Object;
ClientConnection::ClientConnection() :
client_fd(-1), encoder(NULL), serialNo(512)
{
}
ClientConnection::~ClientConnection()
{
if (encoder != NULL) {
delete encoder;
}
}
void ClientConnection::operation(const RootOperation & op)
{
#if 0
const std::string & from = op.GetFrom();
if (from.empty()) {
cerr << "ERROR: Operation with no destination" << endl << flush;
return;
}
dict_t::iterator I = objects.find(from);
if (I == objects.end()) {
cerr << "ERROR: Operation with invalid destination" << endl << flush;
return;
}
oplist res = I->second->message(op);
oplist::iterator J = res.begin();
for(J = res.begin(); J != res.end(); ++J) {
(*J)->SetFrom(I->first);
send(*(*J));
}
#endif
}
void ClientConnection::ObjectArrived(const Error&op)
{
cout << "ERROR" << endl << flush;
push(op);
error_flag = true;
}
void ClientConnection::ObjectArrived(const Info & op)
{
cout << "INFO" << endl << flush;
const std::string & from = op.GetFrom();
if (from.empty()) {
reply_flag = true;
error_flag = false;
try {
Object ac = op.GetArgs().front();
reply = ac.AsMap();
// const std::string & acid = reply["id"].AsString();
// objects[acid] = new ClientAccount(acid, *this);
}
catch (...) {
cerr << "WARNING: Malformed account from server" << endl << flush;
}
} else {
operation(op);
}
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Action& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Appearance& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Combine& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Communicate& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Create& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Delete& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Disappearance& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Divide& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Feel& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Get& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Imaginary& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Listen& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Login& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Logout& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Look& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Move& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Perceive& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Perception& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::RootOperation& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Set& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Sight& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Smell& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Sniff& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Sound& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Talk& op)
{
push(op);
}
void ClientConnection::ObjectArrived(const Atlas::Objects::Operation::Touch& op)
{
push(op);
}
int ClientConnection::read() {
if (ios.is_open()) {
codec->Poll();
return 0;
} else {
return -1;
}
}
bool ClientConnection::connect(const std::string & server)
{
struct sockaddr_in serv_sa;
cout << "Connecting to " << server << endl << flush;
memset(&serv_sa, 0, sizeof(serv_sa));
serv_sa.sin_family = AF_INET;
serv_sa.sin_port = htons(6767);
struct hostent * serv_addr = gethostbyname(server.c_str());
if (serv_addr == NULL) {
cerr << "ERROR: Lookup failed for " << server << endl;
return false;
}
memcpy(&serv_sa.sin_addr, serv_addr->h_addr_list[0], serv_addr->h_length);
client_fd = socket(AF_INET, SOCK_STREAM, 0);
if (client_fd < 0) {
cerr << "ERROR: Could not create server connection" <<endl<<flush;
perror("socket");
return false;
}
int ret;
ret = ::connect(client_fd, (struct sockaddr *)&serv_sa, sizeof(serv_sa));
if (ret < 0) {
cerr << "ERROR: Could not connect to " << server<<"." << endl << flush;
perror("connect");
return false;
}
ios.attach(client_fd);
Atlas::Net::StreamConnect conn("cyphesis_aiclient", ios, this);
cout << "Negotiating... " << flush;
while (conn.GetState() == Atlas::Net::StreamConnect::IN_PROGRESS) {
conn.Poll();
}
cout << "done" << endl;
if (conn.GetState() == Atlas::Net::StreamConnect::FAILED) {
cerr << "Failed to negotiate" << endl;
return false;
}
codec = conn.GetCodec();
encoder = new Atlas::Objects::Encoder(codec);
codec->StreamBegin();
return true;
}
bool ClientConnection::login(const std::string & account,
const std::string & password)
{
Atlas::Objects::Operation::Login l = Atlas::Objects::Operation::Login::Instantiate();
Object::MapType acmap;
acmap["id"] = account;
acmap["password"] = password;
acName = account;
l.SetArgs(Object::ListType(1,Object(acmap)));
reply_flag = false;
error_flag = false;
send(l);
return true;
}
bool ClientConnection::create(const std::string & account,
const std::string & password)
{
Atlas::Objects::Operation::Create c = Atlas::Objects::Operation::Create::Instantiate();
Object::MapType acmap;
acmap["id"] = account;
acmap["password"] = password;
acName = account;
c.SetArgs(Object::ListType(1,Object(acmap)));
reply_flag = false;
error_flag = false;
send(c);
return true;
}
bool ClientConnection::wait()
// Waits for response from server. Used when we are expecting a login response
// Return whether or not an error occured
{
error_flag = false;
reply_flag = false;
while (!reply_flag) {
codec->Poll();
}
return error_flag;
}
void ClientConnection::send(Atlas::Objects::Operation::RootOperation & op)
{
op.SetSerialno(++serialNo);
encoder->StreamMessage(&op);
ios << flush;
}
void ClientConnection::error(const std::string & message) {
// FIXME Need operation based error function
}
void ClientConnection::poll()
{
fd_set infds;
struct timeval tv;
FD_ZERO(&infds);
FD_SET(client_fd, &infds);
tv.tv_sec = 0;
tv.tv_usec = 0;
int retval = select(client_fd+1, &infds, NULL, NULL, &tv);
if (retval && (FD_ISSET(client_fd, &infds))) {
if (ios.peek() == -1) {
std::cerr << "Server disconnected" << std::endl << std::flush;
return;
}
codec->Poll();
return;
}
return;
}
RootOperation * ClientConnection::pop()
{
poll();
if (operationQueue.empty()) {
return NULL;
}
RootOperation * op = operationQueue.front();
operationQueue.pop_front();
return op;
}
bool ClientConnection::pending()
{
return !operationQueue.empty();
}
template<class O>
void ClientConnection::push(const O & op)
{
reply_flag = true;
RootOperation * new_op = new O(op);
operationQueue.push_back(new_op);
}