Skip to content

Commit

Permalink
reworked shim, added the ability to execute commands in the game from…
Browse files Browse the repository at this point in the history
… the JSAPI, moved server browser proxy from an external webserver to the plugin (svcmd.*/Q3PluginApi.*)
  • Loading branch information
inolen committed Feb 4, 2012
1 parent 33e1647 commit 2d0dbaa
Show file tree
Hide file tree
Showing 30 changed files with 902 additions and 819 deletions.
3 changes: 2 additions & 1 deletion .gitignore
@@ -1,5 +1,6 @@
*.sublime-*
bootstrap/
firebreath/
ioquake3/
node_modules/
*.o
*.so
12 changes: 11 additions & 1 deletion Makefile
@@ -1,2 +1,12 @@
all:
.PHONY: ioquake3 plugin web

all: ioquake3 plugin web

ioquake3:
$(MAKE) -C ioquake3

plugin:
$(MAKE) -C firebreath/build/projects/q3plugin

web:
$(MAKE) -C web
6 changes: 6 additions & 0 deletions README
@@ -0,0 +1,6 @@
sudo apt-get install cmake libsdl1.2-dev libgtk2.0-dev
git clone git@github.com:inolen/q3plugin.git
cd q3plugin
git submodule update --recursive --init
./firebreath/prepmake.sh plugin
make
9 changes: 2 additions & 7 deletions plugin/CMakeLists.txt
Expand Up @@ -14,7 +14,7 @@ file (GLOB GENERAL RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
[^.]*.cpp
[^.]*.h
[^.]*.cmake
lib/[^.]*.c
lib/[^.]*.cpp
lib/[^.]*.h
)

