boskee / Minecraft

Simple Minecraft-inspired program using Python and Pyglet
MIT License
207 stars 33 forks source link

failure if PYGLET_SHADOW_WINDOW=0 in effect #79

Open hilbix opened 11 years ago

hilbix commented 11 years ago

Windows:

set PYGLET_SHADOW_WINDOW=0
python main.py

Linux:

export PYGLET_SHADOW_WINDOW=0
./main.py

Both fails with an unmodified PyGLet on Windows and Linux, but AFAICS it shouldn't, because pyCraft uses some feature without initializing it in that case.

Longer story:

When trying to run pyCraft under Windows/7 64 Bit I get following error:

pyglet.gl.ContextException: Unable to share contexts

Apparently my embedded ATI Radeon HD 4200 has some GL issues, as usual. For this there is a workaround in PyGLet: Set the environment variable PYGLET_SHADOW_WINDOW=0

So this error vanishes by using

set PYGLET_SHADOW_WINDOW=0
python main.py

It then fails with

  File "C:\python27.addon\Minecraft\blocks.py", line 62, in __init__
..
  File "C:\Python27\lib\site-packages\pyglet\image\__init__.py", line 930, in blit_to_texture
    if gl.current_context._workaround_unpack_row_length:
AttributeError: 'NoneType' object has no attribute '_workaround_unpack_row_length'

Apparently PyGLet is not prepared for this case if gl.current_context has not been initialized by the app. Changing the line into

 if gl.current_context and gl.current_context._workaround_unpack_row_length:

allows for a graceful workaround.

Then you get following warning:

C:\Python27\lib\site-packages\pyglet\gl\gl_info.py:125: UserWarning: No GL context created yet.

But pyCraft now starts up, somehow.

However all textures and buttons are missing (see screenshots below), so the world looks weird. Apparently Minecraft needs the shadow window somehow for textures, but I really have no idea how to fix that.

Any idea?

Note that I think it is a Minecraft bug, because it forgets to initialize gl.current_context if PygLet does not initialize it itself (as told by the environment variable which, according to googled results, usually should not have bad sideeffects). So the bug seems to be right before init of blocks.py. However I am not sure as I do not understand GL.

FYI: As PIL cannot be installed without some crude registry hacks under 64 bit Windows' Python, I tried it with Pillow. Same result.

Pillow can be installed into Windows Python2.7 64 bit easily (after easy_install has been added to Python) with something like:

\Python27\Scripts\easy_install.exe Pillow

pycraft1

pycraft2

Jimx- commented 11 years ago

Um...have no idea how to fix it either. Maybe we should initialize the blocks after the window is created?

hilbix commented 11 years ago

That's a plan. I try to help, so I am working on this issue right now. However I am not very used to Python, my major languages are C, bash and awk.

AFAICS the delayed initialization of blocks needs some major change in the way the modules are initialized. Already changed 14(!) files and touched over 500 lines of code to move block init out of the way, but I am still in the "import" phase of modules, so still long before open of the window. I have no plan if this helps or if pyCraft will still run afterwards. We will see.

BTW: Have to change some classmethods in nature.py into normal methods, and get rid of "from xxx import *", everywhere (which is not a too bad thing), too. However this might have a negative impact on performance even under cython later on. Sigh.

hilbix commented 11 years ago

I now can confirm that the idea to move the blocks initialization behind Window() is the correct solution.

The heavily changed code allowing delayed init is at https://github.com/hilbix/Minecraft but it still is not complete yet, so pyCraft not really runs yet again. Only the start screen shows on make run (I test under Linux).

With make test (PYGLET_SHADOW_WINDOW=0) this are the intermediate results:

I have no idea yet what this other error means. Perhaps it is due to all those changes. Or it is a completely different thing. We will see.

hilbix commented 11 years ago

Well, success. See screenshot. Not heavily tested, though, and I am pretty sure there are a lot of misses and fuzz still left in the code. So I am not really sure you want to use my changes, as they really tweak things a lot.

Therefor I do not create a pull request here. You can fetch it yourself, see master branch at https://github.com/hilbix/Minecraft.git

Thanks. -Tino

pycraft3

Jimx- commented 11 years ago

Good job! This also makes it possible to reload the texturepack without restarting the game. BTW, does this have any effect on performance?

hilbix commented 11 years ago

I have no valid data and I did no deeply checks. But this is my impression:

1 def initializer(f):
2    __initializers__.append(f)
3    return f

In general I tried to do the changes with a minimal additional footprint, as well for program flow, code design and performance - even that I am not a performance expert on Python. So most changes should have minimal impact on things, I hope.

Ah, one thing to note on mods. I could not find any, but there might be some, somewhere:

The delayed initialization might break some mods which require, that blocks etc. are initialized before they are loaded. This is because G.delayed_inits() is called after the window is initialized, which happens after load_modules() is done. So if modules want to refer to blocks etc., they have to use the decorator @globals.initializer to declare a function which is fired after the graphics context is present.

This then will be called, too, after textures are reloaded - if this really works this way.

Some last note:

I had fun doing this changes, but that's it: Just for fun and because I was curious. But I think I will not find much more time to allocate into Minecraft/pyCraft to help in future, sorry. Tempus fugit ;)