File indexing completed on 2024-05-19 05:40:49

0001 /***************************************************************************
0002  *  Copyright (C) 2021 by Renaud Guezennec                               *
0003  *   http://www.rolisteam.org/contact                                      *
0004  *                                                                         *
0005  *   This software is free software; you can redistribute it and/or modify *
0006  *   it under the terms of the GNU General Public License as published by  *
0007  *   the Free Software Foundation; either version 2 of the License, or     *
0008  *   (at your option) any later version.                                   *
0009  *                                                                         *
0010  *   This program is distributed in the hope that it will be useful,       *
0011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0013  *   GNU General Public License for more details.                          *
0014  *                                                                         *
0015  *   You should have received a copy of the GNU General Public License     *
0016  *   along with this program; if not, write to the                         *
0017  *   Free Software Foundation, Inc.,                                       *
0018  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
0019  ***************************************************************************/
0020 #include "updater/media/campaignupdater.h"
0021 
0022 #include "data/campaign.h"
0023 #include "data/media.h"
0024 #include "diceparser/dicealias.h"
0025 #include "diceparser_qobject/diceroller.h"
0026 #include "model/characterstatemodel.h"
0027 #include "model/dicealiasmodel.h"
0028 #include "model/nonplayablecharactermodel.h"
0029 #include "utils/logcategories.h"
0030 #include "worker/fileserializer.h"
0031 #include "worker/messagehelper.h"
0032 #include <QDir>
0033 
0034 namespace campaign
0035 {
0036 CampaignUpdater::CampaignUpdater(DiceRoller* dice, Campaign* manager, QObject* parent)
0037     : QObject(parent), m_campaign(manager), m_dice(dice)
0038 {
0039     setCampaign(manager);
0040 
0041     ReceiveEvent::registerNetworkReceiver(NetMsg::CampaignCategory, this);
0042 }
0043 
0044 void CampaignUpdater::setCampaign(Campaign* campaign)
0045 {
0046     if(campaign == m_campaign)
0047         return;
0048     m_campaign= campaign;
0049 
0050     // GM player
0051     auto model= m_campaign->diceAliases();
0052 
0053     connect(model, &DiceAliasModel::aliasAdded, this, &CampaignUpdater::updateDiceAliases);
0054     connect(model, &DiceAliasModel::aliasRemoved, this, &CampaignUpdater::updateDiceAliases);
0055     connect(model, &DiceAliasModel::aliasMoved, this, &CampaignUpdater::updateDiceAliases);
0056     connect(model, &DiceAliasModel::modelReset, this, &CampaignUpdater::updateDiceAliases);
0057     connect(model, &DiceAliasModel::dataChanged, this, &CampaignUpdater::updateDiceAliases);
0058     connect(model, &DiceAliasModel::aliasChanged, this, &CampaignUpdater::updateDiceAliases);
0059 
0060     updateDiceAliases();
0061 
0062     // GM player
0063     auto states= m_campaign->stateModel();
0064 
0065     auto updateState= [this]()
0066     {
0067         if(!canForward())
0068             return;
0069         auto const& states= m_campaign->stateModel()->statesList();
0070         FileSerializer::writeStatesIntoCampaign(m_campaign->rootDirectory(),
0071                                                 FileSerializer::statesToArray(states, m_campaign->rootDirectory()));
0072         updateStateModel();
0073         auto list= new QList<CharacterState*>();
0074         std::transform(std::begin(states), std::end(states), std::back_inserter(*list),
0075                        [](const std::unique_ptr<CharacterState>& item) { return item.get(); });
0076         Character::setListOfCharacterState(list);
0077     };
0078 
0079     connect(states, &CharacterStateModel::characterStateAdded, this, updateState);
0080     connect(states, &CharacterStateModel::stateRemoved, this, updateState);
0081     connect(states, &CharacterStateModel::stateMoved, this, updateState);
0082     connect(states, &CharacterStateModel::modelReset, this, updateState);
0083     connect(states, &CharacterStateModel::dataChanged, this, updateState);
0084     connect(states, &CharacterStateModel::stateChanged, this, updateState);
0085 
0086     // updateNPCModel
0087     auto npcModel= m_campaign->npcModel();
0088     auto updateNpcModel= [this]()
0089     {
0090         auto const& npcs= m_campaign->npcModel()->npcList();
0091         if(!npcs.empty())
0092             FileSerializer::writeNpcIntoCampaign(m_campaign->rootDirectory(),
0093                                                  FileSerializer::npcToArray(npcs, m_campaign->rootDirectory()));
0094     };
0095     connect(npcModel, &NonPlayableCharacterModel::characterAdded, this, updateNpcModel);
0096     connect(npcModel, &NonPlayableCharacterModel::characterRemoved, this, updateNpcModel);
0097     connect(npcModel, &NonPlayableCharacterModel::dataChanged, this, updateNpcModel);
0098     connect(npcModel, &NonPlayableCharacterModel::modelReset, this, updateNpcModel);
0099 
0100     auto updateCampaign= [this]()
0101     { FileSerializer::writeCampaignInfo(m_campaign->rootDirectory(), FileSerializer::campaignToObject(m_campaign)); };
0102 
0103     connect(m_campaign, &Campaign::nameChanged, this, updateCampaign);
0104     connect(m_campaign, &Campaign::currentChapterChanged, this, updateCampaign);
0105     connect(m_campaign, &Campaign::mediaAdded, this, updateCampaign);
0106     connect(m_campaign, &Campaign::mediaNameChanged, this, updateCampaign);
0107     connect(m_campaign, &Campaign::mediaRemoved, this, updateCampaign);
0108 }
0109 
0110 NetWorkReceiver::SendType CampaignUpdater::processMessage(NetworkMessageReader* msg)
0111 {
0112     if(msg->action() == NetMsg::CharactereStateModel && msg->category() == NetMsg::CampaignCategory && !m_localIsGm)
0113     {
0114         setUpdating(true);
0115         MessageHelper::fetchCharacterStatesFromNetwork(msg, m_campaign->stateModel());
0116         setUpdating(false);
0117     }
0118     else if(msg->action() == NetMsg::DiceAliasModel && msg->category() == NetMsg::CampaignCategory && !m_localIsGm)
0119     {
0120         MessageHelper::fetchDiceAliasFromNetwork(msg, m_dice->aliases());
0121     }
0122     return NetWorkReceiver::NONE;
0123 }
0124 
0125 DiceRoller* CampaignUpdater::diceParser() const
0126 {
0127     return m_dice;
0128 }
0129 
0130 bool CampaignUpdater::localIsGM()
0131 {
0132     return m_localIsGm;
0133 }
0134 
0135 void CampaignUpdater::updateDiceModel()
0136 {
0137     if(localIsGM())
0138         MessageHelper::sendOffAllDiceAlias(m_campaign->diceAliases());
0139 }
0140 
0141 void CampaignUpdater::updateStateModel()
0142 {
0143     if(localIsGM())
0144         MessageHelper::sendOffAllCharacterState(m_campaign->stateModel());
0145 }
0146 
0147 void CampaignUpdater::saveCampaignTo(const QString& dir)
0148 {
0149     createCampaignTemplate(dir);
0150     saveDataInto(dir);
0151 }
0152 
0153 void CampaignUpdater::save()
0154 {
0155     saveDataInto(m_campaign->rootDirectory());
0156 }
0157 
0158 void CampaignUpdater::saveDataInto(const QString& path)
0159 {
0160     // Dice Aliases
0161     const auto& newAliases= m_campaign->diceAliases()->aliases();
0162     FileSerializer::writeDiceAliasIntoCampaign(path, FileSerializer::dicesToArray(newAliases));
0163 
0164     // States
0165     auto const& states= m_campaign->stateModel()->statesList();
0166     if(!states.empty())
0167         FileSerializer::writeStatesIntoCampaign(path, FileSerializer::statesToArray(states, path));
0168 
0169     // NPC
0170 
0171     auto const& npcs= m_campaign->npcModel()->npcList();
0172     if(!npcs.empty())
0173         FileSerializer::writeNpcIntoCampaign(path, FileSerializer::npcToArray(npcs, m_campaign->rootDirectory()));
0174 
0175     // Campaign Info
0176     FileSerializer::writeCampaignInfo(path, FileSerializer::campaignToObject(m_campaign));
0177 }
0178 
0179 void CampaignUpdater::setLocalIsGM(bool b)
0180 {
0181     if(b == m_localIsGm)
0182         return;
0183     m_localIsGm= b;
0184     emit localIsGMChanged();
0185 }
0186 
0187 bool CampaignUpdater::createCampaignTemplate(const QString& dirPath)
0188 {
0189     auto dir= QDir(dirPath);
0190 
0191     if(dir.exists() && !dir.isEmpty())
0192     {
0193         qCInfo(logCategory::campaign) << tr("'%1' is not empty").arg(dirPath);
0194         return false;
0195     }
0196     else if(!dir.exists())
0197     {
0198         auto parentDir= dir;
0199         parentDir.cdUp();
0200         if(!parentDir.mkdir(dirPath))
0201         {
0202             qCInfo(logCategory::campaign) << tr("Could not create '%1'").arg(dirPath);
0203             return false;
0204         }
0205         FileSerializer::createCampaignDirectory(dirPath);
0206     }
0207     else
0208     {
0209         FileSerializer::createCampaignDirectory(dirPath);
0210     }
0211     return true;
0212 }
0213 
0214 void CampaignUpdater::updateDiceAliases()
0215 {
0216     if(!canForward())
0217         return;
0218     auto aliases= m_dice->aliases();
0219     if(!aliases)
0220         return;
0221     qDeleteAll(*aliases);
0222     aliases->clear();
0223     const auto& newAliases= m_campaign->diceAliases()->aliases();
0224     std::for_each(std::begin(newAliases), std::end(newAliases),
0225                   [aliases](const std::unique_ptr<DiceAlias>& alias)
0226                   {
0227                       auto p= alias.get();
0228                       aliases->append(new DiceAlias(*p));
0229                   });
0230 
0231     FileSerializer::writeDiceAliasIntoCampaign(m_campaign->rootDirectory(), FileSerializer::dicesToArray(newAliases));
0232     updateDiceModel();
0233 }
0234 
0235 void CampaignUpdater::setUpdating(bool b)
0236 {
0237     m_updatingModel= b;
0238 }
0239 
0240 bool CampaignUpdater::canForward()
0241 {
0242     return !m_updatingModel && m_localIsGm;
0243 }
0244 } // namespace campaign