Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: opinions: how to handle resource errors?  (Read 9610 times)

0 Members and 1 Guest are viewing this topic.

Stauricus

  • Sr. Member
  • ****
  • Posts: 369
    • View Profile
    • A Mafia Graphic Novel
    • Email
opinions: how to handle resource errors?
« on: November 04, 2013, 06:48:29 pm »
hello,

i was thinking, how do people usually handle loading erros in SFML?
i mean, if you make a graphical application, without the console running on background, and it fails to load a font: how are you going to say to the user "hey, i had a problem loading fonts"?

because if there is no terminal, you can't output errors to it; and if there's no sf::Font, you can't show a sf::Text on the screen. so, what would you do?

thanks for the suggestions :)
Visit my game site (and hopefully help funding it? )
Website | IndieDB

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11034
    • View Profile
    • development blog
    • Email
Re: opinions: how to handle resource errors?
« Reply #1 on: November 04, 2013, 06:58:46 pm »
If the resources are not where they should be then throwing an exception with a descriptive message should be enough. The game fails to execute properly thus it crashes through an exception.

Of course it might scare away people and thus you could try to implement some fallbacks. For instance integrate a font into the binary, thus it should be impossible to fail, or use some OS specific functions to invoke a nice message box, etc.

Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Stauricus

  • Sr. Member
  • ****
  • Posts: 369
    • View Profile
    • A Mafia Graphic Novel
    • Email
Re: opinions: how to handle resource errors?
« Reply #2 on: November 04, 2013, 07:15:57 pm »
 but i don't understand is: where to am i going to show that the exception occured, if there's no terminal to output?
according my limited knowledge, even if i catch an exception, i'll have to output the error somewhere, right?

could you give me a direction on how to integrate a font in the binary? thanks!
Visit my game site (and hopefully help funding it? )
Website | IndieDB

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11034
    • View Profile
    • development blog
    • Email
Re: opinions: how to handle resource errors?
« Reply #3 on: November 04, 2013, 07:47:36 pm »
Well that's the point, you don't catch that one exception! ;D
If an exception is never caught it will propagate to the OS, which will then terminate the application and depending on the OS display the exception message.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Stauricus

  • Sr. Member
  • ****
  • Posts: 369
    • View Profile
    • A Mafia Graphic Novel
    • Email
Re: opinions: how to handle resource errors?
« Reply #4 on: November 04, 2013, 08:21:49 pm »
wow, just tested it, i had no idea on that!  :o
altough a more good-looking approach would be desirable, so after your suggestion, i did some search on how to insert font files in the binary.
i found this topic, which seems to be the what i want.
thanks for the help!
« Last Edit: November 04, 2013, 08:23:30 pm by Stauricus »
Visit my game site (and hopefully help funding it? )
Website | IndieDB

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: opinions: how to handle resource errors?
« Reply #5 on: November 04, 2013, 09:01:53 pm »
If an exception is never caught it will propagate to the OS, which will then terminate the application and depending on the OS display the exception message.
I don't recommend that. First, you have to rely on OS- and runtime-specific implementations to deliver a meaningful error message. Second, the string returned by what() is a technical description which is not necessarily useful for the end user. Third, uncaught exceptions usually lead to program crashes, giving the user the impression of a buggy application.

On Windows, you typically get a "App.exe has stopped working" message... That's the worst possible error handling one could imagine ;)

so after your suggestion, i did some search on how to insert font files in the binary.
That approach has some disadvantages (dependency on external tools, more maintenance, large binary file and RAM usage, more difficult to update executable, no mods, longer compile times). Usually it's simpler to expect the files to be there, and create an error message when loading fails. You will have to implement error handling anyway, there may also be other issues which you can't handle at compile time.

Your application most probably already uses menus. If your code is well-designed, it is a small effort to add a new menu state that displays an error message. Otherwise, it's also possible to write an entry to a log file.
« Last Edit: November 04, 2013, 09:05:49 pm by Nexus »
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11034
    • View Profile
    • development blog
    • Email