Expand All @@ -40,12 +40,7 @@ SET(SOURCES
# depending on the platform
include_platform()

find_package(OpenGL REQUIRED)
include_directories(${OPENGL_INCLUDE_DIR})
target_link_libraries(${PROJECT_NAME} ${OPENGL_LIBRARIES})

find_package(SDL REQUIRED)
include_directories(${SDL_INCLUDE_DIR})
target_link_libraries(${PROJECT_NAME} ${SDL_LIBRARY})

include("shim/shim.cmake")
include("shim/shim.cmake")
2 changes: 1 addition & 1 deletion plugin/PluginConfig.cmake
Expand Up @@ -56,4 +56,4 @@ set(FBMAC_USE_COREANIMATION 0)
set(FBMAC_USE_INVALIDATINGCOREANIMATION 0)

# If you want to register per-machine on Windows, uncomment this line
#set (FB_ATLREG_MACHINEWIDE 1)
#set (FB_ATLREG_MACHINEWIDE 1)
155 changes: 80 additions & 75 deletions plugin/Q3Plugin.cpp
@@ -1,18 +1,26 @@
#include "Q3Plugin.h"
#include <assert.h>
#include <boost/filesystem/operations.hpp>
#include <SDL.h>
#include <unistd.h>
#include "Q3PluginApi.h"

#define FIFO_NAME "q3plugin"

namespace fs = boost::filesystem;

void Q3Plugin::StaticInitialize() {
}

void Q3Plugin::StaticDeinitialize() {
}

Q3Plugin::Q3Plugin() {
Q3Plugin::Q3Plugin() : gameArgs_(NULL) {
}

Q3Plugin::~Q3Plugin() {
//boost::interprocess::named_mutex::remove("q3plugin");

// This is optional, but if you reset m_api (the shared_ptr to your JSAPI
// root object) and tell the host to free the retained JSAPI objects then
// unless you are holding another shared_ptr reference to your JSAPI object
Expand All @@ -26,99 +34,96 @@ FB::JSAPIPtr Q3Plugin::createJSAPI() {
return boost::make_shared<Q3PluginApi>(FB::ptr_cast<Q3Plugin>(shared_from_this()), m_host);
}

void Q3Plugin::ProcessMessage(msgpipe_msg *msg) {
if (msg->type == MOUSELOCK) {
lockmouse_ = msg->mouselock.lock;
}
}

bool Q3Plugin::onKeyDown(FB::KeyDownEvent* evt, FB::PluginWindow* window) {
if (evt->m_os_key_code >= 0 && evt->m_os_key_code <= 255) {
msgpipe_msg msg;
msg.type = KEYPRESS;
msg.keypress.pressing = true;
msg.keypress.key = evt->m_os_key_code;
msgpipe_send(&pipe_, &msg);
}

return true;
void Q3Plugin::Connect(std::string server) {
msgpipe::message msg;
msg.type = msgpipe::msgs::GAMECMD;
strncpy(msg.gamecmd.text, std::string("connect ").append(server).c_str(), sizeof(msg.gamecmd.text));
fdxpipe_.send(msg);
}

bool Q3Plugin::onKeyUp(FB::KeyUpEvent* evt, FB::PluginWindow* window) {
if (evt->m_os_key_code >= 0 && evt->m_os_key_code <= 255) {
msgpipe_msg msg;
msg.type = KEYPRESS;
msg.keypress.pressing = false;
msg.keypress.key = evt->m_os_key_code;
msgpipe_send(&pipe_, &msg);
}

return true;
void Q3Plugin::ProcessMessage(msgpipe::message& msg) {
}

bool Q3Plugin::onMouseDown(FB::MouseDownEvent* evt, FB::PluginWindow* window) {
msgpipe_msg msg;
msg.type = MOUSEPRESS;
msg.mousepress.pressing = true;

switch (evt->m_Btn) {
case 0:
msg.mousepress.button = MOUSE_LEFT;
break;
case 1:
msg.mousepress.button = MOUSE_MIDDLE;
break;
case 2:
msg.mousepress.button = MOUSE_RIGHT;
break;
}
void Q3Plugin::RunMessagePump() {
try {
if (!fdxpipe_.open(std::string(FIFO_NAME), false)) {
fprintf(stderr, "Failed to make event pipe.\n");
return;
}

msgpipe_send(&pipe_, &msg);
while (true) {
msgpipe::message msg;

return true;
}
while (fdxpipe_.poll(msg)) {
ProcessMessage(msg);
}

bool Q3Plugin::onMouseUp(FB::MouseUpEvent* evt, FB::PluginWindow* window) {
msgpipe_msg msg;
msg.type = MOUSEPRESS;
msg.mousepress.pressing = false;

switch (evt->m_Btn) {
case 0:
msg.mousepress.button = MOUSE_LEFT;
break;
case 1:
msg.mousepress.button = MOUSE_MIDDLE;
break;
case 2:
msg.mousepress.button = MOUSE_RIGHT;
break;
boost::this_thread::sleep(boost::posix_time::milliseconds(1000 / 60));
}
}
catch (boost::thread_interrupted const&) {
}
}

msgpipe_send(&pipe_, &msg);

return true;
void Q3Plugin::StartMessagePump() {
pumpThread_ = boost::thread(&Q3Plugin::RunMessagePump, this);
}

bool Q3Plugin::onMouseMove(FB::MouseMoveEvent* evt, FB::PluginWindow* window) {
if (lockmouse_) {
msgpipe_msg msg;
msg.type = MOUSEMOTION;
msg.mousemotion.xrel = evt->m_x - window->getWindowWidth()/2;
msg.mousemotion.yrel = evt->m_y - window->getWindowHeight()/2;
msgpipe_send(&pipe_, &msg);
void Q3Plugin::StopMessagePump() {
pumpThread_.interrupt();

CenterMouse(window);
}
// Close message pipe.
fdxpipe_.close();

return true;
pumpThread_.join();
}

bool Q3Plugin::onWindowAttached(FB::AttachedEvent* evt, FB::PluginWindow* window) {
boost::thread t(boost::bind(&Q3Plugin::LaunchGame, this, window));
// Load ioquake3 from the same directory as the plugin.
fs::path p(getFSPath());
std::ostringstream gamePath;
gamePath << p.parent_path() << "/ioquake3";

gameArgs_ = (char**)malloc(sizeof(char*) * 10);
memset(gameArgs_, 0, sizeof(char*) * 10);

gameArgs_[0] = strdup(gamePath.str().c_str());
gameArgs_[1] = strdup("+r_fullscreen");
gameArgs_[2] = strdup("0");
gameArgs_[3] = strdup("+r_mode");
gameArgs_[4] = strdup("-1");
gameArgs_[5] = strdup("+r_customWidth");
gameArgs_[6] = (char*)malloc(sizeof(char) * 8);
snprintf(gameArgs_[6], 8, "%i", window->getWindowWidth());
gameArgs_[7] = strdup("+r_customHeight");
gameArgs_[8] = (char*)malloc(sizeof(char) * 8);
snprintf(gameArgs_[8], 8, "%i", window->getWindowHeight());

// Run the message pump.
StartMessagePump();

LaunchGame(9, gameArgs_);

return true;
}

bool Q3Plugin::onWindowDetached(FB::DetachedEvent* evt, FB::PluginWindow* window) {
ShutdownGame();

// Kill the message pump.
StopMessagePump();

// Free up arguments.
if (gameArgs_ != NULL) {
char** p = gameArgs_;

while (*p != NULL) {
free(*p);
p++;
}

free(gameArgs_);
}

return false;
}
37 changes: 22 additions & 15 deletions plugin/Q3Plugin.h
@@ -1,15 +1,13 @@
#ifndef Q3PLUGIN_H
#define Q3PLUGIN_H

#include <boost/thread.hpp>
#include "PluginWindow.h"
#include "PluginEvents/AttachedEvent.h"
#include "PluginEvents/KeyboardEvents.h"
#include "PluginEvents/MouseEvents.h"
#include "PluginCore.h"

extern "C" {
#include "lib/msgpipe.h"
}

FB_FORWARD_PTR(Q3Plugin)
class Q3Plugin : public FB::PluginCore {
Expand All @@ -20,17 +18,19 @@ class Q3Plugin : public FB::PluginCore {
Q3Plugin();
virtual ~Q3Plugin();

void Connect(std::string server);

protected:
virtual FB::JSAPIPtr createJSAPI();
virtual void ProcessMessage(msgpipe::message& msg);
virtual void LaunchGame(int argc, char** argv) = 0;
virtual void ShutdownGame() = 0;

// If you want your plugin to always be windowless, set this to true
// If you want your plugin to be optionally windowless based on the
// value of the "windowless" param tag, remove this method or return
// FB::PluginCore::isWindowless()
virtual bool isWindowless() { return false; }

void ProcessMessage(msgpipe_msg *msg);
virtual void LaunchGame(FB::PluginWindow* window) = 0;
virtual void CenterMouse(FB::PluginWindow* window) = 0;
virtual FB::JSAPIPtr createJSAPI();

BEGIN_PLUGIN_EVENT_MAP()
EVENTTYPE_CASE(FB::KeyDownEvent, onKeyDown, FB::PluginWindow)
Expand All @@ -43,17 +43,24 @@ class Q3Plugin : public FB::PluginCore {
END_PLUGIN_EVENT_MAP()

/** BEGIN EVENTDEF -- DON'T CHANGE THIS LINE **/
virtual bool onKeyDown(FB::KeyDownEvent* evt, FB::PluginWindow* window);
virtual bool onKeyUp(FB::KeyUpEvent* evt, FB::PluginWindow* window);
virtual bool onMouseDown(FB::MouseDownEvent* evt, FB::PluginWindow* window);
virtual bool onMouseUp(FB::MouseUpEvent* evt, FB::PluginWindow* window);
virtual bool onMouseMove(FB::MouseMoveEvent* evt, FB::PluginWindow* window);
virtual bool onKeyDown(FB::KeyDownEvent* evt, FB::PluginWindow* window) = 0;
virtual bool onKeyUp(FB::KeyUpEvent* evt, FB::PluginWindow* window) = 0;
virtual bool onMouseDown(FB::MouseDownEvent* evt, FB::PluginWindow* window) = 0;
virtual bool onMouseUp(FB::MouseUpEvent* evt, FB::PluginWindow* window) = 0;
virtual bool onMouseMove(FB::MouseMoveEvent* evt, FB::PluginWindow* window) = 0;
virtual bool onWindowAttached(FB::AttachedEvent* evt, FB::PluginWindow* window);
virtual bool onWindowDetached(FB::DetachedEvent* evt, FB::PluginWindow* window);
/** END EVENTDEF -- DON'T CHANGE THIS LINE **/

msgpipe pipe_;
bool lockmouse_;
msgpipe::fdxpipe fdxpipe_;

private:
void RunMessagePump();
void StartMessagePump();
void StopMessagePump();

boost::thread pumpThread_;
char** gameArgs_;
};

#endif

0 comments on commit 2d0dbaa

Please sign in to comment.