1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-26 08:41:13 +02:00

Merge pull request #2494 from IvanSavenko/hotfix_2

Hotfix 2
This commit is contained in:
Ivan Savenko 2023-08-06 18:47:32 +03:00 committed by GitHub
commit 1826e990d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 107 additions and 39 deletions

View File

@ -10,7 +10,7 @@ android {
applicationId "is.xyz.vcmi"
minSdk 19
targetSdk 31
versionCode 1302
versionCode 1303
versionName "1.3.0"
setProperty("archivesBaseName", "vcmi")
}

View File

@ -146,7 +146,7 @@ public class NativeMethods
public static void hapticFeedback()
{
final Context ctx = SDL.getContext();
if (Build.VERSION.SDK_INT >= 26) {
if (Build.VERSION.SDK_INT >= 29) {
((Vibrator) ctx.getSystemService(ctx.VIBRATOR_SERVICE)).vibrate(VibrationEffect.createPredefined(VibrationEffect.EFFECT_TICK));
} else {
((Vibrator) ctx.getSystemService(ctx.VIBRATOR_SERVICE)).vibrate(30);

View File

@ -133,6 +133,12 @@ public class ExportDataController extends LauncherSettingController<Void, Void>
}
}
if (exported == null)
{
publishProgress("Failed to copy file " + child.getName());
return false;
}
try(
final OutputStream targetStream = owner.getContentResolver()
.openOutputStream(exported.getUri());

View File

@ -81,7 +81,7 @@ public class FileUtil
{
if (file == null)
{
Log.e("Broken path given to fileutil");
Log.e("Broken path given to fileutil::ensureWriteable");
return false;
}
@ -99,6 +99,12 @@ public class FileUtil
public static boolean clearDirectory(final File dir)
{
if (dir == null)
{
Log.e("Broken path given to fileutil::clearDirectory");
return false;
}
for (final File f : dir.listFiles())
{
if (f.isDirectory() && !clearDirectory(f))

View File

@ -38,6 +38,7 @@
#include <vstd/StringUtils.h>
#include <SDL_main.h>
#include <SDL.h>
#ifdef VCMI_ANDROID
#include "../lib/CAndroidVMHelper.h"
@ -260,19 +261,12 @@ int main(int argc, char * argv[])
if (CResourceHandler::get()->existsResource(ResourceID(filename)))
return true;
logGlobal->error("Error: %s was not found!", message);
return false;
handleFatalError(message, false);
};
if (!testFile("DATA/HELP.TXT", "Heroes III data") ||
!testFile("MODS/VCMI/MOD.JSON", "VCMI data"))
{
exit(1); // These are unrecoverable errors
}
// these two are optional + some installs have them on CD and not in data directory
testFile("VIDEO/GOOD1A.SMK", "campaign movies");
testFile("SOUNDS/G1A.WAV", "campaign music"); //technically not a music but voiced intro sounds
testFile("DATA/HELP.TXT", "VCMI requires Heroes III: Shadow of Death or Heroes III: Complete data files to run!");
testFile("MODS/VCMI/MOD.JSON", "VCMI installation is corrupted! Built-in mod was not found!");
testFile("DATA/TENTCOLR.TXT", "Heroes III: Restoration of Erathia (including HD Edition) data files are not supported!");
srand ( (unsigned int)time(nullptr) );
@ -510,3 +504,18 @@ void handleQuit(bool ask)
quitApplication();
}
}
void handleFatalError(const std::string & message, bool terminate)
{
logGlobal->error("FATAL ERROR ENCOUTERED, VCMI WILL NOW TERMINATE");
logGlobal->error("Reason: %s", message);
std::string messageToShow = "Fatal error! " + message;
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal error!", messageToShow.c_str(), nullptr);
if (terminate)
throw std::runtime_error(message);
else
exit(1);
}

View File

@ -21,3 +21,7 @@ extern SDL_Surface *screen2; // and hlp surface (used to store not-active in
extern SDL_Surface *screenBuf; // points to screen (if only advmapint is present) or screen2 (else) - should be used when updating controls which are not regularly redrawed
void handleQuit(bool ask = true);
/// Notify user about encoutered fatal error and terminate the game
/// TODO: decide on better location for this method
[[noreturn]] void handleFatalError(const std::string & message, bool terminate);

View File

@ -572,7 +572,16 @@ void CServerHandler::sendRestartGame() const
void CServerHandler::sendStartGame(bool allowOnlyAI) const
{
verifyStateBeforeStart(allowOnlyAI ? true : settings["session"]["onlyai"].Bool());
try
{
verifyStateBeforeStart(allowOnlyAI ? true : settings["session"]["onlyai"].Bool());
}
catch (const std::exception & e)
{
showServerError( std::string("Unable to start map! Reason: ") + e.what());
return;
}
LobbyStartGame lsg;
if(client)
{
@ -696,7 +705,7 @@ void CServerHandler::startCampaignScenario(std::shared_ptr<CampaignState> cs)
});
}
void CServerHandler::showServerError(std::string txt)
void CServerHandler::showServerError(std::string txt) const
{
CInfoWindow::showInfoDialog(txt, {});
}

View File

@ -151,7 +151,7 @@ public:
void startGameplay(VCMI_LIB_WRAP_NAMESPACE(CGameState) * gameState = nullptr);
void endGameplay(bool closeConnection = true, bool restart = false);
void startCampaignScenario(std::shared_ptr<CampaignState> cs = {});
void showServerError(std::string txt);
void showServerError(std::string txt) const;
// TODO: LobbyState must be updated within game so we should always know how many player interfaces our client handle
int howManyPlayerInterfaces();

View File

@ -523,6 +523,14 @@ uint8_t MapRendererObjects::checksum(IMapRendererContext & context, const int3 &
for(const auto & objectID : context.getObjects(coordinates))
{
const auto * objectInstance = context.getObject(objectID);
assert(objectInstance);
if(!objectInstance)
{
logGlobal->error("Stray map object that isn't fading");
continue;
}
size_t groupIndex = context.objectGroupIndex(objectInstance->id);
Point offsetPixels = context.objectImageOffset(objectInstance->id, coordinates);

View File

@ -126,24 +126,11 @@ void Graphics::initializeBattleGraphics()
}
Graphics::Graphics()
{
#if 0
std::vector<Task> tasks; //preparing list of graphics to load
tasks += std::bind(&Graphics::loadFonts,this);
tasks += std::bind(&Graphics::loadPaletteAndColors,this);
tasks += std::bind(&Graphics::initializeBattleGraphics,this);
tasks += std::bind(&Graphics::loadErmuToPicture,this);
tasks += std::bind(&Graphics::initializeImageLists,this);
CThreadHelper th(&tasks,std::max((ui32)1,boost::thread::hardware_concurrency()));
th.run();
#else
loadFonts();
loadPaletteAndColors();
initializeBattleGraphics();
loadErmuToPicture();
initializeImageLists();
#endif
//(!) do not load any CAnimation here
}

View File

@ -26,6 +26,12 @@
void CBitmapFont::loadModFont(const std::string & modName, const ResourceID & resource)
{
if (!CResourceHandler::get(modName)->existsResource(resource))
{
logGlobal->error("Failed to load font %s from mod %s", resource.getName(), modName);
return;
}
auto data = CResourceHandler::get(modName)->load(resource)->readAll();
std::string modLanguage = CGI->modh->getModLanguage(modName);
std::string modEncoding = Languages::getLanguageOptions(modLanguage).encoding;

View File

@ -80,6 +80,17 @@ SDL_Surface * CSDL_Ext::newSurface(int w, int h)
SDL_Surface * CSDL_Ext::newSurface(int w, int h, SDL_Surface * mod) //creates new surface, with flags/format same as in surface given
{
SDL_Surface * ret = SDL_CreateRGBSurface(0,w,h,mod->format->BitsPerPixel,mod->format->Rmask,mod->format->Gmask,mod->format->Bmask,mod->format->Amask);
if(ret == nullptr)
{
const char * error = SDL_GetError();
std::string messagePattern = "Failed to create SDL Surface of size %d x %d, %d bpp. Reason: %s";
std::string message = boost::str(boost::format(messagePattern) % w % h % mod->format->BitsPerPixel % error);
handleFatalError(message, true);
}
if (mod->format->palette)
{
assert(ret->format->palette);

View File

@ -264,7 +264,15 @@ void ScreenHandler::initializeWindow()
mainWindow = createWindow();
if(mainWindow == nullptr)
throw std::runtime_error("Unable to create window\n");
{
const char * error = SDL_GetError();
Point dimensions = getPreferredWindowResolution();
std::string messagePattern = "Failed to create SDL Window of size %d x %d. Reason: %s";
std::string message = boost::str(boost::format(messagePattern) % dimensions.x % dimensions.y % error);
handleFatalError(message, true);
}
//create first available renderer if preferred not set. Use no flags, so HW accelerated will be preferred but SW renderer also will possible
mainRenderer = SDL_CreateRenderer(mainWindow, getPreferredRenderingDriver(), 0);

View File

@ -849,7 +849,13 @@ void CCastleBuildings::enterCastleGate()
void CCastleBuildings::enterDwelling(int level)
{
assert(level >= 0 && level < town->creatures.size());
if (level < 0 || level >= town->creatures.size() || town->creatures[level].second.empty())
{
assert(0);
logGlobal->error("Attempt to enter into invalid dwelling of level %d in town %s (%s)", level, town->getNameTranslated(), town->town->faction->getNameTranslated());
return;
}
auto recruitCb = [=](CreatureID id, int count)
{
LOCPLINT->cb->recruitCreatures(town, town->getUpperArmy(), id, count, level);

View File

@ -1183,11 +1183,19 @@ void CTownHandler::initializeRequirements()
{
if (node.Vector().size() > 1)
{
logMod->warn("Unexpected length of town buildings requirements: %d", node.Vector().size());
logMod->warn("Entry contains: ");
logMod->warn(node.toJson());
logMod->error("Unexpected length of town buildings requirements: %d", node.Vector().size());
logMod->error("Entry contains: ");
logMod->error(node.toJson());
}
return BuildingID(VLC->modh->identifiers.getIdentifier(requirement.town->getBuildingScope(), node.Vector()[0]).value());
auto index = VLC->modh->identifiers.getIdentifier(requirement.town->getBuildingScope(), node[0]);
if (!index.has_value())
{
logMod->error("Unknown building in town buildings: %s", node[0].String());
return BuildingID::NONE;
}
return BuildingID(index.value());
});
}
requirementsToLoad.clear();

View File

@ -71,7 +71,7 @@ std::string StartInfo::getCampaignName() const
void LobbyInfo::verifyStateBeforeStart(bool ignoreNoHuman) const
{
if(!mi || !mi->mapHeader)
throw std::domain_error("ExceptionMapMissing");
throw std::domain_error("There is no map to start!");
auto missingMods = CMapService::verifyMapHeaderMods(*mi->mapHeader);
CModHandler::Incompatibility::ModList modList;
@ -88,12 +88,12 @@ void LobbyInfo::verifyStateBeforeStart(bool ignoreNoHuman) const
break;
if(i == si->playerInfos.cend() && !ignoreNoHuman)
throw std::domain_error("ExceptionNoHuman");
throw std::domain_error("There is no human player on map");
if(si->mapGenOptions && si->mode == StartInfo::NEW_GAME)
{
if(!si->mapGenOptions->checkOptions())
throw std::domain_error("ExceptionNoTemplate");
throw std::domain_error("No random map template found!");
}
}