Re: opinions: how to handle resource errors?
« Reply #6 on: November 04, 2013, 09:11:57 pm »
Usually it's simpler to expect the files to be there, and create an error message when loading fails.
That's the question at hand: How do you display an error message when you don't have any resources to work with? Drawing rectangles and shapes and hoping it's an alien reading it? ;)

Sure letting an application crash with an exception is not so good, but what would you do in the worst case scenario? What if you'd assume as you said the resources are there, but they are not, what then?

Quote from: SFML Game Development Book
One possibility would be to provide a default texture (for example, plain white), so the sprites are just drawn as a white rectangle. However, we do not want the player of our game to fiddle around with rectangles; he should either have a proper airplane or nothing.
So should the game just keep running without having loaded anything, letting the player in the dark what the issue actually is? ;)
« Last Edit: November 04, 2013, 09:13:29 pm by eXpl0it3r »
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: opinions: how to handle resource errors?
« Reply #7 on: November 04, 2013, 09:35:58 pm »
Sure letting an application crash with an exception is not so good
Not handling exceptions is pretty much the worst you can do. Not only because the called std::terminate() doesn't guarantee stack unwinding (possibly not executing crucial code), but also because it leaves the user without any information about the error.

because outside of debugging , but what would you do in the worst case scenario? What if you assume as you said the resources are there, but they are not, what then?
Write an error to the console (if available) and possibly to a log file. Providing a fallback menu with textures and fonts is a nice additional feature. However, all error-reporting approaches may fail in very bad circumstances, your application may also crash if a loaded library is incompatible or corrupt. It's a question of how much effort you want to invest to protect against intentional or reckless abuse ;)
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Stauricus

  • Sr. Member
  • ****
  • Posts: 369
    • View Profile
    • A Mafia Graphic Novel
    • Email
Re: opinions: how to handle resource errors?
« Reply #8 on: November 04, 2013, 09:44:43 pm »
Usually it's simpler to expect the files to be there, and create an error message when loading fails.
sure, we always expect the resources to be there. but we know that there are millions of reasons for that to not happen. and there's one more thing that concerns me. from here, you can read that "The loadFromFile function sometimes fails with no obvious reason". i don't know if an "no obvious reason" includes undefined behaviour or if Laurent was just expecting newbies to make mistakes when he wrote that. in any case, i tought it would be better to have a little more caution when loading resources.

Write an error to the console (if available) and possibly to a log file.
well, we don't very often leave the console open in final applications, right? it seems to bother people who are not developers...


i think that loading from memory is a good option. a simple font with only ASCII characters can't be so resource heavy, i guess...
Visit my game site (and hopefully help funding it? )
Website | IndieDB

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: opinions: how to handle resource errors?
« Reply #9 on: November 04, 2013, 09:53:24 pm »
Yes, a font can be okay, but I wouldn't embed all resources in the executable. In fact, that's what SFML did some time ago: Providing a default font. There were also some good reasons to remove it.

well, we don't very often leave the console open in final applications, right?
On Linux, it's quite usual to even start applications from the console. But I agree, most games and desktop software don't do this, that's why I wrote "if available".
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Stauricus

  • Sr. Member
  • ****
  • Posts: 369
    • View Profile
    • A Mafia Graphic Novel
    • Email
Re: opinions: how to handle resource errors?
« Reply #10 on: November 04, 2013, 10:02:09 pm »
as a newcomer to Linux world for some months, i'm getting used to the terminal. but i understand that most people are scared of just seeing it. so that's why i wanted something else.

In fact, that's what SFML did some time ago: Providing a default font. There were also some good reasons to remove it.
yeah, and as i don't have a deep programming knowledge, i actually miss it :P

my real concern was about having a safe way to display error messages. so ok, i'll not put everything inside the executable.
Visit my game site (and hopefully help funding it? )
Website | IndieDB

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11034
    • View Profile
    • development blog
    • Email
