Random image of Textel, my bat fursona

COBERTOS

Exporting my Nintendo Switch app activity

data exportexportNintendo Switchrooting

I was decommissioning my Nintendo Switch (I just bought a Steam Deck :3) and realized it would be nice to get some of the activity data off of it. I had easy access to the screenshots and other stuff Nintendo lets you touch, but it would be nice to have a record of all my play time. It turns out the switch DOES store all this information indefinitely (specifically, it stores app launch and close events), but with no way to get at it or export it. Libnx (a switch homebrew library) exposes a function called pdmqryQueryPlayEvent which allows applications like NX-Activity-Log to get at it.

I ended up using NX-Activity-Log to export everything to JSON. I got all my app interaction events which included a lot of stuff from 2017-2019. Yay!

How I did it

  • I followed switch.homebrew.guide to run homebrew apps on my switch. This required a paperclip and a 4GB+ micro SD card.
    • Their guide is more informed than I am, but the short is I got my switch into RCM (recovery mode) with the paperclip method, made an SD card with Atmosphere, Homebrew Menu, and NX-Activity-Log on it, downloaded fusee-launcher and the fusee, hekate, and lockpick_rcm payloads, launched hekate, and then booted into homebrew menu
  • I ran NX-Activity-Log (open an app while holding R trigger to get to HB menu) and choose NX-Activity-Log
  • Find the JSON export button and run it
  • Copy it off the SD card

The output ends up looking something like the below. Note this is abbreviated and there are other event types in the output too.

{
  "exportString": "September 24 2022, 05:08:03",
  "exportTimestamp": 1664014083,
  "exportVersion": "1.4.0",
  "users": [{
    "id": "################################",
    "name": "#########",
    "titles": [{
      "events": [{
        "clockTimestamp": 1546352350,
        "steadyTimestamp": 51548,
        "type": "Launched"
      }],
      "id": "0100A2F006FBE000",
      "name": "Cat Quest",
      "summary": {
        "firstPlayed": 1546352340,
        "lastPlayed": 1546354200,
        "launches": 1,
        "playtime": 1860
      }
    }]
  }]
}

After all of this I also took a NAND backup and dumped my keys too so if I ever wanted any other data in the future, I could hopefully extract it by flashing a new switch.

Thanks

Really big thanks to NX-Activity-Log and their JSON export feature, switch.homebrew.guide and their other site sdsetup.com for making rooting understandable to an outsider, and to the Team Neptune Discord for steering me in the right direction.

Read More »

Extracting a .unitypackage without Unity3D

unity3dpythonunity

It looks like all the libraries that currently exist to extract .unitypackage files are broken/don't exist anymore (or at least the ones on Unity Answers). So I made a new one in Python.

Download unitypackage_extractor on GitHub

It's also on pypi in case anyone might want to use it in some sort of automated workflow.

While Unity packages are just a .tar.gz, they have a special file structure that doesn't make them usable after extracting right away. Every file and it's data is broken up over multiple files and stored in specific folders. This script just rebuilds the original heirarchy from those files.

Read More »

LTU Forge Global Games Jam

Participated in my first games jam a couple weeks ago, the LTU Forge Global Games Jam. Super fun, a little stressful at times, but it was so exciting to be able to do it in such a welcoming environment. Coming out of it, I feel inspired and more experienced for having done it. I really want to do another; a feeling similarly expressed by my friends.

Carl Escape is a narritive/dialog based game, so naturally that was the first system we worked on.

Multiple dialog bubbles with focus on the currently talking character was the implementation we went with after a few iterations. Blukat worked on the data structure that backed this one.

Basic dialog

While the final game had only two characters, it allowed for dynamic names, backgrounds, and choices in the dialog tree

Dialog with full artwork

As the art and storyline came in from JD, JabberJaws, and BearAxe, Blukat and I plugged in the assets into the API, everyone coming together when things needed final tweaks. Half way through, the dialog front end was mostly complete so I switched over to working on the minigames.

The core minigame was a simple skill check to test the player during certain decisions of the game.

Quick text effect at the beginning and you get dropped in the game. Hit the green to win. It's faster and the win area smaller for more difficult versions of this game.

Skill check minigame gif showing that you have to stop in the bar in the green area

What was fun about these minigames being independent from the rest of the game is that they can be imported into the core game and placed anywhere. Being PIXI.Containers, they lived right in the scene graph with everything else.

Skill check minigame embeded into the main game

The other minigame started out as a bottle flipping game (I got a little side tracked) but turned into the final game for escaping Carl.

Thanks to some awesome last minute artwork from JD. You put the key in the hole to get back into your hours and escape the antagonist.

Minigame where you have to put the key in the door hole

I'm happy that in the end, the game worked when it was presented to everyone though it did have a bug or two. It works on both mobile portrait and desktop though should be barely playable at any resolution. Really wish I would've thought to use a transform: scale() on the game instead of writing a massive resize method though. I did this for a game at work recently and it was so much less work to set up that the one in Carl Escape.

