DefCon - The Defold developer console

I initially created and released DefCon as an internal tool here at King, but it never really caught on, so I’m releasing it on my GitHub account in the hope that someone here on the forum will find it useful. DefCon is a customisable developer console for Defold. The console allows you to interact with a running game (locally or on device) through a browser.

The console allows you to perform a number of different operations on a running Defold instance:

  • Toggle the profiler
  • Toggle physics debug
  • Start/Stop video recording
  • Inspect any Lua table
  • Run arbitrary Lua code
  • Download files

You can also create custom commands to perform game specific operations such as setting the game in a specific state, unlocking new content or enabling a cheat menu.

Learn more and download it here: https://github.com/britzl/defcon

25 Likes

I saw it this weekend while browsing your repositories (lots of little gens in there).

It’s brilliant! Will definitely use it!

Thanks

5 Likes

Awesome lib.Use it in my project, everything work. It will be cool, if defCon can show log. For example in different window.Replace print function, or add additional function to send log. :slight_smile:

Yup, totally doable. I’ll make a note of it.

2 Likes

Is ` detectable in current Defold version? It is preferable show/hide key for console.

How do you mean? Showing and hiding of the web console?

I mean in many popular games you can press ` to open up a console overlay or window. Most people are probably used to that when working with consoles. I think your way of doing the tool is more useful for dev productivity, but may not be good for end users.

1 Like

The main purpose is as a tool for developers. A console overlay or window is a different thing. You probably want to have something that relies more on buttons and lists instead of keyboard input.

1 Like

I’ve released a new version of DefCon with support for routing print() calls to the console. The new command is:

log start|stop

I had to make a couple of larger breaking changes to support streamed command content. If someone has already started using it and created custom commands the command arguments are now sent as a Lua table instead of directly expanded to the command function.

3 Likes

On a sidenote, if there ever is a Defold convention somewhere it needs to be called DefCon.

8 Likes

Thank you very much! This is a very useful tool!

3 Likes

It becomes extra powerful when you add game specific commands. For instance cheat menus or functionality to facilitate testing.

3 Likes

As I understand DefCon incompatible with webview ?
When I try to use DefCon in project with webview - apk crashed. It was in moment when I try to open webview.
But if I remove console.go from the main collection all works fine.

1 Like

This sounds really really strange. What kind of error do you get in logcat?