Re: opinions: how to handle resource errors?
« Reply #11 on: November 04, 2013, 10:49:37 pm »
Write an error to the console (if available) and possibly to a log file. Providing a fallback menu with textures and fonts is a nice additional feature. However, all error-reporting approaches may fail in very bad circumstances, your application may also crash if a loaded library is incompatible or corrupt. It's a question of how much effort you want to invest to protect against intentional or reckless abuse ;)
Not sure why you didn't bother reading all the details of the discussion...
If the resources are missing (that is no fonts and no images to write "messages") and if there's no console to write errors, what should one do?

I quickly ran a few games without resources:
  • Zloxx will just close itself without giving any indication as to why.
  • Airport crashes with a nice "has stopped working" message.
  • Firefall pops up a message box saying it couldn't find the shaders and then opens the crash reporting tool.
  • Crysis (via Steam) crashes with a cryptic error regarding Steam.
  • Open Hexagon starts load stuff and then crashes with "has stopped working".
  • Sim City 3000 opens a message box saying "Unknown Exception".

Thus I come back to either let your application crash, that way to user knows something bad is going on OR as I've said in my first post, use some OS functions to display an error (i.e. message box) and if you don't want that embed some resources in the binary so one has a certain way to display the error without relying on OS functions.

Yes it's an extreme case and one that's probably not worth spending hours on, but when there are certain conditions given, it would be good to try to give an answer that fits within the conditions... ::)
« Last Edit: November 04, 2013, 10:54:56 pm by eXpl0it3r »
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: opinions: how to handle resource errors?
« Reply #12 on: November 05, 2013, 07:27:56 am »
Not sure why you didn't bother reading all the details of the discussion...
If the resources are missing (that is no fonts and no images to write "messages") and if there's no console to write errors, what should one do?
I don't know why "Write an error to the console (if available) and possibly to a log file. Providing a fallback menu with textures and fonts is a nice additional feature." doesn't answer your question. It definitely includes the case where resources cannot be loaded and no console is available. To clarify, by fallback I meant an approach that doesn't fail under these circumstances, e.g. embedded resources. Sorry if it was unclear.

Zloxx writes into a log file, by the way.
« Last Edit: November 05, 2013, 07:44:00 am by Nexus »
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Stauricus

  • Sr. Member
  • ****
  • Posts: 369
    • View Profile
    • A Mafia Graphic Novel
    • Email
Re: opinions: how to handle resource errors?
« Reply #13 on: November 10, 2013, 12:26:17 am »
hi, i just wanted to say that i was able to embed the font in the binary. after a hard time searching how to convert it, i found a little program called xxd, which did the job. actually it is pretty simple after you understand the logic behind it.

so, here it is: the error messaging. end users will no more be completely lost when something goes wrong :P


(the long text is just for testing the "auto-break" feature)

the header that contaisn the font file is only 400kb, so it's not a real concern.
thanks everybody for the help.
Visit my game site (and hopefully help funding it? )
Website | IndieDB

TheRabbit

  • Newbie
  • *
  • Posts: 26
    • View Profile