During/after the jam I wrote down a few points to keep in mind for future projects/game jams:

  • Games jams are an exercise, not a test. This was something I told myself multiple times to lessen the anxiety.
  • Dead simple mechanics are easy to get down and then build on.
  • Narritive stories have tons of boilerplate.
  • Don't get caught up in making "the best game"
  • Trying to act as a leader for the team doesn't really work, it's everyone collective motivation and effort that will push the game over the finish line and really communicate what it's about. It's less anxiety that way too.
  • Parameters like group size, development experience, planning amount, game type, and engine choice/group engine use make quite a difference in how the game will come out.
  • Familiarity tools is essential in allowing people in their roles to be the most efficient with their time.

The other teams put together some really interesting ideas. It's impossible to compare between other's work due to the differences in team structure and team decisions, but I think ours held up well and got some good laughs at the final presentation. So glad to have participated in this!

Read More »

ConEmu and cmder fix for saving current working directory

ConEmu and tools built on it like cmder are awesome for Windows development. I can't see myself ever going back to conhost.exe with its lack of color, unicode-support, buffered-scrolling, tabs, configuration, sane hotkeys... ConEmu does come with a set of annoyances though.

The biggest ConEmu annoyance for me is it not properly persisting the current working directory in Git Bash. Long story short you need to add this snippet to your .bashrc.

#ConEmu Integration
if [[ -n "${ConEmuPID}" ]]; then
  #For WSL and cygwin/msys connector (which ConEmu will use for Git bash). It
  #sends an operating system command (OSC) to cygwin/msys connector to update the
  #cwd on PS1 print (the \$PWD in the below string, \w will not work).
  #https://conemu.github.io/en/ShellWorkDir.html#connector-ps1
  #https://github.com/Maximus5/ConEmu/issues/1752
  PS1="\[\e]9;9;\"\$PWD\"\007\e]9;12\007\]$PS1"
fi

ConEmu by default does not know when Git Bash changes its working directory. This breaks features like tab cloning (hotkey WinS), %CD% in tasks, and workspace persistence. To notify ConEmu of changes, you have to send an operating system command (OSC) using special control characters. The ConEmu documentation does describe how to set this up but I still found it buggy. After extensive testing, I found that only paths that contain the ~ character break it and submitted a bug for it. Using the above snippet I created implements the OSC described in the documentation and also fixes the bug.

This fixes tab cloning, %CD% in tasks, and workspace persistence for non-cmd shells. You can now use all of those features and do nifty things like using the same directory when opening a new task no matter what shell. All you need to do is add /dir %CD% to your "Task Parameters" so that when ConEmu starts that task, all commands will have %CD% as their current working directory.

Con Emu Task Parameters GUI with extra parameter

Read More »

Vue.js render() and $slots; Corrupt DOM

vuevuejsjavascripthtml5htmltemplate$slots

Just ran into an issue today when making a component with a custom render() function and messing around with vnodes passed in via $slots. A seemingly simple template produced really odd results where some DOM elements would disappear, some would be duplicated, some would be out of order, and others would have their inner content ripped out to their outside after a few rerenders. Small template tweaks would also produce vastly different output, sometimes seemingly correct output.

You can see an example in this codepen:

Fix

After hours of debugging I found assigning a v-bind:key to every element fixes it, kind of like how v-for needs a v-bind:key to work properly.

You can do that using this snippet:

{
    created: function(){
        //Give each vnode in your slot a key using forEach index
        this.$slots.default.forEach(function(vNode, index){
            vNode.key = index;
        });
    }
}

Vue's reactivity and element reuse can be seamless and magical for most uses but sometimes it really just bites you in the ass, kind of like this case.

Read More »

Is WebAssembly faster than vanilla Javascript?

webassemblywasmperformancejavascript

I keep seeing GitHub issues of people just like me trying to figure out what WebAssembly (Wasm) and previously asm.js mean for performance-related javascript (in my case, games). WebAssembly should introduce less abstraction between you and the hardware and so your code should in general run faster, right? In reality this question is harder to answer because WebAssembly runs in a Javascript VM-like environment and was not made directly motivated for performance. I'll be putting aside the misinformation and anecdotes to hopefully find out if and how applying Wasm might make your projects more performant.

A bit of background on Wasm

Is%20WebAssembly%20faster%20than%20vanilla%20Javascript%2075a63f0c627a498498088ae744e3c344/2000px-Web_Assembly_Logo.svg-1.png

WebAssembly Logo

