|
CodeReloading
IntroductionCode reloading stream-lines development. When code managed by the code reloading system is modified, the system detects the file changes and puts them in place. There is no need to restart the MUD in order to accomplish the same effect in a reliable way. DetailsThe code reloading system is based around custom code loading, and placement of what that code defines into custom namespaces which you can then import it from. A game can specify any number of base namespaces, and for each, it needs to associate a given script directory where the code to be made available within that namespace is found. You can read more about these script directories on another page. The external code reloading project can be referred to, if more insight than is provided here is desired. ScreencastThe following video illustrates a simple situation where the presence code reloading allows the developer to quickly make a desired change, and employ it in game. The scenario is that the output of the "commands" command displays an unsorted list, and the video covers the changing of this behaviour.
Unit TestingBecause scripts managed by the code reloading system cannot be executed outside of the system, the existing unit testing mechanism does not work. For the code to work, the game needs to be started up and running, and then it is in a place where it can be unit tested. The framework has extensive support for unit testing, including not automatically putting script changes in place if its unit tests fail. You can read more about this on the unit testing page. LimitationsNormal Python ModulesThis system overlays the standard Python module system. Modules in the standard library, or present in specified directories can still be imported in exactly the same way as before. But the code managed by the code reloading system is in this separate system. Note: As code provided from standard modules is handled by a completely separate mechanism than the code reloading system, it does not get the code reloading behaviour. Either the framework needs to be restarted, or the standard Python reload function needs to be utilised. Of course it is worth keeping in mind that if this function was really that useful, this custom code reloading system would not be required. Code Reloading LimitationsWhile the Python language allows a lot of dynamic behaviour, there are some things that cannot be modified or manipulated at runtime. Because of this, there are some cases in which changed code cannot be put into immediate effect. Executing CodeYou cannot change the code out from underneath an executing function. As long as the function call has not exited, it continues to use the code which was in place when it was first called. And given that this framework is based on Stackless Python and its microthreads, functions can execute for as long as the game runs. The primary case to watch out for is infinite loops. A common pattern is to have an infinite loop that blocks waiting for some data, before processing that data and blocking waiting for more. This following code shows a loop that is awakened when a connection is accepted, calling a secondary function to do the actual handling logic. This has already been structured to work around the described problem, but it still remains to a minimal degree. def AcceptTelnetConnections(self, listenSocket):
acceptNonLocal = int(sorrows.data.config.net.acceptnonlocal)
while self.IsRunning():
currentSocket, clientAddress = listenSocket.accept()
self.AcceptTelnetConnection(currentSocket, clientAddress, acceptNonLocal)By calling AcceptTelnetConnection to handle a just accepted connection, the latest code for the handling logic will be employed. But the shown AcceptTelnetConnections code will always be the version used for the loop within it. Let's say that we decide that we no longer want to both passing in the acceptNonLocal argument to AcceptTelnetConnection, we can make this change, but there is no way to update this running function to use it. |