04-03 09:58:15.021   509   863 E VT      : [SRV] [VT THREAD] [VT_Bind] Fail to connect . retry count: 1739308
04-03 09:58:15.035  1127  1192 W WindowAnimator: Failed to dispatch window animation state change.
04-03 09:58:15.035  1127  1192 W WindowAnimator: android.os.DeadObjectException
04-03 09:58:15.035  1127  1192 W WindowAnimator: 	at android.os.BinderProxy.transactNative(Native Method)
04-03 09:58:15.035  1127  1192 W WindowAnimator: 	at android.os.BinderProxy.transact(Binder.java:511)
04-03 09:58:15.035  1127  1192 W WindowAnimator: 	at android.view.IWindow$Stub$Proxy.onAnimationStopped(IWindow.java:548)
04-03 09:58:15.035  1127  1192 W WindowAnimator: 	at com.android.server.wm.WindowAnimator.updateWindowsLocked(WindowAnimator.java:295)
04-03 09:58:15.035  1127  1192 W WindowAnimator: 	at com.android.server.wm.WindowAnimator.animateLocked(WindowAnimator.java:687)
04-03 09:58:15.035  1127  1192 W WindowAnimator: 	at com.android.server.wm.WindowAnimator.access$000(WindowAnimator.java:56)
04-03 09:58:15.035  1127  1192 W WindowAnimator: 	at com.android.server.wm.WindowAnimator$1.doFrame(WindowAnimator.java:128)
04-03 09:58:15.035  1127  1192 W WindowAnimator: 	at android.view.Choreographer$CallbackRecord.run(Choreographer.java:894)
04-03 09:58:15.035  1127  1192 W WindowAnimator: 	at android.view.Choreographer.doCallbacks(Choreographer.java:698)
04-03 09:58:15.035  1127  1192 W WindowAnimator: 	at android.view.Choreographer.doFrame(Choreographer.java:630)
04-03 09:58:15.035  1127  1192 W WindowAnimator: 	at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:882)
04-03 09:58:15.035  1127  1192 W WindowAnimator: 	at android.os.Handler.handleCallback(Handler.java:815)
04-03 09:58:15.035  1127  1192 W WindowAnimator: 	at android.os.Handler.dispatchMessage(Handler.java:104)
04-03 09:58:15.035  1127  1192 W WindowAnimator: 	at android.os.Looper.loop(Looper.java:207)
04-03 09:58:15.035  1127  1192 W WindowAnimator: 	at android.os.HandlerThread.run(HandlerThread.java:61)
04-03 09:58:15.035  1127  1192 W WindowAnimator: 	at com.android.server.ServiceThread.run(ServiceThread.java:46)
04-03 09:58:15.038   350   391 I SurfaceFlinger: [SF client] DEL(0x7f94970880) for (1127:system_server)
04-03 09:58:15.038   350   391 D SurfaceFlinger:     remove: com.defold.dmengine/com.dynamo.android.DefoldActivity
04-03 09:58:15.051   350   350 I BufferQueueConsumer: [com.defold.dmengine/com.dynamo.android.DefoldActivity](this:0x7fa1e0d400,id:28781,api:1,p:-1,c:-1) disconnect(C)
04-03 09:58:15.051   350   350 I BufferQueue: [com.defold.dmengine/com.dynamo.android.DefoldActivity](this:0x7fa1e0d400,id:28781,api:1,p:-1,c:-1) ~BufferQueueCore
04-03 09:58:15.052   350   350 D GraphicBuffer: free, handle(0x7fa6c9e720) (w:1080 h:1920 s:1088 f:0x2 u:0x000b00)
04-03 09:58:15.052  1127  1192 I Timeline: Timeline: Activity_windows_visible id: ActivityRecord{5422a71 u0 com.miui.home/.launcher.Launcher t4281} time:877477091
04-03 09:58:15.052   350   350 I [MALI][Gralloc]: [-]hnd(0x7fa6c9e720), client(28), share_fd(68)
04-03 09:58:15.052  1127  1192 I Timeline: Timeline: App_transition_stopped time:877477092
04-03 09:58:15.052  1127  1192 V WindowManager: Looking for focus: 8 = Window{92244c0 u0 StatusBar}, flags=-2122317752, canReceive=false
04-03 09:58:15.052  1127  1192 V WindowManager: findFocusedWindow: Found new focus @ 5 = Window{cc24100 u0 В приложении "dmengine" произошла ошибка.}
04-03 09:58:15.101  1127  1195 D AutomaticBrightnessController: updateAmbientLux: mAmbientLuxValid=trueAAL=true
04-03 09:58:15.101  1127  1195 D AutomaticBrightnessController: calculateAmbientLux: [-10000, 100]: lux=0.0, weight=5.1005E7
04-03 09:58:15.101  1127  1195 D AutomaticBrightnessController: calculateAmbientLux: totalWeight=5.1005E7, newAmbientLux=0.0
04-03 09:58:15.101  1127  1195 D AutomaticBrightnessController: updateAmbientLux: ambientLux=0.0, timeToBrighten=4000, timeToDarken=8000, current=0.0
04-03 09:58:15.101  1127  1195 D AutomaticBrightnessController: updateAmbientLux: Scheduling ambient lux update for 877481141877481141 (in 4000 ms)
04-03 09:58:15.184  2064  2289 D OpenGLRenderer: CacheTexture 7 upload: x, y, width height = 60, 499, 17, 25
04-03 09:58:15.187   350   389 I BufferQueueProducer: [StatusBar](this:0x7fa1df4000,id:7,api:1,p:2064,c:350) queueBuffer: fps=0.07 dur=15091.32 max=15091.32 min=15091.32
04-03 09:58:15.293  1127  1127 E WifiTrafficPoller: TRAFFIC_STATS_POLL true Token 8893 num clients 14
04-03 09:58:15.293  1127  1127 E WifiTrafficPoller:  packet count Tx=11129248 Rx=15380446
04-03 09:58:15.293  1127  1127 E WifiTrafficPoller: notifying of data activity 3
04-03 09:58:15.304  1127  1932 D PerfServiceManager: [PerfService] MESSAGE_TIMEOUT:101
04-03 09:58:15.304  1127  1932 I libPerfService: [perfScnDisable] scenario:1
04-03 09:58:15.392  1127 10630 I System.out: <doReceiveResponse
04-03 09:58:15.392  1127 10630 W ErrorReport: Fail to sendHttpRequest
04-03 09:58:15.392  1127 10630 W ErrorReport: java.lang.IllegalArgumentException: HTTP entity may not be null
04-03 09:58:15.392  1127 10630 W ErrorReport: 	at org.apache.http.util.EntityUtils.toString(EntityUtils.java:115)
04-03 09:58:15.392  1127 10630 W ErrorReport: 	at org.apache.http.util.EntityUtils.toString(EntityUtils.java:151)
04-03 09:58:15.392  1127 10630 W ErrorReport: 	at miui.util.ErrorReport.c(SourceFile:396)
04-03 09:58:15.392  1127 10630 W ErrorReport: 	at miui.util.ErrorReport.sendReportRequest(SourceFile:353)
04-03 09:58:15.392  1127 10630 W ErrorReport: 	at miui.util.ErrorReport$1.a(SourceFile:369)
04-03 09:58:15.392  1127 10630 W ErrorReport: 	at miui.util.ErrorReport$1.doInBackground(SourceFile:366)
04-03 09:58:15.392  1127 10630 W ErrorReport: 	at android.os.AsyncTask$2.call(AsyncTask.java:295)
04-03 09:58:15.392  1127 10630 W ErrorReport: 	at java.util.concurrent.FutureTask.run(FutureTask.java:237)
04-03 09:58:15.392  1127 10630 W ErrorReport: 	at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
04-03 09:58:15.392  1127 10630 W ErrorReport: 	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
04-03 09:58:15.392  1127 10630 W ErrorReport: 	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
04-03 09:58:15.392  1127 10630 W ErrorReport: 	at java.lang.Thread.run(Thread.java:818)
04-03 09:58:15.393  1127 10630 W ContextImpl: Calling a method in the system process without a qualified user: android.app.ContextImpl.bindService:1300 android.content.ContextWrapper.bindService:614 miui.os.DropBoxManager.cq:361 miui.os.DropBoxManager.a:350 miui.os.DropBoxManager.addText:314
04-03 09:58:15.398  1959  1970 W MessageQueue: Handler (com.miui.internal.server.DropBoxManagerService$2) {e965c51} sending message to a Handler on a dead thread
04-03 09:58:15.398  1959  1970 W MessageQueue: java.lang.IllegalStateException: Handler (com.miui.internal.server.DropBoxManagerService$2) {e965c51} sending message to a Handler on a dead thread
04-03 09:58:15.398  1959  1970 W MessageQueue: 	at android.os.MessageQueue.enqueueMessage(MessageQueue.java:555)
04-03 09:58:15.398  1959  1970 W MessageQueue: 	at android.os.Handler.enqueueMessage(Handler.java:707)
04-03 09:58:15.398  1959  1970 W MessageQueue: 	at android.os.Handler.sendMessageAtTime(Handler.java:609)
04-03 09:58:15.398  1959  1970 W MessageQueue: 	at android.os.Handler.sendMessageDelayed(Handler.java:579)
04-03 09:58:15.398  1959  1970 W MessageQueue: 	at android.os.Handler.sendMessage(Handler.java:516)
04-03 09:58:15.398  1959  1970 W MessageQueue: 	at com.miui.internal.server.DropBoxManagerService.add(SourceFile:226)
04-03 09:58:15.398  1959  1970 W MessageQueue: 	at com.miui.internal.server.IDropBoxManagerService$Stub.onTransact(SourceFile:62)
04-03 09:58:15.398  1959  1970 W MessageQueue: 	at android.os.Binder.execTransact(Binder.java:458)
04-03 09:58:15.521   509   863 E VT      : [SRV] [VT THREAD] [VT_Bind] Fail to connect . retry count: 1739309
04-03 09:58:15.599   350  3581 I BufferQueueProducer: [В приложении "dmengine" произошла ошибка.](this:0x7f96dfa400,id:28782,api:1,p:1127,c:350) new GraphicBuffer needed
04-03 09:58:15.599   350  3581 D GraphicBuffer: free, handle(0x7fa678b080) (w:1080 h:842 s:1088 f:0x1 u:0x000900)
04-03 09:58:15.599   350  3581 I [MALI][Gralloc]: [-]hnd(0x7fa678b080), client(28), share_fd(76)
04-03 09:58:15.600   350  3581 I [MALI][Gralloc]: [+]hnd(0x7fa678b080), client(28), share_fd(29), hnd->flags:4
04-03 09:58:15.600   350  3581 D GraphicBuffer: alloc, handle(0x7fa678b080) (w:1080 h:842 s:1088 f:0x1 u:0x000b00) err(0)
04-03 09:58:15.601  1127  1419 I [MALI][Gralloc]: [+]r_hnd(0x7f58b97940), client(125), share_fd(336)
04-03 09:58:15.601  1127  1419 D GraphicBuffer: register, handle(0x7f58b97940) (w:1080 h:842 s:1088 f:0x1 u:0x000b00)
04-03 09:58:15.609   350   350 D MALI    : eglCreateImageKHR:511: [Crop] 0 0 0 0  img[1080 842]
04-03 09:58:15.929   506   559 D AALService: enableAALEvent: 1 -> 0
04-03 09:58:16.022   509   863 E VT      : [SRV] [VT THREAD] [VT_Bind] Fail to connect . retry count: 1739310
04-03 09:58:16.295  1127  1127 E WifiTrafficPoller: TRAFFIC_STATS_POLL true Token 8893 num clients 14
04-03 09:58:16.296  1127  1127 E WifiTrafficPoller:  packet count Tx=11129266 Rx=15380447
04-03 09:58:16.522   509   863 E VT      : [SRV] [VT THREAD] [VT_Bind] Fail to connect . retry count: 1739311
04-03 09:58:16.538  1127  1402 D InputReader: AP_PROF:AppLaunch_dispatchPtr:Down:877478578, ID:0, Index:1584512960
04-03 09:58:16.539  1127  1127 D SettingsInterface:  from settings cache , name = three_gesture_screenshot , value = null
04-03 09:58:16.539  1127  1127 D SettingsInterface:  from settings cache , name = is_show_three_gesture_alert , value = null
04-03 09:58:16.539  1127  1401 I PerfService: PerfServiceNative_boostEnableTimeoutMsAsync:3, 100
04-03 09:58:16.539  1127  1932 I libPerfService: [perfScnEnable] scenario:3
04-03 09:58:16.540  1127  1401 D PowerManagerService: userActivityFromNative
04-03 09:58:16.540  1127  1401 D lights  : write_int open fd=314
04-03 09:58:16.540  1127  1401 D LightsService: setLight_native: light=2, colorARGB=0XFFFFFFFF, flashMode=0, onMS=0, offMS=0, brightnessMode=0
04-03 09:58:16.540  1127  1401 D PowerManagerService: userActivityNoUpdateLocked: eventTime=877478578, event=2, flags=0x0, uid=1000
04-03 09:58:16.540  1127  1401 D PowerManagerNotifier: onUserActivity: event=2, uid=1000
04-03 09:58:16.540  1127  1932 I libPerfService: 3: set: -1, 4, 2,
04-03 09:58:16.540  1127  1401 D PowerManagerService: updateUserActivitySummaryLocked: mWakefulness=Awake, mUserActivitySummary=0x1, nextTimeout=877489079 (in 10499 ms)

Is it crashing when you call webview.open() or immediately on app start?

In this case I make webview.open when app starts in init() method.
But earler I tried to open webview by input event and recieved the same crash.
I think will be right to say that it crash when I made webview.open

And you’re saying that it doesn’t crash if you remove the console?

Yes, I just remove console.go from the main collection and all works fine.
I can share you the project.

Yes, please share it (bjorn.ritzl@king.com)