Wasm was originally created for so much more than just performance. Wasm is about providing a proper compile target for native code to get into the browser. In the earlier stages of the development cycle, Wasm was actually asm.js, a unofficial JavaScript standard that only supports strict subset of JavaScript to allow native code to compile and run in a JavaScript VM. Wasm is also about providing an environment where multiple sources of code can run safely at a low level where things like memory management and control flow structures (jumping and loops) matter. Already Wasm is doing a ton of things that previously were infeasible or a real pain to do in the browser. (Sourcing a lot of this from this blog post by Adrian Colyer. It's good to keep this in mind while we ask performance only questions.

Wasm loads much quicker than Javascript code in pretty much all cases I've seen that is not really a topic that's up for debate so I'll skip over load performance and focus on runtime performance.

After quite a bit of searching and review, I found a few people who have done research into Wasm's runtime performance specifically by using benchmarks:

  • In a joint Google, Mozilla, Microsoft, and Apple paper (May 2017) (also mentioned in that blog post by Adrian Colyer updating the wider Internet community, Wasm was found to perform close to but still less than C code for runtime of certain benchmarks. Taking test cases from the PolyBenchC library, the paper found that Wasm ran within 2x of native speeds in most cases and for some within 10%. I don't think you're going to get much better than that given the use case of Wasm and it being more abstracted and safe than actual compiled C code. The paper also found that Wasm is 33.7% faster for these same test cases than asm.js (which was already faster than javascript).
  • Alon "Kripken" Zakai, a Mozilla engineer and creator of both Emscripten (LLVM to Javascript compiler) and Ammo.js (port of Bullet Physics to Javascript and Wasm), has also written about Wasm vs asm.js (March 2017), calling out multiple features that Wasm can use over asm.js and the future of what Wasm can add. And while he provides lower estimates (specifically, 5% speedup between Wasm and asm.js) this is due to testing asm.js that was ported to Wasm, and not direct Wasm compilation.
  • The game engine Unity3D has seen improvements in using Wasm in a 2018 benchmark over their 2015 asm.js benchmark. Their 2018 post goes quite into detail over a lot of little changes they've observed.
  • An engineer from Samsung performed a similar benchmark (May 2018) with matrix multiplication, providing multiple implementations with different optimizations. And while he found Wasm to be faster for larger array sizes, he concludes that for normal web development, it's probably smart to stay with normal Javascript for now.
  • One final article to check out.

This gives me a good feeling. Wasm will give you some performance increase but only for applications with datasets that require it. Building websites probably won't be moving to Wasm anytime soon.

For those of us that do want to use Wasm from Javascript for games, realize that Wasm isn't meant for a dynamically-typed, garbage-collected language like Javascript. Typescript gets you closer to a Wasm compatible language but it looks like Javascript has it's own flavor now for Wasm, AssemblyScript, a stricter/modified Typescript. This article discusses other options for running Wasm from Javascript.

Read More »

Chemistory Level and Net Code

chemistory level

Chemistory over the past couple weeks got a few new features, the biggest being an actual level and client/server networking code (or at least the start of it).

netcode-1

There's a separate build for client (Browser) and server (NodeJS), both of which run THREE.js and Oimo.js, though the server doesn't actually render anything. It took a switch to Gulp from Grunt, a pull request to WWOBJLoader2, and heavy use of ifdef-loader but it all actually talks to each other. Next steps are to add boilerplate for RPCs and member syncing and test out a little bit of multiplayer.

I really hope this goes quickly! I want to get back to game play and UI so I can start play-sharing it with my friends.

Read More »

A Simpler Blender Development Environment

After accidentally running Blender from a native console, I realized a much easier way to setup Blender for iterating over features/bug development. My old Blender Python module reloader was becoming too unreliable in my codebase so it was a welcome discovery.

To easily reload Blender for development:

  1. Set up the Blender UI to your liking to test your add-on. Mine happens to be the scripting interface but instead of the notepad on the left, I have the User Preferences view with the add-on tab open.
  2. Save this as your startup file for Blender
  3. Run ./blender.exe from cmd, bash, or Git bash to capture error output in the console without having to toggle it manually every startup.
  4. Optionally, run while :; do ./blender.exe; done from bash or Git bash instead to continuously rerun Blender when it exits automatically.
Read More »

HelloWorld Games Jam Outcome

My current company, HelloWorld, hosted a small games jam after hours. Over the course of 5 days, James (another dev at HW) and I put together two small concepts utilizing a networking engine one of my other coworkers wrote

The original concept for my game was platformer where the player must escape a pool of rising lava and race her friends to some sort of goal. The first step was intergrating the networking engine with THREE.js and physics to get 3D aesthetics and correct movement. The actual gameplay is quite shaky due to integration problems and time limitations.

Once the boilerplate was as complete as it could be, I spent a bit of time throwing together a test level and playtested it with James.

For some added spice, I tried my hand at adding an animated model for the player. THREE.js and Sketchfab made this easier than I expected though I had to use the converted GLTF format SketchFab provides (THREE.js's THREE.FBXLloader doesn't support animations and has other corner case issues).

Given the time constraints this is as far as I got but I say for an 8 hour game jam that's not too bad.

4 of the total 8 hours went into this integration

4 of the total 8 hours went into this integration

Player 2 can be seen stuck on the right side of the screen (mostly due to networking desync)

Player 2 can be seen stuck on the right side of the screen (mostly due to networking desync)

Say hi to Meelo the cat

Say hi to Meelo the cat

Super exciting and I'm looking forward to the next time I get to participate in a games jam. I've been keeping my eye on the The Forge to see if Lawrence Tech will host in 2019 where maybe a few people from HelloWorld can participate.

Read More »
Older posts