mirror of
https://github.com/vcmi/vcmi.git
synced 2024-11-24 08:32:34 +02:00
- ZipArchive namespace for operations with zip archives, located in CZipLoader.h/cpp.
- new fields in mod format, for use with mod manager (check config/shemas/mod.json for details) - removed some 0.92 compatibility from mods loading - several compile fixes
This commit is contained in:
parent
38c1542d9d
commit
5654fef901
@ -1612,7 +1612,7 @@ void VCAI::reserveObject(HeroPtr h, const CGObjectInstance *obj)
|
||||
{
|
||||
reservedObjs.push_back(obj);
|
||||
reservedHeroesMap[h].push_back(obj);
|
||||
logAi->debugStream() << "reserved object id=" << obj->id << "; address=" << (int)obj << "; name=" << obj->getHoverText();
|
||||
logAi->debugStream() << "reserved object id=" << obj->id << "; address=" << (intptr_t)obj << "; name=" << obj->getHoverText();
|
||||
}
|
||||
|
||||
void VCAI::validateVisitableObjs()
|
||||
|
@ -1,5 +1,8 @@
|
||||
project(vcmi)
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
# TODO:
|
||||
# 1) Detection of system version of minizip and use it instead of local
|
||||
# 2) Detection of Qt5 and compilation of launcher, unless explicitly disabled
|
||||
|
||||
# where to look for cmake modules
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_HOME_DIRECTORY}/cmake_modules)
|
||||
@ -16,6 +19,7 @@ set(VCMI_VERSION_PATCH 0)
|
||||
|
||||
option(ENABLE_ERM "Enable compilation of ERM scripting module" OFF)
|
||||
option(ENABLE_EDITOR "Enable compilation of map editor" OFF)
|
||||
option(ENABLE_LAUNCHER "Enable compilation of launcher" OFF)
|
||||
option(ENABLE_TEST "Enable compilation of unit tests" OFF)
|
||||
|
||||
############################################
|
||||
@ -52,11 +56,15 @@ find_package(SDL_mixer REQUIRED)
|
||||
find_package(SDL_ttf REQUIRED)
|
||||
find_package(ZLIB REQUIRED)
|
||||
|
||||
if (ENABLE_EDITOR)
|
||||
if (ENABLE_EDITOR OR ENABLE_LAUNCHER)
|
||||
# Widgets finds its own dependencies (QtGui and QtCore).
|
||||
find_package(Qt5Widgets REQUIRED)
|
||||
endif()
|
||||
|
||||
if (ENABLE_LAUNCHER)
|
||||
find_package(Qt5Network REQUIRED)
|
||||
endif()
|
||||
|
||||
if(ENABLE_TEST)
|
||||
# find_package overwrites BOOST_* variables which are already set, so all components have to be
|
||||
# included again
|
||||
@ -133,6 +141,9 @@ endif()
|
||||
if (ENABLE_EDITOR)
|
||||
add_subdirectory(editor)
|
||||
endif()
|
||||
if (ENABLE_LAUNCHER)
|
||||
add_subdirectory(launcher)
|
||||
endif()
|
||||
if(ENABLE_TEST)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
@ -1,4 +1,25 @@
|
||||
{
|
||||
"name" : "In The Wake of Gods",
|
||||
"description" : "Unnofficial addon for Heroes of Might and Magic III",
|
||||
|
||||
"version" : "3.58.0",
|
||||
"author" : "WoG Team",
|
||||
|
||||
"artifacts" :
|
||||
[
|
||||
"config/wog/artifacts.json"
|
||||
],
|
||||
|
||||
"creatures" :
|
||||
[
|
||||
"config/wog/creatures.json"
|
||||
],
|
||||
|
||||
"factions" :
|
||||
[
|
||||
"config/wog/factions.json"
|
||||
],
|
||||
|
||||
"filesystem":
|
||||
{
|
||||
"" :
|
||||
@ -39,23 +60,5 @@
|
||||
[
|
||||
{"type" : "dir", "path" : "/Maps"}
|
||||
]
|
||||
},
|
||||
|
||||
"name" : "In The Wake of Gods",
|
||||
"description" : "Unnofficial addon for Heroes of Might and Magic III",
|
||||
|
||||
"artifacts" :
|
||||
[
|
||||
"config/wog/artifacts.json"
|
||||
],
|
||||
|
||||
"creatures" :
|
||||
[
|
||||
"config/wog/creatures.json"
|
||||
],
|
||||
|
||||
"factions" :
|
||||
[
|
||||
"config/wog/factions.json"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,10 @@
|
||||
{
|
||||
"name" : "VCMI essential files",
|
||||
"description" : "Essential files required for VCMI to run correctly",
|
||||
|
||||
"version" : "0.0",
|
||||
"author" : "VCMI Team",
|
||||
|
||||
"filesystem":
|
||||
{
|
||||
"DATA/" :
|
||||
@ -13,8 +19,5 @@
|
||||
[
|
||||
{"type" : "dir", "path" : "/Maps"}
|
||||
]
|
||||
},
|
||||
|
||||
"name" : "VCMI essential files",
|
||||
"description" : "Essential files required for VCMI to run correctly"
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
"$schema": "http://json-schema.org/draft-04/schema",
|
||||
"title" : "VCMI mod file format",
|
||||
"description" : "Format used to define main mod file (mod.json) in VCMI",
|
||||
"required" : [ "name", "description" ],
|
||||
"required" : [ "name", "description", "version", "author" ],
|
||||
|
||||
"additionalProperties" : false,
|
||||
"properties":{
|
||||
@ -16,6 +16,26 @@
|
||||
"description": "More lengthy description of mod. No hard limit"
|
||||
},
|
||||
|
||||
"modType" : {
|
||||
"type":"string",
|
||||
"description": "Type of mod, e.g. Town, Artifacts, Graphical."
|
||||
},
|
||||
|
||||
"version" : {
|
||||
"type":"string",
|
||||
"description": "Current mod version, up to 3 numbers, dot-separated. Format: A.B.C"
|
||||
},
|
||||
|
||||
"author" : {
|
||||
"type":"string",
|
||||
"description": "Author of the mod. Can be nickname, real name or name of team"
|
||||
},
|
||||
|
||||
"weblink" : {
|
||||
"type":"string",
|
||||
"description": "Home page of mod or link to forum thread"
|
||||
},
|
||||
|
||||
"depends": {
|
||||
"type":"array",
|
||||
"description": "List of mods that are required to run this one",
|
||||
@ -69,7 +89,7 @@
|
||||
},
|
||||
"type": {
|
||||
"type" : "string",
|
||||
"enum" : [ "dir", "lod", "snd", "vid", "map" ],
|
||||
"enum" : [ "dir", "lod", "snd", "vid", "map", "zip" ],
|
||||
"description" : "Type of data source"
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
{
|
||||
"type" : "object",
|
||||
"$schema": "http://json-schema.org/draft-04/schema",
|
||||
"required" : [ "general", "video", "adventure", "battle", "server", "logging" ],
|
||||
"required" : [ "general", "video", "adventure", "battle", "server", "logging", "launcher" ],
|
||||
"definitions" : {
|
||||
"logLevelEnum" : {
|
||||
"type" : "string",
|
||||
@ -224,6 +224,21 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"launcher" : {
|
||||
"type" : "object",
|
||||
"default": {},
|
||||
"additionalProperties" : false,
|
||||
"required" : [ "repositoryURL" ],
|
||||
"properties" : {
|
||||
"repositoryURL" : {
|
||||
"type" : "array",
|
||||
"default" : [ ],
|
||||
"items" : {
|
||||
"type" : "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2184,7 +2184,7 @@ SpellID CBattleInfoCallback::getRandomBeneficialSpell(const CStack * subject) co
|
||||
break;
|
||||
case SpellID::SLAYER://only if monsters are present
|
||||
{
|
||||
auto kingMonster = getStackIf([&](const CStack *stack) //look for enemy, non-shooting stack
|
||||
auto kingMonster = getStackIf([&](const CStack *stack) -> bool //look for enemy, non-shooting stack
|
||||
{
|
||||
const auto isKing = Selector::type(Bonus::KING1)
|
||||
.Or(Selector::type(Bonus::KING2))
|
||||
|
@ -294,18 +294,11 @@ void CHeroHandler::loadHeroSkills(CHero * hero, const JsonNode & node)
|
||||
|
||||
for(const JsonNode & spell : node["spellbook"].Vector())
|
||||
{
|
||||
if (spell.getType() == JsonNode::DATA_FLOAT) // for compatibility
|
||||
VLC->modh->identifiers.requestIdentifier("spell", spell,
|
||||
[=](si32 spellID)
|
||||
{
|
||||
hero->spells.insert(SpellID(spell.Float()));
|
||||
}
|
||||
else
|
||||
{
|
||||
VLC->modh->identifiers.requestIdentifier("spell", spell,
|
||||
[=](si32 spellID)
|
||||
{
|
||||
hero->spells.insert(SpellID(spellID));
|
||||
});
|
||||
}
|
||||
hero->spells.insert(SpellID(spellID));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -156,10 +156,6 @@ bool CIdentifierStorage::resolveIdentifier(const ObjectCallback & request)
|
||||
{
|
||||
logGlobal->errorStream() << "\tID is available in mod " << it->second.scope;
|
||||
}
|
||||
|
||||
// temporary code to smooth 0.92->0.93 transition
|
||||
request.callback(entries.first->second.id);
|
||||
return true;
|
||||
}
|
||||
logGlobal->errorStream() << "Unknown identifier " << request.type << "." << request.name << " from mod " << request.localScope;
|
||||
return false;
|
||||
|
@ -339,7 +339,7 @@ void JsonWriter::writeEntry(JsonVector::const_iterator entry)
|
||||
|
||||
void JsonWriter::writeString(const std::string &string)
|
||||
{
|
||||
static const std::string escaped = "\"\\/\b\f\n\r\t";
|
||||
static const std::string escaped = "\"\\\b\f\n\r\t";
|
||||
|
||||
out <<'\"';
|
||||
size_t pos=0, start=0;
|
||||
@ -506,7 +506,6 @@ bool JsonParser::extractEscaping(std::string &str)
|
||||
{
|
||||
break; case '\"': str += '\"';
|
||||
break; case '\\': str += '\\';
|
||||
break; case '/': str += '/';
|
||||
break; case 'b': str += '\b';
|
||||
break; case 'f': str += '\f';
|
||||
break; case 'n': str += '\n';
|
||||
|
@ -302,7 +302,7 @@ DLL_LINKAGE void RemoveObject::applyGs( CGameState *gs )
|
||||
{
|
||||
|
||||
CGObjectInstance *obj = gs->getObjInstance(id);
|
||||
logGlobal->debugStream() << "removing object id=" << id << "; address=" << (int)obj << "; name=" << obj->getHoverText();
|
||||
logGlobal->debugStream() << "removing object id=" << id << "; address=" << (intptr_t)obj << "; name=" << obj->getHoverText();
|
||||
//unblock tiles
|
||||
if(obj->defInfo)
|
||||
{
|
||||
@ -595,7 +595,7 @@ DLL_LINKAGE void NewObject::applyGs( CGameState *gs )
|
||||
o->initObj();
|
||||
assert(o->defInfo);
|
||||
|
||||
logGlobal->debugStream() << "added object id=" << id << "; address=" << (int)o << "; name=" << o->getHoverText();
|
||||
logGlobal->debugStream() << "added object id=" << id << "; address=" << (intptr_t)o << "; name=" << o->getHoverText();
|
||||
}
|
||||
|
||||
DLL_LINKAGE void NewArtifact::applyGs( CGameState *gs )
|
||||
|
@ -14,6 +14,8 @@
|
||||
|
||||
struct z_stream_s;
|
||||
|
||||
/// Abstract class that provides buffer for one-directional input streams (e.g. compressed data)
|
||||
/// Used for zip archives support and in .lod deflate compression
|
||||
class CBufferedStream : public CInputStream
|
||||
{
|
||||
public:
|
||||
@ -86,7 +88,7 @@ private:
|
||||
|
||||
/**
|
||||
* A class which provides method definitions for reading a gzip-compressed file
|
||||
* This class implements lazy loading - data will be decompressed (and cached by this class) only by request
|
||||
* This class implements lazy loading - data will be decompressed (and cached) only by request
|
||||
*/
|
||||
class DLL_LINKAGE CCompressedStream : public CBufferedStream
|
||||
{
|
||||
@ -103,7 +105,7 @@ public:
|
||||
~CCompressedStream();
|
||||
|
||||
/**
|
||||
* Prepare stream for decompression of next block (e.g. nect part of h3c)
|
||||
* Prepare stream for decompression of next block (e.g. next part of h3c)
|
||||
* Applicable only for streams that contain multiple concatenated compressed data
|
||||
*
|
||||
* @return false if next block was not found, true othervice
|
||||
|
@ -2,6 +2,8 @@
|
||||
#include "../../Global.h"
|
||||
#include "CZipLoader.h"
|
||||
|
||||
#include "../ScopeGuard.h"
|
||||
|
||||
/*
|
||||
* CZipLoader.cpp, part of VCMI engine
|
||||
*
|
||||
@ -100,3 +102,101 @@ std::unordered_set<ResourceID> CZipLoader::getFilteredFiles(std::function<bool(c
|
||||
}
|
||||
return foundID;
|
||||
}
|
||||
|
||||
/// extracts currently selected file from zip into stream "where"
|
||||
static bool extractCurrent(unzFile file, std::ostream & where)
|
||||
{
|
||||
std::array<char, 8 * 1024> buffer;
|
||||
|
||||
unzOpenCurrentFile(file);
|
||||
|
||||
while (1)
|
||||
{
|
||||
int readSize = unzReadCurrentFile(file, buffer.data(), buffer.size());
|
||||
|
||||
if (readSize < 0) // error
|
||||
break;
|
||||
|
||||
if (readSize == 0) // end-of-file. Also performs CRC check
|
||||
return unzCloseCurrentFile(file) == UNZ_OK;
|
||||
|
||||
if (readSize > 0) // successfull read
|
||||
{
|
||||
where.write(buffer.data(), readSize);
|
||||
if (!where.good())
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// extraction failed. Close file and exit
|
||||
unzCloseCurrentFile(file);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<std::string> ZipArchive::listFiles(std::string filename)
|
||||
{
|
||||
std::vector<std::string> ret;
|
||||
|
||||
unzFile file = unzOpen(filename.c_str());
|
||||
|
||||
if (unzGoToFirstFile(file) == UNZ_OK)
|
||||
{
|
||||
do
|
||||
{
|
||||
unz_file_info info;
|
||||
std::vector<char> filename;
|
||||
|
||||
unzGetCurrentFileInfo (file, &info, nullptr, 0, nullptr, 0, nullptr, 0);
|
||||
|
||||
filename.resize(info.size_filename);
|
||||
// Get name of current file. Contrary to docs "info" parameter can't be null
|
||||
unzGetCurrentFileInfo (file, &info, filename.data(), filename.size(), nullptr, 0, nullptr, 0);
|
||||
|
||||
ret.push_back(std::string(filename.data(), filename.size()));
|
||||
}
|
||||
while (unzGoToNextFile(file) == UNZ_OK);
|
||||
}
|
||||
unzClose(file);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ZipArchive::extract(std::string from, std::string where)
|
||||
{
|
||||
// Note: may not be fast enough for large archives (should NOT happen with mods)
|
||||
// because locating each file by name may be slow. Unlikely slower than decompression though
|
||||
return extract(from, where, listFiles(from));
|
||||
}
|
||||
|
||||
bool ZipArchive::extract(std::string from, std::string where, std::vector<std::string> what)
|
||||
{
|
||||
unzFile archive = unzOpen(from.c_str());
|
||||
|
||||
auto onExit = vstd::makeScopeGuard([&]()
|
||||
{
|
||||
unzClose(archive);
|
||||
});
|
||||
|
||||
for (std::string & file : what)
|
||||
{
|
||||
if (unzLocateFile(archive, file.c_str(), 1) != UNZ_OK)
|
||||
return false;
|
||||
|
||||
std::string fullName = where + '/' + file;
|
||||
std::string fullPath = fullName.substr(0, fullName.find_last_of("/"));
|
||||
|
||||
boost::filesystem::create_directories(fullPath);
|
||||
// directory. No file to extract
|
||||
// TODO: better way to detect directory? Probably check return value of unzOpenCurrentFile?
|
||||
if (boost::algorithm::ends_with(file, "/"))
|
||||
continue;
|
||||
|
||||
std::ofstream destFile(fullName);
|
||||
if (!destFile.good())
|
||||
return false;
|
||||
|
||||
if (!extractCurrent(archive, destFile))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -55,3 +55,16 @@ public:
|
||||
std::string getMountPoint() const override;
|
||||
std::unordered_set<ResourceID> getFilteredFiles(std::function<bool(const ResourceID &)> filter) const override;
|
||||
};
|
||||
|
||||
|
||||
namespace ZipArchive
|
||||
{
|
||||
/// List all files present in archive
|
||||
std::vector<std::string> DLL_LINKAGE listFiles(std::string filename);
|
||||
|
||||
/// extracts all files from archive "from" into destination directory "where". Directory must exist
|
||||
bool DLL_LINKAGE extract(std::string from, std::string where);
|
||||
|
||||
///same as above, but extracts only files mentioned in "what" list
|
||||
bool DLL_LINKAGE extract(std::string from, std::string where, std::vector<std::string> what);
|
||||
}
|
@ -22,6 +22,7 @@
|
||||
#include "../lib/VCMI_Lib.h"
|
||||
#include "../lib/mapping/CMap.h"
|
||||
#include "../lib/VCMIDirs.h"
|
||||
#include "../lib/ScopeGuard.h"
|
||||
#include "../client/CSoundBase.h"
|
||||
#include "CGameHandler.h"
|
||||
#include "CVCMIServer.h"
|
||||
@ -3536,7 +3537,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
||||
|
||||
StartAction start_action(ba);
|
||||
sendAndApply(&start_action);
|
||||
auto makeScopeGuard([&]{ sendAndApply(&end_action); }); //if we started than we have to finish
|
||||
auto onExit = vstd::makeScopeGuard([&]{ sendAndApply(&end_action); }); //if we started than we have to finish
|
||||
|
||||
const CGHeroInstance * attackingHero = gs->curB->battleGetFightingHero(ba.side);
|
||||
CHeroHandler::SBallisticsLevelInfo sbi = VLC->heroh->ballistics[attackingHero->getSecSkillLevel(SecondarySkill::BALLISTICS)];
|
||||
|
Loading…
Reference in New Issue
Block a user