Merged athile's work

actorid
Nicolay Korslund 15 years ago
commit 0de4bb9d6c

@ -30,12 +30,12 @@ set(GAMEREND_HEADER
apps/openmw/mwrender/interior.hpp
apps/openmw/mwrender/playerpos.hpp
apps/openmw/mwrender/sky.hpp)
source_group(game_renderer FILES ${GAMEREND} ${GAMEREND_HEADER})
source_group(apps\\openmw\\mwrender FILES ${GAMEREND} ${GAMEREND_HEADER})
# set(GAMEINPUT)
set(GAMEINPUT_HEADER
apps/openmw/mwinput/inputmanager.hpp)
source_group(game_input FILES ${GAMEINPUT} ${GAMEINPUT_HEADER})
source_group(apps\\openmw\\mwinput FILES ${GAMEINPUT} ${GAMEINPUT_HEADER})
set(APPS ${GAME} ${GAMEREND} ${GAMEINPUT})
set(APPS_HEADER ${GAME_HEADER} ${GAMEREND_HEADER} ${GAMEINPUT_HEADER})
@ -48,7 +48,7 @@ set(BSA
set(BSA_HEADER
components/bsa/bsa_archive.hpp
components/bsa/bsa_file.hpp)
source_group(bsa FILES ${BSA} ${BSA_HEADER})
source_group(components\\bsa FILES ${BSA} ${BSA_HEADER})
set(NIF
components/nif/nif_file.cpp)
@ -64,13 +64,13 @@ set(NIF_HEADER
components/nif/data.hpp
components/nif/nif_file.hpp
components/nif/property.hpp)
source_group(nif FILES ${NIF} ${NIF_HEADER})
source_group(components\\nif FILES ${NIF} ${NIF_HEADER})
set(NIFOGRE
components/nifogre/ogre_nif_loader.cpp)
set(NIFOGRE_HEADER
components/nifogre/ogre_nif_loader.hpp)
source_group(nifogre FILES ${NIFOGRE} ${NIFOGRE_HEADER})
source_group(components\\nifogre FILES ${NIFOGRE} ${NIFOGRE_HEADER})
set(ESM_STORE
components/esm_store/store.cpp
@ -79,16 +79,16 @@ set(ESM_STORE_HEADER
components/esm_store/cell_store.hpp
components/esm_store/reclists.hpp
components/esm_store/store.hpp)
source_group(esm_store FILES ${ESM_STORE} ${ESM_STORE_HEADER})
source_group(components\\esm_store FILES ${ESM_STORE} ${ESM_STORE_HEADER})
file(GLOB ESM_HEADER components/esm/*.hpp)
source_group(esm_header FILES ${ESM_HEADER})
source_group(components\\esm FILES ${ESM_HEADER})
set(OGRE
components/engine/ogre/renderer.cpp)
set(OGRE_HEADER
components/engine/ogre/renderer.hpp)
source_group(ogre FILES ${OGRE} ${OGRE_HEADER})
source_group(components\\engine\\ogre FILES ${OGRE} ${OGRE_HEADER})
set(INPUT
components/engine/input/oismanager.cpp)
@ -99,7 +99,13 @@ set(INPUT_HEADER
components/engine/input/dispatch_map.hpp
components/engine/input/dispatcher.hpp
components/engine/input/poller.hpp)
source_group(input FILES ${INPUT} ${INPUT_HEADER})
source_group(components\\engine\\input FILES ${INPUT} ${INPUT_HEADER})
set(COMMANDSERVER
components/commandserver/command.hpp
components/commandserver/server.hpp
components/commandserver/server.cpp)
source_group(components\\commandserver FILES ${COMMANDSERVER})
set(MISC
components/misc/stringops.cpp
@ -107,19 +113,21 @@ set(MISC
set(MISC_HEADER
components/misc/fileops.hpp
components/misc/slice_array.hpp
components/misc/stringops.hpp)
source_group(misc FILES ${MISC} ${MISC_HEADER})
components/misc/stringops.hpp
components/misc/tsdeque.hpp)
source_group(components\\misc FILES ${MISC} ${MISC_HEADER})
file(GLOB COMPILER components/compiler/*.cpp)
file(GLOB COMPILER_HEADER components/compiler/*.hpp)
source_group(compiler FILES ${COMPILER} ${COMPILER_HEADER})
source_group(components\\compiler FILES ${COMPILER} ${COMPILER_HEADER})
file(GLOB INTERPRETER components/interpreter/*.cpp)
file(GLOB INTERPRETER_HEADER components/interpreter/*.hpp)
source_group(interpreter FILES ${INTERPRETER} ${INTERPRETER_HEADER})
source_group(components\\interpreter FILES ${INTERPRETER} ${INTERPRETER_HEADER})
set(COMPONENTS ${BSA} ${NIF} ${NIFOGRE} ${ESM_STORE} ${OGRE} ${INPUT} ${MISC} ${COMPILER}
set(COMPONENTS ${BSA} ${NIF} ${NIFOGRE} ${ESM_STORE} ${OGRE} ${INPUT} ${MISC}
${COMMANDSERVER}
${COMPILER}
${INTERPRETER})
set(COMPONENTS_HEADER ${BSA_HEADER} ${NIF_HEADER} ${NIFOGRE_HEADER} ${ESM_STORE_HEADER}
${ESM_HEADER} ${OGRE_HEADER} ${INPUT_HEADER} ${MISC_HEADER} ${COMPILER_HEADER}
@ -128,7 +136,7 @@ set(COMPONENTS_HEADER ${BSA_HEADER} ${NIF_HEADER} ${NIFOGRE_HEADER} ${ESM_STORE_
# source directory: libs
set(MANGLE_VFS libs/mangle/vfs/servers/ogre_vfs.cpp)
source_group(mangle_vfs FILES ${MANGLE_VFS})
source_group(libs\\mangle_vfs FILES ${MANGLE_VFS})
set(OPENMW_LIBS ${MANGLE_VFS})
set(OPENMW_LIBS_HEADER)
@ -151,7 +159,7 @@ include_directories("."
${CMAKE_HOME_DIRECTORY}/extern/caelum/include)
link_directories(${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR})
ADD_SUBDIRECTORY( extern/caelum )
add_subdirectory( extern/caelum )
# Specify build paths
@ -203,6 +211,9 @@ if (APPLE)
target_link_libraries(openmw ${CARBON_FRAMEWORK})
endif (APPLE)
# Other apps and tools
add_subdirectory( apps/clientconsole )
# Apple bundling
if (APPLE)
set_source_files_properties(
@ -220,19 +231,11 @@ endif (APPLE)
# Tools
option(BUILD_MWCOMPILER "build standalone Morrowind script compiler" ON)
if (BUILD_MWCOMPILER)
set(TOOLS_MWCOMPILER ${COMPILER} apps/mwcompiler/main.cpp apps/mwcompiler/context.cpp
apps/mwcompiler/context.hpp)
add_executable(mwcompiler ${TOOLS_MWCOMPILER})
add_subdirectory( apps/mwcompiler )
endif()
option(BUILD_MWINTERPRETER "build standalone Morrowind script code interpreter" ON)
if (BUILD_MWINTERPRETER)
set(TOOLS_MWINTERPRETER ${INTERPRETER} apps/mwinterpreter/main.cpp
apps/mwinterpreter/context.cpp apps/mwinterpreter/context.hpp)
add_executable(mwinterpreter ${TOOLS_MWINTERPRETER})
add_subdirectory( apps/mwinterpreter )
endif()

@ -0,0 +1,2 @@
project(clientconsole)
add_executable(clientconsole client.cpp)

@ -0,0 +1,138 @@
#include <iostream>
#include <boost/array.hpp>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
#pragma warning( disable : 4966 )
class Client
{
protected:
struct Header
{
char magic[4];
boost::uint32_t dataLength;
};
boost::asio::io_service mIOService;
tcp::socket* mpSocket;
public:
bool connect(const char* port)
{
tcp::resolver resolver(mIOService);
tcp::resolver::query query("localhost", port);
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
tcp::resolver::iterator end;
mpSocket = new tcp::socket(mIOService);
boost::system::error_code error = boost::asio::error::host_not_found;
while (error && endpoint_iterator != end)
{
mpSocket->close();
mpSocket->connect(*endpoint_iterator++, error);
}
return (error) ? false : true;
}
void disconnect()
{
mpSocket->close();
mIOService.stop();
}
bool send (const char* msg)
{
const size_t slen = strlen(msg);
const size_t plen = sizeof(Header) + slen + 1;
std::vector<char> packet(plen);
Header* pHeader = reinterpret_cast<Header*>(&packet[0]);
strncpy(pHeader->magic, "OMW0", 4);
pHeader->dataLength = slen + 1; // Include the null terminator
strncpy(&packet[8], msg, pHeader->dataLength);
boost::system::error_code ec;
boost::asio::write(*mpSocket, boost::asio::buffer(packet),
boost::asio::transfer_all(), ec);
if (ec)
std::cout << "Error: " << ec.message() << std::endl;
return !ec;
}
bool receive (std::string& reply)
{
Header header;
boost::system::error_code error;
mpSocket->read_some(boost::asio::buffer(&header, sizeof(Header)), error);
if (error != boost::asio::error::eof)
{
if (strncmp(header.magic, "OMW0", 4) == 0)
{
std::vector<char> msg;
msg.resize(header.dataLength);
boost::system::error_code error;
mpSocket->read_some(boost::asio::buffer(&msg[0], header.dataLength), error);
if (!error)
{
reply = &msg[0];
return true;
}
}
else
throw std::exception("Unexpected header!");
}
return false;
}
};
int main(int argc, char* argv[])
{
std::cout << "OpenMW client console" << std::endl;
std::cout << "=====================" << std::endl;
std::cout << "Type 'quit' to exit." << std::endl;
std::cout << "Connecting...";
Client client;
if (client.connect("27917"))
{
std::cout << "success." << std::endl;
bool bDone = false;
do
{
std::cout << "Client> ";
std::string buffer;
std::getline(std::cin, buffer);
if (buffer == "quit")
bDone = true;
else
{
if (client.send(buffer.c_str()))
{
std::string reply;
if (client.receive(reply))
std::cout << "Server: " << reply << std::endl;
else
bDone = true;
}
else
bDone = true;
}
} while (!bDone);
client.disconnect();
}
else
std::cout << "failed." << std::endl;
return 0;
}

@ -0,0 +1,9 @@
project(MWCompiler)
set(TOOLS_MWCOMPILER ${COMPILER}
main.cpp
context.cpp
context.hpp)
add_executable(mwcompiler ${TOOLS_MWCOMPILER})

@ -0,0 +1,9 @@
project(MWInterpreter)
set(TOOLS_MWINTERPRETER
${INTERPRETER}
main.cpp
context.cpp
context.hpp)
add_executable(mwinterpreter ${TOOLS_MWINTERPRETER})

@ -11,8 +11,24 @@
#include "world.hpp"
class ProcessCommandsHook : public Ogre::FrameListener
{
public:
ProcessCommandsHook(OMW::Engine* pEngine) : mpEngine (pEngine) {}
virtual bool frameStarted(const Ogre::FrameEvent& evt)
{
mpEngine->processCommands();
return true;
}
protected:
OMW::Engine* mpEngine;
};
OMW::Engine::Engine()
{
mspCommandServer.reset(
new OMW::CommandServer::Server(&mCommandQueue, kCommandServerPort));
}
// Load all BSA files in data directory.
@ -71,6 +87,31 @@ void OMW::Engine::addMaster (const std::string& master)
}
}
<<<<<<< HEAD
=======
// Enables sky rendering
//
void OMW::Engine::enableSky (bool bEnable)
{
mEnableSky = bEnable;
}
void OMW::Engine::processCommands()
{
Command cmd;
while (mCommandQueue.try_pop_front(cmd))
{
///\todo Add actual processing of the received command strings
std::cout << "Command: '" << cmd.mCommand << "'" << std::endl;
///\todo Replace with real output. For now, echo back the string in uppercase
std::string reply(cmd.mCommand);
std::transform(reply.begin(), reply.end(), reply.begin(), toupper);
cmd.mReplyFunction(reply);
}
}
>>>>>>> 450542b4b9a7cf6987c192abbf7e2cc44da286d2
// Initialise and enter main loop.
void OMW::Engine::go()
@ -106,11 +147,22 @@ void OMW::Engine::go()
// Sets up the input system
MWInput::MWInputManager input(mOgre, mWorld->getPlayerPos());
// Launch the console server
std::cout << "Starting command server on port " << kCommandServerPort << std::endl;
mspCommandServer->start();
mOgre.getRoot()->addFrameListener( new ProcessCommandsHook(this) );
std::cout << "\nStart! Press Q/ESC or close window to exit.\n";
// Start the main rendering loop
mOgre.start();
<<<<<<< HEAD
=======
mspCommandServer->stop();
delete mpSkyManager;
>>>>>>> 450542b4b9a7cf6987c192abbf7e2cc44da286d2
std::cout << "\nThat's all for now!\n";
}

@ -6,6 +6,16 @@
#include <boost/filesystem.hpp>
#include "components/engine/ogre/renderer.hpp"
#include "apps/openmw/mwrender/mwscene.hpp"
#include "components/misc/tsdeque.hpp"
#include "components/commandserver/server.hpp"
#include "components/commandserver/command.hpp"
namespace MWRender
{
class SkyManager;
}
namespace OMW
{
@ -15,12 +25,20 @@ namespace OMW
class Engine
{
enum { kCommandServerPort = 27917 };
boost::filesystem::path mDataDir;
Render::OgreRenderer mOgre;
std::string mCellName;
std::string mMaster;
World *mWorld;
bool mEnableSky;
MWRender::SkyManager* mpSkyManager;
TsDeque<OMW::Command> mCommandQueue;
std::auto_ptr<OMW::CommandServer::Server> mspCommandServer;
// not implemented
Engine (const Engine&);
Engine& operator= (const Engine&);
@ -49,6 +67,12 @@ namespace OMW
/// - Currently OpenMW only supports one master at the same time.
void addMaster (const std::string& master);
/// Enables rendering of the sky (off by default).
void enableSky (bool bEnable);
/// Process pending commands
void processCommands();
/// Initialise and enter main loop.
void go();
};

@ -0,0 +1,19 @@
#ifndef COMMANDSERVER_COMMAND_HPP
#define COMMANDSERVER_COMMAND_HPP
namespace OMW
{
///
/// A Command is currently defined as a string input that, when processed,
/// will generate a string output. The string output is passed to the
/// mReplyFunction as soon as the command has been processed.
///
class Command
{
public:
std::string mCommand;
boost::function1<void, std::string> mReplyFunction;
};
}
#endif COMMANDSERVER_COMMAND_HPP

@ -0,0 +1,199 @@
#include "server.hpp"
using boost::asio::ip::tcp;
//
// Namespace for containing implementation details that the
// rest of OpenMW doesn't need to worry about
//
namespace OMW { namespace CommandServer { namespace Detail {
struct Header
{
char magic[4];
size_t dataLength;
} header;
///
/// Tracks an active connection to the CommandServer
///
class Connection
{
public:
Connection (boost::asio::io_service& io_service, Server* pServer);
void start();
void stop();
tcp::socket& socket();
void reply (std::string s);
protected:
void handle ();
tcp::socket mSocket;
Server* mpServer;
boost::thread* mpThread;
};
Connection::Connection (boost::asio::io_service& io_service, Server* pServer)
: mSocket (io_service)
, mpServer (pServer)
{
}
void Connection::start()
{
mpThread = new boost::thread(boost::bind(&Connection::handle, this));
}
///
/// Stops and disconnects the connection
///
void Connection::stop()
{
mSocket.close();
mpThread->join();
}
tcp::socket& Connection::socket()
{
return mSocket;
}
void Connection::reply (std::string reply)
{
const size_t plen = sizeof(Header) + reply.length() + 1;
std::vector<char> packet(plen);
Header* pHeader = reinterpret_cast<Header*>(&packet[0]);
strncpy(pHeader->magic, "OMW0", 4);
pHeader->dataLength = reply.length() + 1; // Include the null terminator
strncpy(&packet[8], reply.c_str(), pHeader->dataLength);
boost::system::error_code ec;
boost::asio::write(mSocket, boost::asio::buffer(packet),
boost::asio::transfer_all(), ec);
if (ec)
std::cout << "Error: " << ec.message() << std::endl;
}
void Connection::handle ()
{
bool bDone = false;
while (!bDone)
{
// Read the header
boost::system::error_code error;
mSocket.read_some(boost::asio::buffer(&header, sizeof(Header)), error);
if (error != boost::asio::error::eof)
{
if (strncmp(header.magic, "OMW0", 4) == 0)
{
std::vector<char> msg;
msg.resize(header.dataLength);
boost::system::error_code error;
mSocket.read_some(boost::asio::buffer(&msg[0], header.dataLength), error);
if (!error)
mpServer->postCommand(this, &msg[0]);
else
bDone = true;
}
else
throw std::exception("Unexpected header!");
}
else
bDone = true;
}
mpServer->removeConnection(this);
}
}}}
namespace OMW { namespace CommandServer {
using namespace Detail;
Server::Server (Deque* pCommandQueue, const int port)
: mAcceptor (mIOService, tcp::endpoint(tcp::v4(), port))
, mpCommandQueue (pCommandQueue)
, mbStopping (false)
{
}
void Server::start()
{
mIOService.run();
mpThread = new boost::thread(boost::bind(&Server::threadMain, this));
}
void Server::stop()
{
// (1) Stop accepting new connections
// (2) Wait for the listener thread to finish
mAcceptor.close();
mpThread->join();
// Now that no new connections are possible, close any existing
// open connections
{
boost::mutex::scoped_lock lock(mConnectionsMutex);
mbStopping = true;
for (ConnectionSet::iterator it = mConnections.begin();
it != mConnections.end();
++it)
{
(*it)->stop();
}
}
}
void Server::removeConnection (Connection* ptr)
{
// If the server is shutting down (rather the client closing the
// connection), don't remove the connection from the list: that
// would corrupt the iterator the server is using to shutdown all
// clients.
if (!mbStopping)
{
boost::mutex::scoped_lock lock(mConnectionsMutex);
std::set<Connection*>::iterator it = mConnections.find(ptr);
if (it != mConnections.end())
mConnections.erase(it);
}
delete ptr;
}
void Server::postCommand (Connection* pConnection, const char* s)
{
Command cmd;
cmd.mCommand = s;
cmd.mReplyFunction = std::bind1st(std::mem_fun(&Connection::reply), pConnection);
mpCommandQueue->push_back(cmd);
}
void Server::threadMain()
{
// Loop until accept() fails, which will cause the break statement to be hit
while (true)
{
std::auto_ptr<Connection> spConnection(new Connection(mAcceptor.io_service(), this));
boost::system::error_code ec;
mAcceptor.accept(spConnection->socket(), ec);
if (!ec)
{
boost::mutex::scoped_lock lock(mConnectionsMutex);
mConnections.insert(spConnection.get());
spConnection->start();
spConnection.release();
}
else
break;
}
}
}}

@ -0,0 +1,63 @@
#ifndef CONSOLESERVER_H
#define CONSOLESERVER_H
#include <iostream>
#include <string>
#include <deque>
#include <set>
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include "components/misc/tsdeque.hpp"
#include "components/commandserver/command.hpp"
namespace OMW { namespace CommandServer
{
//
// Forward Declarations
//
namespace Detail
{
class Connection;
}
//
// Server that opens a port to listen for string commands which will be
// put into the deque provided in the Server constructor.
//
class Server
{
public:
typedef TsDeque<Command> Deque;
Server (Deque* pCommandQueue, const int port);
void start();
void stop();
protected:
friend class Detail::Connection;
typedef std::set<Detail::Connection*> ConnectionSet;
void removeConnection (Detail::Connection* ptr);
void postCommand (Detail::Connection*, const char* s);
void threadMain();
// Objects used to set up the listening server
boost::asio::io_service mIOService;
boost::asio::ip::tcp::acceptor mAcceptor;
boost::thread* mpThread;
bool mbStopping;
// Track active connections
ConnectionSet mConnections;
mutable boost::mutex mConnectionsMutex;
// Pointer to command queue
Deque* mpCommandQueue;
};
}}
#endif // CONSOLESERVER_H

@ -5,6 +5,7 @@
#include <cassert>
#include <algorithm>
#include <stack>
#include <iterator>
#include "generator.hpp"
#include "scanner.hpp"

@ -3,6 +3,7 @@
#include <cctype>
#include <algorithm>
#include <iterator>
#include "errorhandler.hpp"
#include "exception.hpp"

@ -4,6 +4,7 @@
#include <cctype>
#include <sstream>
#include <algorithm>
#include <iterator>
#include "exception.hpp"
#include "errorhandler.hpp"

@ -195,7 +195,7 @@ namespace Interpreter
mSegment5.insert (std::make_pair (code, opcode));
}
void Interpreter::Interpreter::run (const Type_Code *code, int codeSize)
void Interpreter::run (const Type_Code *code, int codeSize)
{
assert (codeSize>=4);

@ -0,0 +1,56 @@
#ifndef TSDEQUE_H
#define TSDEQUE_H
#include <boost/thread.hpp>
//
// Adapted from http://www.justsoftwaresolutions.co.uk/threading/implementing-a-thread-safe-queue-using-condition-variables.html
//
template<typename Data>
class TsDeque
{
private:
std::deque<Data> the_queue;
mutable boost::mutex the_mutex;
boost::condition_variable the_condition_variable;
public:
void push_back(Data const& data)
{
boost::mutex::scoped_lock lock(the_mutex);
the_queue.push_back(data);
lock.unlock();
the_condition_variable.notify_one();
}
bool empty() const
{
boost::mutex::scoped_lock lock(the_mutex);
return the_queue.empty();
}
bool try_pop_front(Data& popped_value)
{
boost::mutex::scoped_lock lock(the_mutex);
if(the_queue.empty())
return false;
popped_value=the_queue.front();
the_queue.pop_front();
return true;
}
void wait_and_pop_front(Data& popped_value)
{
boost::mutex::scoped_lock lock(the_mutex);
while(the_queue.empty())
{
the_condition_variable.wait(lock);
}
popped_value=the_queue.front();
the_queue.pop_front();
}
};
#endif // TSDEQUE_H
Loading…
Cancel
Save