If you do not already know how to program then if you do not already have a game specific set of scripts then this might be advanced material.
In any case, I really wanted something scriptable and something that can inspect anything in the game and change it. Ultimately I figured out how to compile IronPython for Mono that Unity uses and compiled something that loads into general Unity games and apps I've tried so far. I use a thirdparty plugin called IPA from Eusth (More details can be found here [Link]) to instrument the game and load plugins it was created for one game but works for any Unity game I've ever tried.
Prerequisites:
Runs on Windows x86 and x64 architectures. Only on standalone unity installs so no silverlight or web clients. And currently I have different builds for Unity 4 and 5 as that is what I have encountered most.
To install:
Download and unpack the console zip file from [Link] file into the game folder. The plugin requires IPA to be installed so I've created additional downloads that include a recent version but you can download separately from [Link].
Drag the game exe over ipa.exe to instrument it. Note that this changes the dlls in the Managed folder. This enables the console assemblies to be loaded by the game (and any other plugins you might have). There are other ways to do this that might be simpler and less invasive but this is really simple once you used it once or twice. It makes a backup of the changed dlls so you can revert the changes if you dont like it.
To use:
Press the Ctrl+` (backquote) keys at the same time. For international users you can change the console startup options from the Plugins\Console\Console.ini file if you dont have easy access to the backtick or prefer a different key. There is also an option to open on start or to start hidden and run a startup script which is useful if there is a GUI cheat window script for the game.
You can close the console using ^Z (Control-Z) + Enter or run quit(). I will note that once the console is closed after opening I cannot restart the console and have it work properly so that is disabled. Games will close if you close the console using the X button.
From here you can manipulate anything in the game if you know how to find it. Most games usually have some class that is the root of everything that you can use to get access to more interesting stuff though not always easily. You can use Reflector, dotPeek or dnSpy to search through the game assemblies to find useful stuff. For Unity, most of the good stuff is in Assembly-CSharp.dll.
Notes:
I should note that manipulating Unity objects directly from the Console can crash the game so I've introduced a library called coroutine to help run python functions properly in unity. If you put too much in a function then unity block and you never see anything so its best to only use the unity wrapper for short operations. You can look at the test.py library in the download for details.
Also you cannot create MonoBehaviour derived classes directly in Python so I had to create wrapper classes that call back to python classes.
You can use the behaviors to take things to the next level and custom user interfaces in Unity which will run arbitrary python code. This is finally where the real payoff is as you can bind keys or buttons to scripts that do useful work. I'll post some specific game examples elsewhere to show this.
You can see an example of using the Unity gui for Cosmic Star Heroine here.
Examples:
Code: Select all
>>> import UnityEngine
>>> print UnityEngine.Application.unityVersion
5.3.5f1
Code: Select all
"""
Create centered window that has a couple of buttons for testing
"""
def test():
import unity_util
import UnityEngine
from UnityEngine import GUI, GUILayout, Screen, Rect, Input, KeyCode
import System
# delete all of the old stuff
unity_util.clean_behaviors()
class DemoMessage():
def __init__(self):
self.color = UnityEngine.Color.white
self.counter = 1
self.options = System.Array.CreateInstance(UnityEngine.GUILayoutOption, 0)
self.show_buttons = False
self.gameObject = None # will be assigned if exists as member
self.component = None # will be assigned if exists as member
self.visible = True
#print "Called when object is created"
def Update(self):
# Update is called less so better place to check keystate than OnGUI
if Input.GetKeyDown(KeyCode.F8):
# unity sucks for checking meta keys
ctrl, alt, shift = unity_util.metakey_state()
if ctrl and not alt and not shift:
self.visible = not self.visible
def OnGUI(self):
if self.visible:
self.counter = self.counter + 1
origColor = GUI.color
try:
GUI.BeginGroup(Rect (Screen.width / 2 - 50, Screen.height / 2 - 50, 400, 400))
GUI.color = self.color
with GUILayout.VerticalScope("Group", GUI.skin.window):
GUILayout.Label(str(self.counter))
self.show_buttons = GUILayout.Toggle(self.show_buttons, "Buttons")
if self.show_buttons:
if GUILayout.Button("Click me"):
print "clicked"
if GUILayout.Button("Close"):
if self.gameObject:
UnityEngine.Object.DestroyObject(self.gameObject)
except:
GUI.color = origColor
GUI.EndGroup()
def __del__(self):
#print "Called when object is garbage collected"
pass
return unity_util.create_gui_behavior(DemoMessage)
[Link]