You seem to be using the same pattern here a lot.

It would be better for this to live in terrain and be absorbed into world.  Something like:

    world.retry_on_exception(attempt_func, max_attempts=5)