1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-06-15 00:05:02 +02:00

Entities redesign and a few ERM features

* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
This commit is contained in:
AlexVinS
2018-03-17 17:58:30 +03:00
committed by AlexVinS
parent 11bb46780a
commit ecaa9f5d0b
475 changed files with 22491 additions and 7123 deletions

View File

@ -44,11 +44,12 @@
#include "lobby/CBonusSelection.h"
#include "battle/CBattleInterface.h"
#include "../lib/CThreadHelper.h"
#include "../lib/CScriptingModule.h"
#include "../lib/registerTypes/RegisterTypes.h"
#include "gui/CGuiHandler.h"
#include "CMT.h"
#include "CServerHandler.h"
#include "../lib/ScriptHandler.h"
#include <vcmi/events/EventBus.h>
#ifdef VCMI_ANDROID
#include "lib/CAndroidVMHelper.h"
@ -105,6 +106,39 @@ public:
}
};
CPlayerEnvironment::CPlayerEnvironment(PlayerColor player_, CClient * cl_, std::shared_ptr<CCallback> mainCallback_)
: player(player_),
cl(cl_),
mainCallback(mainCallback_)
{
}
const Services * CPlayerEnvironment::services() const
{
return VLC;
}
vstd::CLoggerBase * CPlayerEnvironment::logger() const
{
return logGlobal;
}
events::EventBus * CPlayerEnvironment::eventBus() const
{
return cl->eventBus();//always get actual value
}
const CPlayerEnvironment::BattleCb * CPlayerEnvironment::battle() const
{
return mainCallback.get();
}
const CPlayerEnvironment::GameCb * CPlayerEnvironment::game() const
{
return mainCallback.get();
}
CClient::CClient()
{
@ -114,7 +148,36 @@ CClient::CClient()
registerTypesClientPacks2(*applier);
IObjectInterface::cb = this;
gs = nullptr;
erm = nullptr;
}
CClient::~CClient()
{
IObjectInterface::cb = nullptr;
}
const Services * CClient::services() const
{
return VLC; //todo: this should be CGI
}
const CClient::BattleCb * CClient::battle() const
{
return this;
}
const CClient::GameCb * CClient::game() const
{
return this;
}
vstd::CLoggerBase * CClient::logger() const
{
return logGlobal;
}
events::EventBus * CClient::eventBus() const
{
return clientEventBus.get();
}
void CClient::newGame()
@ -122,11 +185,14 @@ void CClient::newGame()
CSH->th->update();
CMapService mapService;
gs = new CGameState();
gs->preInit(VLC);
logNetwork->trace("\tCreating gamestate: %i", CSH->th->getDiff());
gs->init(&mapService, CSH->si.get(), settings["general"]["saveRandomMaps"].Bool());
logNetwork->trace("Initializing GameState (together): %d ms", CSH->th->getDiff());
initMapHandler();
reinitScripting();
initPlayerEnvironments();
initPlayerInterfaces();
}
@ -168,10 +234,16 @@ void CClient::loadGame()
throw; //obviously we cannot continue here
}
logNetwork->trace("Loaded common part of save %d ms", CSH->th->getDiff());
gs->preInit(VLC);
gs->updateOnLoad(CSH->si.get());
initMapHandler();
reinitScripting();
initPlayerEnvironments();
serialize(loader->serializer, loader->serializer.fileVersion);
initPlayerInterfaces();
}
@ -190,6 +262,13 @@ void CClient::serialize(BinarySerializer & h, const int version)
h & i->second->human;
i->second->saveGame(h, version);
}
if(version >= 800)
{
JsonNode scriptsState;
clientScripts->serializeState(h.saving, scriptsState);
h & scriptsState;
}
}
void CClient::serialize(BinaryDeserializer & h, const int version)
@ -253,6 +332,17 @@ void CClient::serialize(BinaryDeserializer & h, const int version)
}
nInt.reset();
}
{
JsonNode scriptsState;
if(version >= 800)
{
h & scriptsState;
}
clientScripts->serializeState(h.saving, scriptsState);
}
logNetwork->trace("Loaded client part of save %d ms", CSH->th->getDiff());
}
@ -270,6 +360,8 @@ void CClient::save(const std::string & fname)
void CClient::endGame()
{
clientScripts.reset();
//suggest interfaces to finish their stuff (AI should interrupt any bg working threads)
for(auto & i : playerint)
i.second->finish();
@ -296,8 +388,8 @@ void CClient::endGame()
playerint.clear();
battleints.clear();
callbacks.clear();
battleCallbacks.clear();
playerEnvironments.clear();
logNetwork->info("Deleted playerInts.");
logNetwork->info("Client stopped.");
}
@ -319,6 +411,24 @@ void CClient::initMapHandler()
pathCache.clear();
}
void CClient::initPlayerEnvironments()
{
playerEnvironments.clear();
auto allPlayers = CSH->getAllClientPlayers(CSH->c->connectionID);
for(auto & color : allPlayers)
{
logNetwork->info("Preparing environment for player %s", color.getStr());
playerEnvironments[color] = std::make_shared<CPlayerEnvironment>(color, this, std::make_shared<CCallback>(gs, color, this));
}
if(settings["session"]["spectate"].Bool())
{
playerEnvironments[PlayerColor::SPECTATOR] = std::make_shared<CPlayerEnvironment>(PlayerColor::SPECTATOR, this, std::make_shared<CCallback>(gs, boost::none, this));
}
}
void CClient::initPlayerInterfaces()
{
for(auto & elem : gs->scenarioOps->playerInfos)
@ -327,19 +437,20 @@ void CClient::initPlayerInterfaces()
if(!vstd::contains(CSH->getAllClientPlayers(CSH->c->connectionID), color))
continue;
if(vstd::contains(playerint, color))
continue;
logNetwork->trace("Preparing interface for player %s", color.getStr());
if(elem.second.isControlledByAI())
if(!vstd::contains(playerint, color))
{
auto AiToGive = aiNameForPlayer(elem.second, false);
logNetwork->info("Player %s will be lead by %s", color, AiToGive);
installNewPlayerInterface(CDynLibHandler::getNewAI(AiToGive), color);
}
else
{
installNewPlayerInterface(std::make_shared<CPlayerInterface>(color), color);
logNetwork->info("Preparing interface for player %s", color.getStr());
if(elem.second.isControlledByAI())
{
auto AiToGive = aiNameForPlayer(elem.second, false);
logNetwork->info("Player %s will be lead by %s", color.getStr(), AiToGive);
installNewPlayerInterface(CDynLibHandler::getNewAI(AiToGive), color);
}
else
{
logNetwork->info("Player %s will be lead by human", color.getStr());
installNewPlayerInterface(std::make_shared<CPlayerInterface>(color), color);
}
}
}
@ -379,41 +490,32 @@ std::string CClient::aiNameForPlayer(bool battleAI)
return goodAI;
}
void CClient::installNewPlayerInterface(std::shared_ptr<CGameInterface> gameInterface, boost::optional<PlayerColor> color, bool battlecb)
void CClient::installNewPlayerInterface(std::shared_ptr<CGameInterface> gameInterface, PlayerColor color, bool battlecb)
{
boost::unique_lock<boost::recursive_mutex> un(*CPlayerInterface::pim);
PlayerColor colorUsed = color.get_value_or(PlayerColor::UNFLAGGABLE);
if(!color)
privilegedGameEventReceivers.push_back(gameInterface);
playerint[color] = gameInterface;
playerint[colorUsed] = gameInterface;
logGlobal->trace("\tInitializing the interface for player %s", colorUsed);
logGlobal->trace("\tInitializing the interface for player %s", color.getStr());
auto cb = std::make_shared<CCallback>(gs, color, this);
callbacks[colorUsed] = cb;
battleCallbacks[colorUsed] = cb;
gameInterface->init(cb);
battleCallbacks[color] = cb;
gameInterface->init(playerEnvironments.at(color), cb);
installNewBattleInterface(gameInterface, color, battlecb);
}
void CClient::installNewBattleInterface(std::shared_ptr<CBattleGameInterface> battleInterface, boost::optional<PlayerColor> color, bool needCallback)
void CClient::installNewBattleInterface(std::shared_ptr<CBattleGameInterface> battleInterface, PlayerColor color, bool needCallback)
{
boost::unique_lock<boost::recursive_mutex> un(*CPlayerInterface::pim);
PlayerColor colorUsed = color.get_value_or(PlayerColor::UNFLAGGABLE);
if(!color)
privilegedBattleEventReceivers.push_back(battleInterface);
battleints[colorUsed] = battleInterface;
battleints[color] = battleInterface;
if(needCallback)
{
logGlobal->trace("\tInitializing the battle interface for player %s", *color);
logGlobal->trace("\tInitializing the battle interface for player %s", color.getStr());
auto cbc = std::make_shared<CBattleCallback>(color, this);
battleCallbacks[colorUsed] = cbc;
battleInterface->init(cbc);
battleCallbacks[color] = cbc;
battleInterface->init(playerEnvironments.at(color), cbc);
}
}
@ -437,14 +539,6 @@ void CClient::handlePack(CPack * pack)
delete pack;
}
void CClient::commitPackage(CPackForClient * pack)
{
CommitPackage cp;
cp.freePack = false;
cp.packToCommit = pack;
sendRequest(&cp, PlayerColor::NEUTRAL);
}
int CClient::sendRequest(const CPackForServer * request, PlayerColor player)
{
static ui32 requestCounter = 0;
@ -464,6 +558,7 @@ int CClient::sendRequest(const CPackForServer * request, PlayerColor player)
void CClient::battleStarted(const BattleInfo * info)
{
setBattle(info);
for(auto & battleCb : battleCallbacks)
{
if(vstd::contains_if(info->sides, [&](const SideInBattle& side) {return side.color == battleCb.first; })
@ -472,9 +567,6 @@ void CClient::battleStarted(const BattleInfo * info)
battleCb.second->setBattle(info);
}
}
// for(ui8 side : info->sides)
// if(battleCallbacks.count(side))
// battleCallbacks[side]->setBattle(info);
std::shared_ptr<CPlayerInterface> att, def;
auto & leftSide = info->sides[0], & rightSide = info->sides[1];
@ -552,6 +644,8 @@ void CClient::battleFinished()
if(settings["session"]["spectate"].Bool() && !settings["session"]["spectate-skip-battle"].Bool())
battleCallbacks[PlayerColor::SPECTATOR]->setBattle(nullptr);
setBattle(nullptr);
}
void CClient::startPlayerBattleAction(PlayerColor color)
@ -645,6 +739,23 @@ PlayerColor CClient::getLocalPlayer() const
return getCurrentPlayer();
}
scripting::Pool * CClient::getGlobalContextPool() const
{
return clientScripts.get();
}
scripting::Pool * CClient::getContextPool() const
{
return clientScripts.get();
}
void CClient::reinitScripting()
{
clientEventBus = make_unique<events::EventBus>();
clientScripts.reset(new scripting::PoolImpl(this));
}
#ifdef VCMI_ANDROID
extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_notifyServerClosed(JNIEnv * env, jobject cls)
{