Minecraft
Minecraft copied to clipboard
failure if PYGLET_SHADOW_WINDOW=0 in effect
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
Um...have no idea how to fix it either. Maybe we should initialize the blocks after the window is created?
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.
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:
-
delayed_inits()
beforesuper(window,
shows the same error of this issue. -
delayed_inits()
behindsuper(window,
crashes a little bit later in the code, so THIS problem here is fixed.
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.
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
Good job! This also makes it possible to reload the texturepack without restarting the game. BTW, does this have any effect on performance?
I have no valid data and I did no deeply checks. But this is my impression:
- AFAICS reloading textures might need some more effort. What I did is not a clean design, it just is a hack to do delayed initialization. It was not designed to support re-initialization. Because of this there is, by purpose, the
once
function insideglobals.initializer
. Perhaps commenting outdel ref[0]
might do the trick such thatglobal.delayed_inits()
can be re-invoked to reload textures. If this works, you can rewriteglobals.initializer
as well to read:
1 def initializer(f):
2 __initializers__.append(f)
3 return f
- It is very likely that cython optimization became slightly worse, as many objects are no more accessed directly (before:
from block import *
andgrass_block
, nowimport block as B
andB.grass_block
, so they are "inside a dict"). This shortcomming probably can be optimized by changing some affected code later by introducing local variables to provide the needed values inside critical paths. - After cythonizing it, I cannot see any noticable speed decay. But even with Cython my machines have a too low FPS to notice any difference. (I am not a Gamer, so my Desktops have low graphics power.)
- In
nature.py
I had to change some things from "classes" to "instances" to be able to do delayed initialization (seenature._init()
, which introduces new names; Also I renamed old classes away by appending an_
to the class names, as an intermediate solution to catch old and thus wrong references, which are difficult to spot otherwise). Due to this all I am not really sure that everything here (biome generator) still works as designed. I am not deeply enough into this to check it is working correctly. If not, the classes have to get modified by introducing some_init
classmethods, which would be some other unique hack. - And still I am not really sure I found all the references which need to be fixed. So it is likely that still some errors pop out due to undefined variables in some functions (for example: furnace). Cython helped a lot to detect some missing references, but it also skipped some functions, perhaps because they are not optimized in
.pxd
yet so they stay pythonized. But I am not skilled enough in this area, so I cannot do much there.
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 ;)