Pycraft, a 3D open-source open-world video game made in Python!
This article, released roughly once a month will document what changes have been made to the project, what challenges we faced and how we overcame them and how and where you can install this project from.
For anyone wondering, this is to accompany the regular updates on my Twitter page (@pycraftdev on twitter: www.twitter.com/PycraftDev) which are now also shared to my Dev profile here: https://dev.to/pycraftdev. This article is written by Tom Jebbo, the lead developer and graphics designer and I hope you enjoy both using the project and reading this article!
- You can find the latest release of Pycraft (v0.9.4) here: https://github.com/PycraftDeveloper/Pycraft
- You can find the latest developer preview of Pycraft (v0.9.5–2) here: https://github.com/PycraftDeveloper/Pycraft/tree/Pycraft-v0.9.5-2
- You can also find the latest documentation for Pycraft here: https://python-pycraft.readthedocs.io/en/latest/
- Pycraft's New Installer
- - The Installer
- - The Updater
- - The Uninstaller
- - To Conclude
- News about Pycraft
- Final Words
- Links and Credits
The latest major update to Pycraft, v0.9.4 was focused around finding a better way to install Pycraft and all its dependencies, in part due to how large and complex the project was getting to setup and install. At the same time, we also decided to make a better way to modify your install, allowing for Pycraft to be updated or removed from your device at a later date.
We did this to make the project more user friendly although this does still have its drawbacks - the main one being that the installer only works for Pycraft when its uncompiled. This was because compiled versions of Pycraft are much easier to use, needing only to be downloaded and run as all the modules the project needs are already there. For this reason, you cannot access the installer (although it is still present, you cannot click the option) in compiled versions of Pycraft.
We use the same UI design throughout Pycraft for the simplicity and also because it saves on code, we now just tell the installer to create a new menu:
root = InstallerImportData.mod_TkinterUtils__.TkinterInstaller.CreateDisplay(InstallerImportData, root)
Here we are calling a function we made ourselves to close the Tkinter window then open a new one in its place, this clears all of the previously drawn graphics and then loads the banner image on the left too. Then this function returns the display object so we can use it for other things later on.
I know that this isn't ideal, there is absolutely a more efficient way to clear the elements on w tkinter window, but I am pleased with how the installer turned out considering my bad experiences with Tkinter, we didn't want to spend too long on the project as this could easily months more of work, but it functions exactly as intended and there will be future revisions. Development of the installer was not easy and many features got redesigned multiple times, usually because we weren't satisfied with the end goal or because it was slow or inefficient. The way we engineered each of the sections where we manipulated files was completely changes as I was unhappy with how many global variables that took, there are over half as many global variables in Pycraft's installer as there was originally and the installer is much more versatile as a result.
Before we attempt to manipulate (move, copy, add or delete) files on your PC we always ask for permission, this way you can control exactly what the installer is or isn't allowed to do on your system, we do the same with connecting to the internet as we want to be transparent with what the program is doing on your PC, this is because we want to be as transparent as possible about when the program is using functions on your PC.
Now we will go into more detail about each section of the install utility, identifying design choices, challenges and the mechanism behind it!
The installer was the first section we decided to work on, initially this was all that would be made, but we decided to make the other elements as we felt the user should be able to remove the project after they have installed it - making it more user friendly.
The installer opens to a welcome page, this is unique to this UI as the other sections come under a different menu. Here we initially see the design of the menu for the entire installer, unfortunately this does use the PIL module to load images so that will have to be installed manually, although a better solution is being looked for (where no access to a CLI is required).
We decided to design our UI around the installer for Python, with a banner image on the left and side, a title and sub-title and a description of what is happening at this stage. We keep the back and advance buttons in the same place throughout the installer, although not every button is present at every stage. On the start screen of any of the UIs you are given the option to close the installer, which can also be achieved by pressing 'X'. We have also engineered the process so that if you go back a stage your preferences for the previous window will be saved so you don't have to re-enter details. All of the buttons and most of the menu elements are linked to the system style, so as you can see with the image below - taken on Windows 11 - the Windows 11 design theme is shown.
Initially we had 4 individual menus for the installer, but later decided that to save on code, space and complexity to combine the first UI and second UI together so that you can now choose to install a BETA version of Pycraft right at the start of the process.
This raised our first problem, we now have to make sure that if the user chooses a specific version of the project, that choice is respected throughout the installer and is compatible with all versions of Pycraft, as a result no area of the installer is specific to a version, meaning that future versions can be added easily and without compatibility issues.
Continuing onto the next UI you are provided with more information about the installer, links to the project's GitHub page and a copy of the licence, we would strongly recommend reading this, it's not long but provides some useful information about what to do in the event of a bug, and ways you can report it. There are no limitations on what you can do with Pycraft. Selecting "I have read the above text" allows you to continue.
When we press continue, we are prompted to choose a location to install Pycraft, although this does not matter some early versions supported by the installer may not like being installed in some locations, additionally we cannot install to any folders the user cannot access without administrative permissions but this is not something we can work around, after you have chosen a suitable install location for Pycraft, pressing continue will initiate the install process.
Making the project backwards compatible was particularly challenging as Pycraft v0.9.3 and below where not designed with a new installer in mind (more on that later) so we had to be less specific on features than we would like, as a more complex installer would be less user friendly, larger in terms of code and portability and also much harder to identify bugs between versions of Pycraft.
When we start the install, we provide a detailed breakdown of exactly what each stage of the process is happening. All of the install, update and uninstall process start by trying to access the version of Pycraft you're modifying or in the case of the installer it will try to find the latest version of Pycraft on PyPi.
Then, with the help of the threading, subprocess and sys modules we run the same command the user would in a CLI to download Pycraft, this will download Pycraft to the default download location in "site-packages", we then move Pycraft to the location the user has specified. As this process can take some time, especially on low-speed internet connections or on slow storage we add an element to the screen that indicates the menu hasn't crashed.
The command we run is essentially this:
subprocess.check_call([sys.executable, "-m","pip","install","python-pycraft"], False)
But closer integrated into the structure of the project and with more options and precautions in place in the event things go wrong, This line of Python is not commonly found but allows you to download a package or run a command through Python, we are running the command:
-m pip install python-pycraft
At the location of the currently running Python version.
Once the update has finished, the UI will show something like this:
Clicking "continue" takes you to a final menu that allows you to close the installer, as well as to create shortcuts to the desktop or start menu, at least one of these would be recommended as it might be difficult to find Pycraft otherwise. We also provide a quick link to the GitHub profile again for if you want to read the latest release notes or more information about the project.
The installer was a very complex process to add, and during this process we started launching active testing of the project on Linux and although the process does not currently work on Linux, we have not allowed it to - to avoid damaging other files - this will be added in a future update. There are very much still issues with the entire installer, although the core functionality is working there are some limitations still, which we are working constantly to address.
The updater is by far the most unique part of the installer, it features the least amount of code, heavily relying on sections of the installer and uninstaller to function, this was also the least area to get worked on so was the quickest to do, although was actually not the easiest because up to that point the installer was not engineered to be accessed internally, for instance running the installer from the update GUI to reinstall packages, so the entire installer was later redesigned and features all the improvements and features learned.
This section uses most of the functionality of the rest of the installer, although does have a specific area where it checks for an out of date install of Pycraft by running a command to check for outdated packages (using the same technique as the installer above):
$python3.10 -m pip list –-outdated
The user would not be able to update Pycraft unless an update was available, and we only release the most stable - full releases of Pycraft to PyPi, if we didn't do this then this functionality would break and developer preview builds, which are not in a finished state would be installed instead. You can see the process for checking for an update to Pycraft in the menu below, this is compatible with all versions of Pycraft that also support the installer. We check for if Pycraft is outdated by using the command above, however we do not know what the latest version of Pycraft is because we cannot get access to that information in the CLI, the area that would have that feature:
$python 3.10 -m pip search python-pycraft
Is currently unavailable due to high demand;
"RuntimeError: PyPi's XMLRPC API is currently disabled due to unmanageable load and will be deprecated in the near future. See https://status.python.org/ for more information."
As a result, we are not specific at getting what the latest version is. We could have made this more complex, searching GitHub instead, but that adds additional complexity and points of failure - and is not strictly necessary.
Because this section links to the installer and uninstaller for the rest of the process we will not go into details about their functionality to avoid repeating ourselves, instead this section will focus on what we did to improve the project when we redesigned the installer.
Initially we used a whole host of global variables to determine exactly what was going on in each thread, but instead we changed this so that the project would wait for as long as the thread is running, instead of for as long as it takes for a global variable to be updated, this makes modifying the installer much easier as we have less global variables to handle and also we aren't guessing when the process is finished before moving onto the next stage, if however a mistake was to occur and the process moves on before an earlier thread is finished, the program will wait at the next step before continuing.
Additionally, we decided to improve our emphasis on modularity for this redesign, the original installer was much longer than the new one is, and was designed entirely in one file, much like early versions of Pycraft, we restructured both to allow for additional modularity and easier updates of code in future, but here that also helps out because it reduces the amount of code we had to repeat.
The final major point here is that we designed the new installer around the same core as Pycraft, this means we have a central file that acts as a point of initialisation, then we have a menu that provides options and each individual process. This decision was made in order to make working between the installer and Pycraft more fluent and to allow them both to work closely together. It also helps because we have integrated the installer right into Pycraft it's self so was crucial we followed through on the design.
The uninstaller then, this is where we had to be really careful, this was the most complex section to design, and the one that we took the most care on, mainly because this section has the ability to delete files, and we have various measures in the project to prevent things from going wrong and the wrong files being deleted.
We start on a menu that provides us with 3 options:
"Remove Pycraft and additional files but keep save data" - This is the preferred choice as it means you can reinstall Pycraft at a later date and all your configurations are still available (although for now you do have to manually replace the folder where saved data is kept; "Data Files" to the location of the new install) and it also is the method we use to update Pycraft, as we run this option first, to remove older files and then install the new ones in their place. This option will remove all of the files for Pycraft as well as all of the required modules it needs (and as Pycraft's modules may have required modules we don't specify which files to remove, only the folder where they are found in, otherwise that would be a lot of additional complexity and not make it flexible for changes in future) although this does leave saved data. We recommend this option for anyone planning to upgrade their version.
"Remove Pycraft but leave additional files" - This is intended for developers mainly, it keeps all of your downloaded modules for Python and only removes Pycraft, but does not keep saved data. We are looking into ways of changing this menu so that keeping additional files is a box you can tick instead of an option to add greater customisability.
"Remove everything" - This option is designed for people who just want to remove Pycraft entirely from their system, if you are having issues with the project this is the best way to fix it, clearing everything and re-installing the files. There is an additional 'repair' section that is currently being worked on, this will also help you fix problems with your install by attempting to diagnose and fix issues and the final resort there will be the same, reinstalling Pycraft from scratch if you allow it.
You can see the UI below; we chose to keep the design the same throughout the project:
Clicking on any one of these options, then pressing 'Continue' will bring you to a menu that shows you exactly what the installer is doing in a user-friendly way. We can use a progress-bar here to indicate how many files we have removed, as we know the amount we started with - something we cannot do with the installer - however this adds a lot of additional programming time and decided that for the code simplicity and reducing the number of global variables in this installer to remove that feature, instead we have the same indicator on the bottom left to show the installer hasn't crashed.
The uninstaller is designed to intentionally be limited in functionality, for instance we do not attempt to navigate to the start menu and remove any shortcuts there, in case the user selects that option on install, we did this intentionally as we didn't want to start deleting files in other areas of your PC as this can be dangerous and cause more areas for malfunction.
There was an installer back in the early versions of Pycraft, this isn't the first installer Pycraft has seen, this isn't even the second! But it is, by far the most reliable.
For the first design Pycraft and the installer where one and the same, the installer was integrated into Pycraft, which at the time was one file - approximately the same size and the modern Home Screen which is really impressive! - And this had significant issues, starting with the fact it was built into Pycraft meant you had to install all the additional modules first before the project would run, then once you had managed that it was entirely Pygame based so did not use the same theme as most installers making it confusing.
In revision two we switched to Tkinter from Pygame and the results where significantly better although the installer was slow and not portable initially this was intended to be the final design, but a confusing layout and not to mention how much both Pycraft has changed (Its no longer one (monolithic) file for one thing) meant a new design was needed and that is where we are today!
There is a significant change happening to Pycraft… The game engine is being completely redesigned from the ground up, we are completely changing how the controller and keyboard interact with the project, as well as adding significant in-game features to Pycraft, like shadow mapping, time (sun-sets and sunrises for example), weather (rain, storms, sun, clouds ext.), as well as adding new designs for the map, as well as new textures. This update is going to be huge and is the sole focus of Pycraft v0.9, we aim to have all that finished before we reach Pycraft v0.10, in line with the update schedule I have planned, and shared in previous articles.
Already we have added shadow mapping and the fundamentals of time, as well as the entire installer too and been making significant headway elsewhere too, the next medium article for May will document these changes better and go into much more detail on these changes. In the meantime, I've also been working to improve and add new features for developers, for example in the latest builds of Pycraft v0.9.5 you can press 'k' to skip 1 minute of the day forward. I've also added a counter that shows the amount of time spent in game (useful for keeping a track of time when implementing time into the game). You will soon be able to press 'Q' in all menus of Pycraft too as a developer and access a menu that lists all of the variables that are used throughout the project and their current values, making monitoring those a lot easier! There are a whole host of new changes and feature coming to Pycraft and there is a lot of work to be done, and bugs to fix!
Thank you for reading this article, I hope that you have liked this article and hopefully you have caught up will all things Pycraft. If you want to share this article that would be greatly appreciated!
Pycraft takes a lot of my time to develop, and a lot of work is but into Pycraft as a whole and writing these articles for you, as a result if you have any questions, suggestions or help; feel free to contact us at https://github.com/PycraftDeveloper/Pycraft, or by contacting the lead developer here: https://twitter.com/PycraftDev or by dropping a post on the discord server which you can find here: https://discord.gg/h4jpcjJh (server invite).
My Twitter Page: https://twitter.com/PycraftDev
My GitHub page: https://github.com/PycraftDeveloper
My Dev.to page: https://dev.to/pycraftdev
Pycraft can be found here: https://github.com/PycraftDeveloper/Pycraft
Pycraft can be also found here: https://pypi.org/project/Python-Pycraft/
Pycraft's documentation can be found here: https://python-pycraft.readthedocs.io/en/latest/
- Thomas Jebbo (PycraftDeveloper) @ www.github.com/PycraftDeveloper
- Count of Freshness Traversal @ https://twitter.com/DmitryChunikhinn
- Dogukan Demir (demirdogukan) @ https://github.com/demirdogukan
- Henri Post (HenryFBP) @ https://github.com/HenryFBP
- PyPi @ www.pypi.org
- PIL (Pillow or Python Imaging Library) @ www.github.com/python-pillow/Pillow
- Pygame @ www.github.com/pygame/pygame
- Numpy @ www.github.com/numpy/numpy
- PyOpenGL (and its counterpart PyOpenGL-accelerate) @ www.github.com/mcfletch/pyopengl
- PyAutoGUI @ www.github.com/asweigart/pyautogui
- Psutil @ www.github.com/giampaolo/psutil
- PyWaveFront @ www.github.com/pywavefront/PyWavefront
- Py-CPUinfo @ www.github.com/pytorch/cpuinfo
- GPUtil @ www.github.com/anderskm/gputil
- Tabulate @ www.github.com/p-ranav/tabulate
- Moderngl @ https://github.com/moderngl/moderngl
- Moderngl_window @ https://github.com/moderngl/moderngl-window
- PyJoystick @ https://github.com/justengel/pyjoystick
- FreeSound: - Erokia's "ambient wave compilation" @ www.freesound.org/s/473545
- FreeSound: - Soundholder's "ambient meadow near forest" @ www.freesound.org/s/425368
- FreeSound: - monte32's "Footsteps_6_Dirt_shoe" @ www.freesound.org/people/monte32/sounds/353799
Please note links under the "With thanks to" are not moderated by me, they are safe links at the time of writing however I do not control the content on them!