Open source Star Ruler 2 source code!
This commit is contained in:
@@ -0,0 +1,765 @@
|
||||
#include "binds.h"
|
||||
#include "empire.h"
|
||||
#include "obj/object.h"
|
||||
#include "main/references.h"
|
||||
#include "main/logging.h"
|
||||
#include "main/initialization.h"
|
||||
#include "scripts/manager.h"
|
||||
#include "scripts/generic_call.h"
|
||||
#include "network/player.h"
|
||||
#include "network/network_manager.h"
|
||||
#include "processing.h"
|
||||
#include "network.h"
|
||||
#include "../as_addons/include/scriptarray.h"
|
||||
#include "threads.h"
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
namespace scripts {
|
||||
|
||||
struct EventDesc {
|
||||
int id;
|
||||
GenericCallDesc sendToServer;
|
||||
GenericCallDesc sendToClient;
|
||||
|
||||
bool onlyPrimitive;
|
||||
bool recvLocal;
|
||||
bool recvServer;
|
||||
bool recvShadow;
|
||||
bool recvMenu;
|
||||
bool passPlayer;
|
||||
std::string recvEngine;
|
||||
std::string recvModule;
|
||||
|
||||
GenericCallDesc recvCall;
|
||||
Manager* recvManager;
|
||||
asIScriptFunction* recvFunc;
|
||||
};
|
||||
|
||||
threads::Mutex eventDescMutex;
|
||||
std::vector<EventDesc*> evtDescs;
|
||||
|
||||
void ClearEvents() {
|
||||
threads::Lock lock(eventDescMutex);
|
||||
foreach(it, evtDescs)
|
||||
delete *it;
|
||||
evtDescs.clear();
|
||||
}
|
||||
|
||||
void ReadEvents(const std::string& filename) {
|
||||
threads::Lock lock(eventDescMutex);
|
||||
|
||||
DataReader datafile(filename);
|
||||
while(datafile++) {
|
||||
std::string& line = datafile.line;
|
||||
|
||||
//Split the line into the call and handler part
|
||||
std::vector<std::string> parts;
|
||||
split(line, parts, "->", true);
|
||||
|
||||
if(parts.size() != 2) {
|
||||
error(datafile.position() + " - ERROR: Invalid event format.");
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string& call = parts[0];
|
||||
std::string& handler = parts[1];
|
||||
|
||||
//Make the call descriptors
|
||||
GenericCallDesc sendToServer(call);
|
||||
bool local = false;
|
||||
|
||||
//Split the handler identifier
|
||||
if(handler.compare(0, 6, "local ") == 0) {
|
||||
local = true;
|
||||
handler = handler.substr(6);
|
||||
}
|
||||
|
||||
//Non-local RPCs cannot have return values
|
||||
if(!local && sendToServer.returnType.type) {
|
||||
error(datafile.position() + " - ERROR: Non-local events cannot have return values.");
|
||||
continue;
|
||||
}
|
||||
else if(sendToServer.returnType == GT_Custom_Handle) {
|
||||
error(datafile.position() + " - ERROR: Return type cannot be a custom class.");
|
||||
continue;
|
||||
}
|
||||
|
||||
std::vector<std::string> scopes;
|
||||
split(handler, scopes, "::", true);
|
||||
|
||||
bool recvServer = false;
|
||||
bool recvShadow = false;
|
||||
bool recvMenu = false;
|
||||
bool primitive = true;
|
||||
|
||||
if(scopes[0] == "server") {
|
||||
recvServer = true;
|
||||
recvShadow = false;
|
||||
}
|
||||
else if(scopes[0] == "shadow") {
|
||||
recvServer = false;
|
||||
recvShadow = true;
|
||||
}
|
||||
else if(scopes[0] == "menu_client") {
|
||||
recvServer = false;
|
||||
recvMenu = true;
|
||||
}
|
||||
else if(scopes[0] == "menu_server") {
|
||||
recvServer = true;
|
||||
recvMenu = true;
|
||||
}
|
||||
|
||||
if(local && !recvServer && !recvShadow) {
|
||||
error(datafile.position() + " - ERROR: Send-to-client events cannot be marked as local.");
|
||||
continue;
|
||||
}
|
||||
|
||||
GenericCallDesc recvCall;
|
||||
|
||||
GenericCallDesc sendToClient;
|
||||
sendToClient.name = sendToServer.name;
|
||||
sendToClient.argCount = 1;
|
||||
sendToClient.arguments[0] = GT_Player_Ref;
|
||||
|
||||
recvCall.returnType = sendToServer.returnType;
|
||||
recvCall.returnsArray = sendToServer.returnsArray;
|
||||
|
||||
for(unsigned i = 0; i < sendToServer.argCount; ++i) {
|
||||
auto& arg = sendToServer.arguments[i];
|
||||
recvCall.arguments[recvCall.argCount++] = arg;
|
||||
|
||||
if(arg.type == GT_Custom_Handle) {
|
||||
arg.customName = "Serializable";
|
||||
primitive = false;
|
||||
}
|
||||
|
||||
sendToClient.arguments[sendToClient.argCount++] = arg;
|
||||
}
|
||||
|
||||
if(scopes.size() != 3) {
|
||||
error((datafile.position() + " - ERROR: Invalid event handler format '%s'.").c_str(), handler.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
recvCall.name = scopes[2];
|
||||
|
||||
EventDesc* desc = new EventDesc();
|
||||
desc->id = (int)evtDescs.size();
|
||||
desc->recvServer = recvServer;
|
||||
desc->recvShadow = recvShadow;
|
||||
desc->recvMenu = recvMenu;
|
||||
desc->sendToServer = sendToServer;
|
||||
desc->sendToClient = sendToClient;
|
||||
desc->recvLocal = local;
|
||||
desc->recvEngine = scopes[0];
|
||||
desc->recvModule = scopes[1];
|
||||
desc->recvCall = recvCall;
|
||||
desc->recvFunc = 0;
|
||||
desc->passPlayer = false;
|
||||
desc->onlyPrimitive = primitive;
|
||||
|
||||
if(desc->sendToServer.returnsArray) {
|
||||
desc->sendToServer.returnType.type = GT_Custom_Handle;
|
||||
desc->sendToServer.returnType.customName = "DataList";
|
||||
}
|
||||
|
||||
if(desc->sendToClient.returnsArray) {
|
||||
desc->sendToClient.returnType.type = GT_Custom_Handle;
|
||||
desc->sendToClient.returnType.customName = "DataList";
|
||||
}
|
||||
|
||||
evtDescs.push_back(desc);
|
||||
}
|
||||
}
|
||||
|
||||
void BindEventBinds(bool menu) {
|
||||
threads::Lock lock(eventDescMutex);
|
||||
|
||||
foreach(it, evtDescs) {
|
||||
EventDesc& desc = **it;
|
||||
|
||||
if(!devices.network->isClient) {
|
||||
if(desc.recvShadow)
|
||||
continue;
|
||||
}
|
||||
|
||||
if(menu != desc.recvMenu)
|
||||
continue;
|
||||
|
||||
Manager* man = 0;
|
||||
if(desc.recvMenu)
|
||||
man = devices.scripts.menu;
|
||||
else if(desc.recvEngine == "server" || desc.recvEngine == "shadow")
|
||||
man = devices.scripts.server;
|
||||
else
|
||||
man = devices.scripts.client;
|
||||
desc.recvManager = man;
|
||||
|
||||
if(!desc.recvServer || desc.recvLocal || !devices.network->isClient) {
|
||||
desc.recvFunc = man->getFunction(desc.recvModule.c_str(),
|
||||
desc.recvCall.declaration(true).c_str());
|
||||
|
||||
if(!desc.recvFunc) {
|
||||
if(desc.recvServer || desc.recvShadow) {
|
||||
desc.recvCall.prepend(GT_Player_Ref);
|
||||
desc.passPlayer = true;
|
||||
desc.recvFunc = man->getFunction(desc.recvModule.c_str(),
|
||||
desc.recvCall.declaration(true).c_str());
|
||||
}
|
||||
if(!desc.recvFunc) {
|
||||
error("Events: Could not find function %s::%s::%s",
|
||||
desc.recvEngine.c_str(), desc.recvModule.c_str(),
|
||||
desc.recvCall.declaration(true).c_str());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned aCnt = desc.recvCall.argCount;
|
||||
for(unsigned i = 0; i < aCnt; ++i) {
|
||||
auto& arg = desc.recvCall.arguments[i];
|
||||
|
||||
//Find the correct type id for the receiving function
|
||||
if(arg.type == GT_Custom_Handle) {
|
||||
std::string in_name = "Serializable";
|
||||
|
||||
auto* mod = man->engine->GetModule(desc.recvModule.c_str());
|
||||
if(mod) {
|
||||
int cid = mod->GetTypeIdByDecl(arg.customName.c_str());
|
||||
arg.customType = (void*)man->engine->GetTypeInfoById(cid);
|
||||
}
|
||||
|
||||
asITypeInfo *rcvType, *srType, *clType;
|
||||
if(desc.recvMenu) {
|
||||
rcvType = man->engine->GetTypeInfoByName(in_name.c_str());
|
||||
srType = man->engine->GetTypeInfoByName(in_name.c_str());
|
||||
clType = man->engine->GetTypeInfoByName(in_name.c_str());
|
||||
}
|
||||
else {
|
||||
rcvType = man->engine->GetTypeInfoByName(in_name.c_str());
|
||||
srType = devices.scripts.server->engine->GetTypeInfoByName(in_name.c_str());
|
||||
clType = devices.scripts.client->engine->GetTypeInfoByName(in_name.c_str());
|
||||
}
|
||||
|
||||
if(!srType || !clType || !rcvType) {
|
||||
error("Error: Could not find interface type '%s'.", in_name.c_str());
|
||||
}
|
||||
else {
|
||||
arg.customRead = (void*)rcvType->GetMethodByDecl("void read(Message&)");
|
||||
arg.customWrite = (void*)rcvType->GetMethodByDecl("void write(Message&)");
|
||||
|
||||
unsigned r = i;
|
||||
if(desc.recvServer && desc.passPlayer)
|
||||
--r;
|
||||
|
||||
desc.sendToClient.arguments[r+1].customWrite = (void*)srType->GetMethodByDecl("void write(Message&)");
|
||||
|
||||
desc.sendToServer.arguments[r].customType = arg.customType;
|
||||
desc.sendToServer.arguments[r].customRead = arg.customRead;
|
||||
desc.sendToServer.arguments[r].customWrite = (void*)clType->GetMethodByDecl("void write(Message&)");
|
||||
}
|
||||
|
||||
if(!arg.customType) {
|
||||
error("Error: Could not find class '%s' in module '%s' for event description.",
|
||||
arg.customName.c_str(), desc.recvModule.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Player ALL_PLAYERS(-1);
|
||||
Player SERVER_PLAYER(-2);
|
||||
|
||||
GenericValue handleSendToServer(void* arg, GenericCallData& args) {
|
||||
GenericValue retVal;
|
||||
EventDesc& desc = *(EventDesc*)arg;
|
||||
args.desc = desc.sendToServer;
|
||||
|
||||
if(desc.recvLocal || !devices.network->isClient) {
|
||||
if(desc.recvFunc && desc.recvManager) {
|
||||
//Transfer custom classes from one engine to the other
|
||||
if(desc.onlyPrimitive) {
|
||||
Call cl = desc.recvManager->call(desc.recvFunc);
|
||||
|
||||
//Append player argument
|
||||
if(desc.passPlayer)
|
||||
cl.push(&devices.network->currentPlayer);
|
||||
|
||||
//Append other arguments
|
||||
args.pushTo(cl);
|
||||
|
||||
retVal = desc.recvCall.call(cl);
|
||||
}
|
||||
else {
|
||||
net::Message msg(net::MT_Application, net::MF_Managed);
|
||||
std::vector<asIScriptObject*> resultObjects;
|
||||
|
||||
for(unsigned i = 0; i < args.desc.argCount; ++i) {
|
||||
auto& arg = args.desc.arguments[i];
|
||||
if(arg.type != GT_Custom_Handle)
|
||||
continue;
|
||||
|
||||
if(!arg.customWrite || !arg.customRead || !arg.customType || !desc.recvManager)
|
||||
continue;
|
||||
|
||||
//Write to message
|
||||
{
|
||||
scripts::Call cl = getActiveManager()->call((asIScriptFunction*)arg.customWrite);
|
||||
cl.setObject((asIScriptObject*)args.values[i].ptr);
|
||||
cl.push(&msg);
|
||||
cl.call();
|
||||
}
|
||||
|
||||
//Create object
|
||||
asITypeInfo* type = (asITypeInfo*)arg.customType;
|
||||
asIScriptObject* ret = (asIScriptObject*)desc.recvManager->engine->CreateScriptObject(type);
|
||||
|
||||
//Call read function
|
||||
{
|
||||
scripts::Call cl = desc.recvManager->call((asIScriptFunction*)arg.customRead);
|
||||
cl.setObject(ret);
|
||||
cl.push(&msg);
|
||||
cl.call();
|
||||
}
|
||||
|
||||
msg.reset();
|
||||
resultObjects.push_back(ret);
|
||||
}
|
||||
|
||||
Call cl = desc.recvManager->call(desc.recvFunc);
|
||||
|
||||
//Append player argument
|
||||
if(desc.passPlayer)
|
||||
cl.push(&devices.network->currentPlayer);
|
||||
|
||||
//Append other arguments
|
||||
unsigned customIndex = 0;
|
||||
auto transferCustom = [&](ArgumentDesc& arg, asIScriptObject* ptr) -> asIScriptObject* {
|
||||
return resultObjects[customIndex++];
|
||||
};
|
||||
|
||||
args.pushTo(cl, 0, transferCustom);
|
||||
retVal = desc.recvCall.call(cl);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
auto writeCustom = [](net::Message& msg, ArgumentDesc& adesc, GenericValue& val) {
|
||||
if(adesc.type != GT_Custom_Handle)
|
||||
return;
|
||||
|
||||
if(adesc.customWrite) {
|
||||
//Call write function
|
||||
scripts::Call cl = getActiveManager()->call((asIScriptFunction*)adesc.customWrite);
|
||||
cl.setObject(val.script);
|
||||
cl.push(&msg);
|
||||
cl.call();
|
||||
}
|
||||
else {
|
||||
error("Could not find custom write for argument.");
|
||||
}
|
||||
};
|
||||
|
||||
net::Message msg(MT_Event_Call, net::MF_Managed);
|
||||
msg << desc.id;
|
||||
args.write(msg, 0, writeCustom);
|
||||
|
||||
devices.network->send(msg);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
GenericValue handleSendToClient_local(void* arg, GenericCallData& args) {
|
||||
EventDesc& desc = *(EventDesc*)arg;
|
||||
args.desc = desc.sendToServer;
|
||||
|
||||
auto writeCustom = [&](net::Message& msg, ArgumentDesc& adesc, GenericValue& val) {
|
||||
if(adesc.customWrite) {
|
||||
//Call write function
|
||||
scripts::Call cl = devices.scripts.server->call((asIScriptFunction*)adesc.customWrite);
|
||||
cl.setObject(val.script);
|
||||
cl.push(&msg);
|
||||
cl.call();
|
||||
}
|
||||
};
|
||||
|
||||
net::Message msg(MT_Event_Call, net::MF_Managed);
|
||||
msg << desc.id;
|
||||
args.write(msg, 0, writeCustom);
|
||||
|
||||
msg.finalize();
|
||||
msg.rewind();
|
||||
handleEventMessage(&devices.network->currentPlayer, msg);
|
||||
return GenericValue();
|
||||
}
|
||||
|
||||
GenericValue handleSendToClient(void* arg, GenericCallData& args) {
|
||||
EventDesc& desc = *(EventDesc*)arg;
|
||||
Player* pl = args.values[0].player;
|
||||
args.desc = desc.sendToClient;
|
||||
|
||||
auto writeCustom = [&](net::Message& msg, ArgumentDesc& adesc, GenericValue& val) {
|
||||
if(adesc.customWrite) {
|
||||
//Call write function
|
||||
scripts::Call cl = devices.scripts.server->call((asIScriptFunction*)adesc.customWrite);
|
||||
cl.setObject(val.script);
|
||||
cl.push(&msg);
|
||||
cl.call();
|
||||
}
|
||||
};
|
||||
|
||||
net::Message msg(MT_Event_Call, net::MF_Managed);
|
||||
msg << desc.id;
|
||||
args.write(msg, 1, writeCustom);
|
||||
|
||||
if(!devices.network->isServer || pl == nullptr || pl == &devices.network->currentPlayer) {
|
||||
msg.finalize();
|
||||
msg.rewind();
|
||||
handleEventMessage(&devices.network->currentPlayer, msg);
|
||||
}
|
||||
else if(pl == &ALL_PLAYERS || pl->id == -1) {
|
||||
devices.network->sendAll(msg);
|
||||
handleEventMessage(&devices.network->currentPlayer, msg);
|
||||
}
|
||||
else
|
||||
devices.network->send(pl, msg);
|
||||
|
||||
return GenericValue();
|
||||
}
|
||||
|
||||
threads::Mutex queuedEventLock;
|
||||
std::stack<std::tuple<Player,net::Message*>> queuedClientEvents;
|
||||
void processEvents() {
|
||||
while(!queuedClientEvents.empty()) {
|
||||
queuedEventLock.lock();
|
||||
auto item = queuedClientEvents.top();
|
||||
queuedClientEvents.pop();
|
||||
queuedEventLock.release();
|
||||
|
||||
handleEventMessage(&std::get<0>(item), *std::get<1>(item));
|
||||
delete std::get<1>(item);
|
||||
}
|
||||
}
|
||||
|
||||
scripts::Manager* handleEventMessage(Player* from, net::Message& msg, bool interceptMenu) {
|
||||
int eventId;
|
||||
msg >> eventId;
|
||||
|
||||
if(eventId < 0 || eventId >= (int)evtDescs.size())
|
||||
return nullptr;
|
||||
|
||||
EventDesc& edesc = *evtDescs[eventId];
|
||||
if(interceptMenu && edesc.recvMenu)
|
||||
return edesc.recvManager;
|
||||
|
||||
if(!edesc.recvMenu && !game_running) {
|
||||
msg.rewind();
|
||||
threads::Lock lock(queuedEventLock);
|
||||
queuedClientEvents.push(std::tuple<Player,net::Message*>(*from,new net::Message(msg)));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GenericCallDesc& cdesc = edesc.recvCall;
|
||||
GenericCallData data(cdesc);
|
||||
|
||||
auto readCustom = [edesc](net::Message& msg, ArgumentDesc& desc, GenericValue& val) {
|
||||
if(desc.customType && desc.customRead && edesc.recvManager) {
|
||||
//Create object
|
||||
asITypeInfo* type = (asITypeInfo*)desc.customType;
|
||||
val.script = (asIScriptObject*)edesc.recvManager->engine->CreateScriptObject(type);
|
||||
|
||||
//Call read function
|
||||
scripts::Call cl = edesc.recvManager->call((asIScriptFunction*)desc.customRead);
|
||||
cl.setObject(val.script);
|
||||
cl.push(&msg);
|
||||
cl.call();
|
||||
}
|
||||
};
|
||||
|
||||
if((edesc.recvServer || edesc.recvShadow) && edesc.passPlayer) {
|
||||
data.values[0].player = from;
|
||||
data.read(msg, 1, readCustom);
|
||||
}
|
||||
else {
|
||||
data.read(msg, 0, readCustom);
|
||||
}
|
||||
|
||||
if(edesc.recvFunc && edesc.recvManager) {
|
||||
Call cl = edesc.recvManager->call(edesc.recvFunc);
|
||||
data.pushTo(cl);
|
||||
cl.call();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void linkEmpire(Player& inPl, Empire* emp) {
|
||||
threads::ReadLock lock(devices.network->playerLock);
|
||||
Player* pl = devices.network->getPlayer(inPl.id);
|
||||
if(!pl)
|
||||
return;
|
||||
if(pl->emp && pl->emp != Empire::getSpectatorEmpire()) {
|
||||
pl->emp->player = nullptr;
|
||||
pl->emp->lastPlayer = net::Address();
|
||||
}
|
||||
pl->emp = emp;
|
||||
pl->changedEmpire = true;
|
||||
pl->controlMask = 0;
|
||||
pl->viewMask = ~0;
|
||||
if(emp && emp != Empire::getSpectatorEmpire()) {
|
||||
emp->player = pl;
|
||||
emp->lastPlayer = pl->address;
|
||||
pl->controlMask = emp->mask;
|
||||
pl->viewMask = emp->mask;
|
||||
}
|
||||
}
|
||||
|
||||
static bool playerEquals(Player& player, Player& other) {
|
||||
return player.id == other.id;
|
||||
}
|
||||
|
||||
static asITypeInfo* getPlayerArrayType() {
|
||||
return (asITypeInfo*)asGetActiveContext()->GetEngine()->GetUserData(EDID_playerArray);
|
||||
}
|
||||
|
||||
static CScriptArray* getPlayers() {
|
||||
CScriptArray* results = new CScriptArray(0, getPlayerArrayType());
|
||||
results->Reserve(devices.network->players.size());
|
||||
|
||||
{
|
||||
threads::ReadLock lock(devices.network->playerLock);
|
||||
foreach(it, devices.network->players)
|
||||
results->InsertLast(&it->second);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
static Player* getPlayer(int id) {
|
||||
return devices.network->getPlayer(id);
|
||||
}
|
||||
|
||||
static std::string playerName(Player& player) {
|
||||
return std::string(player.nickname);
|
||||
}
|
||||
|
||||
static void ctor_addr(void* mem) {
|
||||
new(mem) net::Address();
|
||||
}
|
||||
|
||||
static void ctor_addrv(void* mem, const std::string& hostname, int port) {
|
||||
new(mem) net::Address(hostname, port);
|
||||
}
|
||||
|
||||
static net::Address& cpy_addr(net::Address& into, const net::Address& from) {
|
||||
into = from;
|
||||
return into;
|
||||
}
|
||||
|
||||
static bool eq_addr(const net::Address& addr, const net::Address& other) {
|
||||
return addr == other;
|
||||
}
|
||||
|
||||
static void dtor_addr(net::Address& addr) {
|
||||
addr.~Address();
|
||||
}
|
||||
|
||||
static void ctor_game(void* mem) {
|
||||
new(mem) net::Game();
|
||||
}
|
||||
|
||||
static net::Game& cpy_game(net::Game& into, const net::Game& from) {
|
||||
into = from;
|
||||
return into;
|
||||
}
|
||||
|
||||
static void dtor_game(net::Game& addr) {
|
||||
addr.~Game();
|
||||
}
|
||||
|
||||
static void queryServers() {
|
||||
devices.network->queryServers();
|
||||
}
|
||||
|
||||
static bool isQuerying() {
|
||||
return devices.network->query && devices.network->query->updating;
|
||||
}
|
||||
|
||||
static void getQueriedServers(CScriptArray* arr) {
|
||||
threads::Mutex mtx(devices.network->queryMtx);
|
||||
std::vector<net::Game>& list = devices.network->queryResult;
|
||||
foreach(it, list)
|
||||
arr->InsertLast(&(*it));
|
||||
list.clear();
|
||||
}
|
||||
|
||||
static void mpKick(int playerId) {
|
||||
devices.network->kick(playerId);
|
||||
}
|
||||
|
||||
static void mpConnect(net::Game& game, bool disablePunchthrough, const std::string& pwd) {
|
||||
devices.network->connect(game, disablePunchthrough, pwd);
|
||||
}
|
||||
|
||||
static void hostGame(const std::string& gamename, int port, unsigned maxPlayers, bool isPublic, bool punchthrough, const std::string& password) {
|
||||
devices.network->host(gamename, port, maxPlayers, isPublic, punchthrough, password);
|
||||
}
|
||||
|
||||
static unsigned dcReason() {
|
||||
return devices.network->disconnection;
|
||||
}
|
||||
|
||||
static float glxProgress() {
|
||||
return devices.network->galaxyProgress;
|
||||
}
|
||||
|
||||
static bool glxAwaiting() {
|
||||
return devices.network->isClient && devices.network->serverReady &&
|
||||
!devices.network->currentPlayer.hasGalaxy;
|
||||
}
|
||||
|
||||
class IsolateAction : public processing::Action {
|
||||
asIScriptObject* obj;
|
||||
public:
|
||||
IsolateAction(asIScriptObject* object) : obj(object) {}
|
||||
|
||||
bool run() {
|
||||
auto* func = obj->GetObjectType()->GetMethodByDecl("void call()");
|
||||
if(func) {
|
||||
auto& mana = scripts::Manager::fromEngine(obj->GetEngine());
|
||||
auto call = mana.call(func);
|
||||
call.setObject(obj);
|
||||
call.call();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
~IsolateAction() {
|
||||
obj->Release();
|
||||
}
|
||||
};
|
||||
|
||||
static void runIsolate(asIScriptObject* obj) {
|
||||
if(obj == nullptr)
|
||||
return;
|
||||
auto* act = new IsolateAction(obj);
|
||||
processing::queueIsolationAction(act);
|
||||
}
|
||||
|
||||
void RegisterEventBinds(bool server, bool shadow, bool menu) {
|
||||
threads::Lock lock(eventDescMutex);
|
||||
|
||||
ClassBind player("Player", asOBJ_REF | asOBJ_NOCOUNT, 0);
|
||||
player.addMember("const int id", offsetof(Player, id));
|
||||
player.addMember("Empire@ emp", offsetof(Player, emp));
|
||||
if(server) {
|
||||
player.addMember("uint controlMask", offsetof(Player, controlMask));
|
||||
player.addMember("uint viewMask", offsetof(Player, viewMask));
|
||||
}
|
||||
else {
|
||||
player.addMember("const uint controlMask", offsetof(Player, controlMask));
|
||||
player.addMember("const uint viewMask", offsetof(Player, viewMask));
|
||||
}
|
||||
player.addMethod("bool controls(Empire& emp)", asMETHOD(Player, controls));
|
||||
player.addMethod("bool views(Empire& emp)", asMETHOD(Player, views));
|
||||
player.addExternMethod("string get_name()", asFUNCTION(playerName));
|
||||
player.addExternMethod("bool opEquals(const Player& other) const", asFUNCTION(playerEquals));
|
||||
if(server)
|
||||
player.addExternMethod("void linkEmpire(Empire@ empire)", asFUNCTION(linkEmpire));
|
||||
|
||||
bindGlobal("const Player ALL_PLAYERS", &ALL_PLAYERS);
|
||||
bindGlobal("const Player SERVER_PLAYER", &SERVER_PLAYER);
|
||||
bindGlobal("Player CURRENT_PLAYER", &devices.network->currentPlayer);
|
||||
bind("array<Player@>@ getPlayers()", asFUNCTION(getPlayers));
|
||||
bind("Player@ getPlayer(int id)", asFUNCTION(getPlayer));
|
||||
|
||||
ClassBind ga("GameAddress", asOBJ_VALUE | asOBJ_APP_CLASS_CDA, sizeof(net::Address));
|
||||
ga.addConstructor("void f()", asFUNCTION(ctor_addr));
|
||||
ga.addConstructor("void f(const string& hostname, int port = 2048)", asFUNCTION(ctor_addrv));
|
||||
ga.addDestructor("void f()", asFUNCTION(dtor_addr));
|
||||
ga.addExternMethod("GameAddress& opAssign(const GameAddress& other)", asFUNCTION(cpy_addr));
|
||||
ga.addExternMethod("bool opEquals(const GameAddress& other) const", asFUNCTION(eq_addr));
|
||||
ga.addMember("int port", offsetof(net::Address, port));
|
||||
ga.addMethod("string toString(bool showPort = true) const", asMETHOD(net::Address, toString));
|
||||
|
||||
ClassBind gs("GameServer", asOBJ_VALUE | asOBJ_APP_CLASS_CDA, sizeof(net::Game));
|
||||
gs.addConstructor("void f()", asFUNCTION(ctor_game));
|
||||
gs.addDestructor("void f()", asFUNCTION(dtor_game));
|
||||
gs.addExternMethod("GameServer& opAssign(const GameServer& other)", asFUNCTION(cpy_game));
|
||||
gs.addMember("GameAddress address", offsetof(net::Game, address));
|
||||
gs.addMember("string name", offsetof(net::Game, name));
|
||||
gs.addMember("string mod", offsetof(net::Game, mod));
|
||||
gs.addMember("uint16 players", offsetof(net::Game, players));
|
||||
gs.addMember("uint16 maxPlayers", offsetof(net::Game, maxPlayers));
|
||||
gs.addMember("int punchPort", offsetof(net::Game, punchPort));
|
||||
gs.addMember("int version", offsetof(net::Game, version));
|
||||
gs.addMember("bool started", offsetof(net::Game, started));
|
||||
gs.addMember("bool isLocal", offsetof(net::Game, isLocal));
|
||||
gs.addMember("bool password", offsetof(net::Game, password));
|
||||
player.addMember("GameAddress address", offsetof(Player, address));
|
||||
|
||||
EnumBind dr("DisconnectReason");
|
||||
dr["DR_Timeout"] = net::DR_Timeout;
|
||||
dr["DR_Error"] = net::DR_Error;
|
||||
dr["DR_Close"] = net::DR_Close;
|
||||
dr["DR_Kick"] = net::DR_Kick;
|
||||
dr["DR_Version"] = net::DR_Version;
|
||||
dr["DR_Password"] = net::DR_Password;
|
||||
|
||||
bind("DisconnectReason get_mpDisconnectReason()", asFUNCTION(dcReason));
|
||||
bind("float get_galaxySendProgress()", asFUNCTION(glxProgress));
|
||||
bind("bool get_awaitingGalaxy()", asFUNCTION(glxAwaiting));
|
||||
bind("void mpQueryServers()", asFUNCTION(queryServers));
|
||||
bind("bool mpIsQuerying()", asFUNCTION(isQuerying));
|
||||
bind("void mpGetServers(array<GameServer>& list)", asFUNCTION(getQueriedServers));
|
||||
bind("void mpKick(int playerId)", asFUNCTION(mpKick));
|
||||
bind("void mpHost(const string& gamename = \"\", uint port = 2048, uint maxPlayers = 0, bool isPublic = true, bool punchthrough = true, const string& password = \"\")",
|
||||
asFUNCTION(hostGame));
|
||||
bind("void mpConnect(const GameServer& game, bool disablePunchthrough = false, const string& password = \"\")", asFUNCTION(mpConnect));
|
||||
|
||||
if(void* plArray = getEngine()->GetTypeInfoById(getEngine()->GetTypeIdByDecl("array<Player@>")))
|
||||
getEngine()->SetUserData(plArray, EDID_playerArray);
|
||||
|
||||
if(server) {
|
||||
if(!shadow)
|
||||
bindGlobal("Player HOST_PLAYER", &devices.network->currentPlayer);
|
||||
}
|
||||
bindGlobal("int MP_VERSION", &NetworkManager::MP_VERSION);
|
||||
|
||||
foreach(it, evtDescs) {
|
||||
EventDesc* desc = *it;
|
||||
if(desc->recvMenu && !menu)
|
||||
continue;
|
||||
|
||||
//Register the functions to send
|
||||
if(server) {
|
||||
if(!desc->recvServer) {
|
||||
if(shadow)
|
||||
bindGeneric(desc->sendToServer, handleSendToClient_local, desc, true);
|
||||
else
|
||||
bindGeneric(desc->sendToClient, handleSendToClient, desc, true);
|
||||
}
|
||||
}
|
||||
else if(menu && desc->recvMenu) {
|
||||
if(desc->recvServer)
|
||||
bindGeneric(desc->sendToServer, handleSendToServer, desc, true);
|
||||
else
|
||||
bindGeneric(desc->sendToClient, handleSendToClient, desc, true);
|
||||
}
|
||||
else {
|
||||
if(desc->recvServer)
|
||||
bindGeneric(desc->sendToServer, handleSendToServer, desc, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Adding console commands
|
||||
InterfaceBind isolateClass("IsolateHook");
|
||||
isolateClass.addMethod("void call()");
|
||||
bind("void isolate_run(IsolateHook@ hook)", asFUNCTION(runIsolate));
|
||||
}
|
||||
|
||||
};
|
||||
Reference in New Issue
Block a user