Re: opinions: how to handle resource errors?
« Reply #14 on: November 10, 2013, 09:39:34 am »
I use a (admittedly Windows specific) error box if font loading fails:
MessageBox(HWND_DESKTOP,"Failed loading arial.ttf","Fatal Error",MB_OK);
But once I have a font loaded I created a little (ugly) method of popping up a error message in the middle of the screen:
//pushes message 'stringIn' to the top of the rendering window
//automatically word wraps and centers text
void Game::centerScreenMessage(const std::string &stringIn)
{
        sf::RectangleShape rect;
        rect.setSize(sf::Vector2f(500.f,200.f));//setup a rectangle thats 500 pixels wide and 200 tall
        rect.setFillColor(sf::Color(0,0,51)); //fill it with dark blue
        rect.setPosition(float(int(mWindow.getSize().x/2.f - rect.getSize().x/2.f)),float(int(mWindow.getSize().y/2.f - rect.getSize().y/2.f))); //center the rectangle
       
        sf::Text myText; //setup a text object to hold all the drawing information
        myText.setFont(loginFont); //load the font
        myText.setCharacterSize(24); //set size
        myText.setColor(sf::Color(204,204,204)); //text color = light grey
        myText.setString(stringIn); //set the string

        sf::IntRect cSize = loginFont.getGlyph('a',myText.getCharacterSize(),false).bounds; //used to determine font height, character 'a' doesn't matter
       
        std::deque<int> textSize; //container to hold widths of individual lines
       
        textSize = wrapText(myText,rect); //fill container and linebreak myText

        std::deque<sf::Text> texts; //make a container to hold all the new lines of text
        int j=0;
        mWindow.draw(rect); //draw the text box
        for (unsigned int i = 0; i < textSize.size(); i++)
        {
                texts.push_back(sf::Text(myText)); //put a new element on
                //set position so that the text is center justified:
                texts.back().setPosition(float(int(mWindow.getSize().x/2 - textSize[i]/2)),float(int(mWindow.getSize().y/2 - (cSize.height*textSize.size()) / 2 + (i * cSize.height))));
                j = myText.getString().toAnsiString().find('\n',j); //find the line break
                if (j < 0)
                        texts.back().setString(myText.getString().toAnsiString()); //this is probably redundant
                else
                {
                        texts.back().setString(myText.getString().toAnsiString().substr(0,j)); //break the text string up and then continue processing
                        myText.setString(myText.getString().toAnsiString().substr(j+1));
                }
                mWindow.draw(texts.back()); //draw the text on top of the textbox
        }
        mWindow.display();
}

//wraps text 'textIn' by inserting line breaks based on the width of 'boundingBox' and the font and size of 'textIn'
//returns a deque containing the line width of every line that was segmented
std::deque<int> wrapText(sf::Text &textIn, const sf::RectangleShape &boundingBox)
{
        int lineSize = 0; //counter used to see how long our current line is
        int lastSpace = -1; //counter to keep track of the location of the last space we found
        int maxWidth = 0;
        std::deque<int> output;
        sf::String outputString = "";
        sf::String lastLine;
        sf::Font fontIn = *textIn.getFont();
        lastLine = textIn.getString();

        for (unsigned int i = 0; i < lastLine.getSize(); i++)
        {
                sf::Glyph glyph = fontIn.getGlyph(lastLine[i], textIn.getCharacterSize(),false); //get the current character
                if ((lineSize + glyph.advance) > boundingBox.getSize().x) //check for runoff
                {
                        if (lastSpace != -1)
                        {
                                output.push_back(maxWidth- fontIn.getGlyph(' ',textIn.getCharacterSize(),false).advance); //put a new element in, but remove the size of the last space
                                outputString = outputString + lastLine.toAnsiString().substr(0,lastSpace) + '\n'; //put the current length of string onto the first line
                                lastLine = lastLine.toAnsiString().substr(lastSpace+1); //put the remainder back into lastLine to continue processing
                        }
                        else //processing one really long string with no spaces...
                        {
                                output.push_back(lineSize); //put the size of the current string of characters
                                outputString = outputString + lastLine.toAnsiString().substr(0,i) + '\n'; //put the current length of string onto the first line
                                lastLine = lastLine.toAnsiString().substr(i); //put the remainder back into lastLine to continue processing
                        }                      
                        i=-1; //reset our counters -- time to find out if you like overflow
                        lastSpace = -1;
                        maxWidth = 0;
                        lineSize = 0;
                }
                else
                {
                        lineSize += glyph.advance; //increment linesize by the texture size of the current character
                       
                        if (lastLine[i] == '\n') //if we come accross a natural line break
                        {
                                maxWidth = lineSize - glyph.advance; //ignore the size of the linebreak
                                output.push_back(maxWidth);
                                maxWidth = 0;//reset counters
                                lineSize = 0;
                                lastSpace = -1;
                        }
                        if (lastLine[i] == ' ') //track where the space is
                        {
                                lastSpace = i;
                                maxWidth = lineSize; //set string width to cutoff point
                        }
                }
        }
        output.push_back(lineSize);
        outputString = outputString + lastLine; //put the remainder of the string back in
        textIn.setString(outputString);
        return output;
}

I think I've done too much coding today, I just tried to preview this post by hitting F7 (build)...