mirror of
https://github.com/OpenMW/openmw.git
synced 2025-06-22 14:11:35 +00:00
Merged athile's work
This commit is contained in:
commit
0de4bb9d6c
15 changed files with 605 additions and 28 deletions
|
@ -30,12 +30,12 @@ set(GAMEREND_HEADER
|
||||||
apps/openmw/mwrender/interior.hpp
|
apps/openmw/mwrender/interior.hpp
|
||||||
apps/openmw/mwrender/playerpos.hpp
|
apps/openmw/mwrender/playerpos.hpp
|
||||||
apps/openmw/mwrender/sky.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)
|
||||||
set(GAMEINPUT_HEADER
|
set(GAMEINPUT_HEADER
|
||||||
apps/openmw/mwinput/inputmanager.hpp)
|
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 ${GAME} ${GAMEREND} ${GAMEINPUT})
|
||||||
set(APPS_HEADER ${GAME_HEADER} ${GAMEREND_HEADER} ${GAMEINPUT_HEADER})
|
set(APPS_HEADER ${GAME_HEADER} ${GAMEREND_HEADER} ${GAMEINPUT_HEADER})
|
||||||
|
@ -48,7 +48,7 @@ set(BSA
|
||||||
set(BSA_HEADER
|
set(BSA_HEADER
|
||||||
components/bsa/bsa_archive.hpp
|
components/bsa/bsa_archive.hpp
|
||||||
components/bsa/bsa_file.hpp)
|
components/bsa/bsa_file.hpp)
|
||||||
source_group(bsa FILES ${BSA} ${BSA_HEADER})
|
source_group(components\\bsa FILES ${BSA} ${BSA_HEADER})
|
||||||
|
|
||||||
set(NIF
|
set(NIF
|
||||||
components/nif/nif_file.cpp)
|
components/nif/nif_file.cpp)
|
||||||
|
@ -64,13 +64,13 @@ set(NIF_HEADER
|
||||||
components/nif/data.hpp
|
components/nif/data.hpp
|
||||||
components/nif/nif_file.hpp
|
components/nif/nif_file.hpp
|
||||||
components/nif/property.hpp)
|
components/nif/property.hpp)
|
||||||
source_group(nif FILES ${NIF} ${NIF_HEADER})
|
source_group(components\\nif FILES ${NIF} ${NIF_HEADER})
|
||||||
|
|
||||||
set(NIFOGRE
|
set(NIFOGRE
|
||||||
components/nifogre/ogre_nif_loader.cpp)
|
components/nifogre/ogre_nif_loader.cpp)
|
||||||
set(NIFOGRE_HEADER
|
set(NIFOGRE_HEADER
|
||||||
components/nifogre/ogre_nif_loader.hpp)
|
components/nifogre/ogre_nif_loader.hpp)
|
||||||
source_group(nifogre FILES ${NIFOGRE} ${NIFOGRE_HEADER})
|
source_group(components\\nifogre FILES ${NIFOGRE} ${NIFOGRE_HEADER})
|
||||||
|
|
||||||
set(ESM_STORE
|
set(ESM_STORE
|
||||||
components/esm_store/store.cpp
|
components/esm_store/store.cpp
|
||||||
|
@ -79,16 +79,16 @@ set(ESM_STORE_HEADER
|
||||||
components/esm_store/cell_store.hpp
|
components/esm_store/cell_store.hpp
|
||||||
components/esm_store/reclists.hpp
|
components/esm_store/reclists.hpp
|
||||||
components/esm_store/store.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)
|
file(GLOB ESM_HEADER components/esm/*.hpp)
|
||||||
source_group(esm_header FILES ${ESM_HEADER})
|
source_group(components\\esm FILES ${ESM_HEADER})
|
||||||
|
|
||||||
set(OGRE
|
set(OGRE
|
||||||
components/engine/ogre/renderer.cpp)
|
components/engine/ogre/renderer.cpp)
|
||||||
set(OGRE_HEADER
|
set(OGRE_HEADER
|
||||||
components/engine/ogre/renderer.hpp)
|
components/engine/ogre/renderer.hpp)
|
||||||
source_group(ogre FILES ${OGRE} ${OGRE_HEADER})
|
source_group(components\\engine\\ogre FILES ${OGRE} ${OGRE_HEADER})
|
||||||
|
|
||||||
set(INPUT
|
set(INPUT
|
||||||
components/engine/input/oismanager.cpp)
|
components/engine/input/oismanager.cpp)
|
||||||
|
@ -99,7 +99,13 @@ set(INPUT_HEADER
|
||||||
components/engine/input/dispatch_map.hpp
|
components/engine/input/dispatch_map.hpp
|
||||||
components/engine/input/dispatcher.hpp
|
components/engine/input/dispatcher.hpp
|
||||||
components/engine/input/poller.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
|
set(MISC
|
||||||
components/misc/stringops.cpp
|
components/misc/stringops.cpp
|
||||||
|
@ -107,19 +113,21 @@ set(MISC
|
||||||
set(MISC_HEADER
|
set(MISC_HEADER
|
||||||
components/misc/fileops.hpp
|
components/misc/fileops.hpp
|
||||||
components/misc/slice_array.hpp
|
components/misc/slice_array.hpp
|
||||||
components/misc/stringops.hpp)
|
components/misc/stringops.hpp
|
||||||
source_group(misc FILES ${MISC} ${MISC_HEADER})
|
components/misc/tsdeque.hpp)
|
||||||
|
source_group(components\\misc FILES ${MISC} ${MISC_HEADER})
|
||||||
|
|
||||||
file(GLOB COMPILER components/compiler/*.cpp)
|
file(GLOB COMPILER components/compiler/*.cpp)
|
||||||
file(GLOB COMPILER_HEADER components/compiler/*.hpp)
|
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 components/interpreter/*.cpp)
|
||||||
file(GLOB INTERPRETER_HEADER components/interpreter/*.hpp)
|
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}
|
||||||
set(COMPONENTS ${BSA} ${NIF} ${NIFOGRE} ${ESM_STORE} ${OGRE} ${INPUT} ${MISC} ${COMPILER}
|
${COMMANDSERVER}
|
||||||
|
${COMPILER}
|
||||||
${INTERPRETER})
|
${INTERPRETER})
|
||||||
set(COMPONENTS_HEADER ${BSA_HEADER} ${NIF_HEADER} ${NIFOGRE_HEADER} ${ESM_STORE_HEADER}
|
set(COMPONENTS_HEADER ${BSA_HEADER} ${NIF_HEADER} ${NIFOGRE_HEADER} ${ESM_STORE_HEADER}
|
||||||
${ESM_HEADER} ${OGRE_HEADER} ${INPUT_HEADER} ${MISC_HEADER} ${COMPILER_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
|
# source directory: libs
|
||||||
|
|
||||||
set(MANGLE_VFS libs/mangle/vfs/servers/ogre_vfs.cpp)
|
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 ${MANGLE_VFS})
|
||||||
set(OPENMW_LIBS_HEADER)
|
set(OPENMW_LIBS_HEADER)
|
||||||
|
@ -151,7 +159,7 @@ include_directories("."
|
||||||
${CMAKE_HOME_DIRECTORY}/extern/caelum/include)
|
${CMAKE_HOME_DIRECTORY}/extern/caelum/include)
|
||||||
link_directories(${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR})
|
link_directories(${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR})
|
||||||
|
|
||||||
ADD_SUBDIRECTORY( extern/caelum )
|
add_subdirectory( extern/caelum )
|
||||||
|
|
||||||
# Specify build paths
|
# Specify build paths
|
||||||
|
|
||||||
|
@ -203,6 +211,9 @@ if (APPLE)
|
||||||
target_link_libraries(openmw ${CARBON_FRAMEWORK})
|
target_link_libraries(openmw ${CARBON_FRAMEWORK})
|
||||||
endif (APPLE)
|
endif (APPLE)
|
||||||
|
|
||||||
|
# Other apps and tools
|
||||||
|
add_subdirectory( apps/clientconsole )
|
||||||
|
|
||||||
# Apple bundling
|
# Apple bundling
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
set_source_files_properties(
|
set_source_files_properties(
|
||||||
|
@ -220,19 +231,11 @@ endif (APPLE)
|
||||||
|
|
||||||
# Tools
|
# Tools
|
||||||
option(BUILD_MWCOMPILER "build standalone Morrowind script compiler" ON)
|
option(BUILD_MWCOMPILER "build standalone Morrowind script compiler" ON)
|
||||||
|
|
||||||
if (BUILD_MWCOMPILER)
|
if (BUILD_MWCOMPILER)
|
||||||
set(TOOLS_MWCOMPILER ${COMPILER} apps/mwcompiler/main.cpp apps/mwcompiler/context.cpp
|
add_subdirectory( apps/mwcompiler )
|
||||||
apps/mwcompiler/context.hpp)
|
|
||||||
|
|
||||||
add_executable(mwcompiler ${TOOLS_MWCOMPILER})
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
option(BUILD_MWINTERPRETER "build standalone Morrowind script code interpreter" ON)
|
option(BUILD_MWINTERPRETER "build standalone Morrowind script code interpreter" ON)
|
||||||
|
|
||||||
if (BUILD_MWINTERPRETER)
|
if (BUILD_MWINTERPRETER)
|
||||||
set(TOOLS_MWINTERPRETER ${INTERPRETER} apps/mwinterpreter/main.cpp
|
add_subdirectory( apps/mwinterpreter )
|
||||||
apps/mwinterpreter/context.cpp apps/mwinterpreter/context.hpp)
|
|
||||||
|
|
||||||
add_executable(mwinterpreter ${TOOLS_MWINTERPRETER})
|
|
||||||
endif()
|
endif()
|
||||||
|
|
2
apps/clientconsole/CMakeLists.txt
Executable file
2
apps/clientconsole/CMakeLists.txt
Executable file
|
@ -0,0 +1,2 @@
|
||||||
|
project(clientconsole)
|
||||||
|
add_executable(clientconsole client.cpp)
|
138
apps/clientconsole/client.cpp
Executable file
138
apps/clientconsole/client.cpp
Executable file
|
@ -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;
|
||||||
|
}
|
9
apps/mwcompiler/CMakeLists.txt
Normal file
9
apps/mwcompiler/CMakeLists.txt
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
project(MWCompiler)
|
||||||
|
|
||||||
|
set(TOOLS_MWCOMPILER ${COMPILER}
|
||||||
|
main.cpp
|
||||||
|
context.cpp
|
||||||
|
context.hpp)
|
||||||
|
|
||||||
|
add_executable(mwcompiler ${TOOLS_MWCOMPILER})
|
||||||
|
|
9
apps/mwinterpreter/CMakeLists.txt
Normal file
9
apps/mwinterpreter/CMakeLists.txt
Normal file
|
@ -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"
|
#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()
|
OMW::Engine::Engine()
|
||||||
{
|
{
|
||||||
|
mspCommandServer.reset(
|
||||||
|
new OMW::CommandServer::Server(&mCommandQueue, kCommandServerPort));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load all BSA files in data directory.
|
// 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.
|
// Initialise and enter main loop.
|
||||||
|
|
||||||
void OMW::Engine::go()
|
void OMW::Engine::go()
|
||||||
|
@ -106,11 +147,22 @@ void OMW::Engine::go()
|
||||||
// Sets up the input system
|
// Sets up the input system
|
||||||
MWInput::MWInputManager input(mOgre, mWorld->getPlayerPos());
|
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";
|
std::cout << "\nStart! Press Q/ESC or close window to exit.\n";
|
||||||
|
|
||||||
// Start the main rendering loop
|
// Start the main rendering loop
|
||||||
mOgre.start();
|
mOgre.start();
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
|
=======
|
||||||
|
mspCommandServer->stop();
|
||||||
|
delete mpSkyManager;
|
||||||
|
|
||||||
|
>>>>>>> 450542b4b9a7cf6987c192abbf7e2cc44da286d2
|
||||||
std::cout << "\nThat's all for now!\n";
|
std::cout << "\nThat's all for now!\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,16 @@
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
#include "components/engine/ogre/renderer.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
|
namespace OMW
|
||||||
{
|
{
|
||||||
|
@ -15,12 +25,20 @@ namespace OMW
|
||||||
|
|
||||||
class Engine
|
class Engine
|
||||||
{
|
{
|
||||||
|
enum { kCommandServerPort = 27917 };
|
||||||
|
|
||||||
boost::filesystem::path mDataDir;
|
boost::filesystem::path mDataDir;
|
||||||
Render::OgreRenderer mOgre;
|
Render::OgreRenderer mOgre;
|
||||||
std::string mCellName;
|
std::string mCellName;
|
||||||
std::string mMaster;
|
std::string mMaster;
|
||||||
World *mWorld;
|
World *mWorld;
|
||||||
|
|
||||||
|
bool mEnableSky;
|
||||||
|
MWRender::SkyManager* mpSkyManager;
|
||||||
|
|
||||||
|
TsDeque<OMW::Command> mCommandQueue;
|
||||||
|
std::auto_ptr<OMW::CommandServer::Server> mspCommandServer;
|
||||||
|
|
||||||
// not implemented
|
// not implemented
|
||||||
Engine (const Engine&);
|
Engine (const Engine&);
|
||||||
Engine& operator= (const Engine&);
|
Engine& operator= (const Engine&);
|
||||||
|
@ -49,6 +67,12 @@ namespace OMW
|
||||||
/// - Currently OpenMW only supports one master at the same time.
|
/// - Currently OpenMW only supports one master at the same time.
|
||||||
void addMaster (const std::string& master);
|
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.
|
/// Initialise and enter main loop.
|
||||||
void go();
|
void go();
|
||||||
};
|
};
|
||||||
|
|
19
components/commandserver/command.hpp
Executable file
19
components/commandserver/command.hpp
Executable file
|
@ -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
|
199
components/commandserver/server.cpp
Executable file
199
components/commandserver/server.cpp
Executable file
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}}
|
63
components/commandserver/server.hpp
Executable file
63
components/commandserver/server.hpp
Executable file
|
@ -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 <cassert>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
#include "generator.hpp"
|
#include "generator.hpp"
|
||||||
#include "scanner.hpp"
|
#include "scanner.hpp"
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
#include "errorhandler.hpp"
|
#include "errorhandler.hpp"
|
||||||
#include "exception.hpp"
|
#include "exception.hpp"
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
#include "exception.hpp"
|
#include "exception.hpp"
|
||||||
#include "errorhandler.hpp"
|
#include "errorhandler.hpp"
|
||||||
|
|
|
@ -195,7 +195,7 @@ namespace Interpreter
|
||||||
mSegment5.insert (std::make_pair (code, opcode));
|
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);
|
assert (codeSize>=4);
|
||||||
|
|
||||||
|
|
56
components/misc/tsdeque.hpp
Executable file
56
components/misc/tsdeque.hpp
Executable file
|
@ -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…
Reference in a new issue