Dustscripting Is Live

Dustscript support has been added to Dustmod. Dustscripts allow level authors to make their levels more dynamic by adding their own custom game behavior. Want the player to have to clear the enemies in a room before being able to progress? Dustscript can make it happen.

Dustscript makes use of the AngelScript runtime already used within Dustforce. Each script is run within its own isolated context that communicates with the game script using the Dustscript API. Keeping scripts in their own isolated contexts rather than running them within the game context was necessary to prevent scripts from e.g. sending cheated replays and decoupling scripts from the exact game ABI.

Angelscript

A basic understanding of Angelscript is needed to write Dustscripts. Fortunately Angelscript borrows a lot of syntax from C++. The Angelscript documentation page can be found here. Dustscript relies heavily on object handles in particular so understanding how they work is helpful in understanding how to use Dustscript.

The Dustscript API

The API definitions and documentation will be updated here and here. I will avoid breaking the ABI so that old scripts will continue to work, however there may be some exceptional circumstances where this is necessary while the Dustscript system is still in early development.

In order to help with save states (and multiplayer) your scripts can not make use of non-const globals (you should see an error). Instead you can store all of your state as member variables of your script class. In addition, the following constraints should be followed to ensure your script works for online multiplayer:

  • Do not call draw functions outside of the script.draw() callback.
  • Do not update any state within the script.draw() callback, it should only be a rendering of the current game state.
  • Do not update game state based on information obtained from calls like ‘get_active_player()’. These kinds of calls should just be used for rendering.
  • Do not use uninitialized memory. Angelscript does not automatically zero data. (update: I believe this is no longer necessary but still recommended)

Writing Your First Script

First, after creating a new map make sure to set the level type to “Dustmod”. Only dustmod or nexus level types can have scripts added to them.

Screenshot from 2017-07-27 18-55-30.png

Next, let’s write a quick script to attach to this level. In this script we’re going to award the player their air charges every time we see them collect dust. Get out your favorite editor and save this as the file “sample.cpp” (the cpp extension is useful if your editor supports syntax highlighting since Angelscript is so similar to C++). You can save this file in your level_src directory or in the directory containing the dustmod binary.

const int MAX_PLAYERS = 4;

class script {
  /* We don't actually use the scene object in this script, but most will. */
  scene@ g;

  /* Keep track of how much dust we had in the last frame. */
  array<int> dust_last;

  /* Keep track of how much dust we had when the last checkpoint was saved. */
  array<int> dust_checkpoint;

  script() {
    @g = get_scene();

    /* Initialize each player to have collected 0 dust last frame. */
    for (int i = 0; i < MAX_PLAYERS; i++) {
      dust_last.insertLast(0);
      dust_checkpoint.insertLast(0);
    }
  }

  void step(int entities) {
    for (int i = 0; i < MAX_PLAYERS; i++) {
      /* Try to get a 'dustman' object handle for each player. */
      entity@ e = controller_entity(i);
      if (@e == null) {
        continue;
      }
      dustman@ dm = e.as_dustman();
      if (@dm == null) {
        continue;
      }

      /* If the player exists check its total filth and see how it compares to
       * last frame. If it's increased set their 'dash' (aircharges) back to
       * their 'dash_max' (max aircharges). */
      int dust_cur = dm.total_filth();
      if (dust_cur > dust_last[i]) {
        puts("Restoring Air Charges");
        dm.dash(dm.dash_max());
      }

      /* Note the last seen dust count for thsi player. */
      dust_last[i] = dust_cur;
    }
  }

  void checkpoint_save() {
    /* Save the current dust counts when the checkpoint is saved. */
    dust_checkpoint = dust_last;
  }

  void checkpoint_load() {
    /* Restore the saved dust counts when a checkpoint is loaded. */
    dust_last = dust_checkpoint;
  }
}

Back in the Dustforce client make sure you toggle on the console (by default this is done using F12). Navigate to the scripts tab and enter the script name “sample.cpp” as shown and push enter.

Screenshot from 2017-07-27 19-22-55.png

You should see the console display something like “Compiled 1682 bytes from ‘…'”. Try introducing a compile error into the script and compiling again by pushing Control and clicking the “[x]” button next to the script name, you should see the console display the compile error.

Now you can test out your script. Try adding a tall vertical wall with dust on it as shown. By collecting the dust you should now be able to continue to make air jumps and climb the wall.

Samples

Filth Air Charge (sample above)
Prop Test
Hitbox Test

Security

Dustscripts are run in their own private context and can only access the Dustscript API. Nonetheless the Dustscripting system does open up a large attack surface someone could conceivably try to exploit. If you’d prefer to not to run custom scripts you can check ‘Disable Scripts’ in the Dustmod menu.

Advertisements

A Year of Dailies

May 17th, 2016 was the day that the Dustkid daily went live, a year ago today. Over this year we’ve seen a lot of data come in without any kind of visualization outside of the Daily page itself.  In this post I want to dump a lot of that data that I thought might be interesting to look at one day.  Additionally I’ve included complete data on some of what will be summarized in this post at Dustkid Daily Stats.

There have been 370 maps selected as dailies at this moment.  This is slightly over the expected 365 due to the “daily” not initially being a daily and a couple forced re-rolls.  Of those 370 the rest of the stats will be on only 367 as I’ve left out Peta Difficult, Titan, and today’s daily (stock maps were never meant to be dailies and Peta doesn’t even have a leaderboard).

Over these dailies we’ve seen 9,641 leaderboard entries averaging 26.3 entries per daily.  Of those, 8,353 of those (86.6%) were an SS on the ‘Score’ leaderboards.  Bringing renewed energy back to older maps has frequently resulted in new Score and Time world records.  Over the year 252 (68.7%) dailies minted new Score world records and 248 (67.6%) gained new Time world records.  Often, several people managed to beat the previous world records as new routes were found or new tech could be used.

The daily is selected from all visible maps on Atlas that are not part of the Community Map Pack (and haven’t before been a daily).  SS count is used a simple heuristic to favor selecting higher quality maps that got more play, initially.  I’d like to thank the authors of the selected maps and list those authors who appeared at least 6 times:

Shin Rekkoha 21
TheBirdOfPrey 18
Tropicallo 11
ShurykaN 10
Meark 9
DustCreep 9
TwinkieSWF 8
Giamma 7
Clearly Not a Towel 7
DoughNation 6
indapop 6
Krankdud 6
Jvcpro 6

And of course, I’d like to thank the people who actually participated in the dailies and gave this project life.  The following table shows the top 10 daily participation counts.

DG ‘Anand’ 319
msg555 309
indapop 293
EtherealSamantha 279
theduesta 277
Sunny 276
Brayd of Guy 258
mister__simon 248
DDFranky 241
Malice 232

To create a type of “Daily Composite Leaderboard” I constructed a basic medal system that awarded 100 points for first and 40% less points each rank thereafter ending at 1 point for 10th.  These are the top 10 on this composite leaderboard for Score including their top 3 medal counts.

Username Points 1st (100 pts) 2nd (60 pts) 3rd (36 pts)
indapop 13368 87 53 24
msg555 11979 61 58 27
Xiamul 4964 37 13 7
mister__simon 4461 10 19 25
Nighthawk 3819 19 21 12
TwinkieSWF 3139 11 15 18
Sunny 2987 1 18 19
Fishy 2929 10 11 19
Sivade 2889 16 10 10
TiMMaY- 2879 11 9 18

Similarly, these are the results for Time

indapop 13884 97 41 25
msg555 6492 26 32 19
Fishy 5508 28 28 14
TwinkieSWF 5164 25 26 18
Sunny 4893 19 20 20
Xiamul 4736 32 13 10
EtherealSamantha 3444 7 15 19
mister__simon 3160 10 8 22
Nighthawk 3094 16 12 11
DG ‘Anand’ 2935 17 14 5

Only 27 apples were hit during a year of dailies.

Dustmod Has Updated

7.8.1

  • Fully implemented affine camera support (i.e. rotations)
  • A lot of new scripting functionality
  • Various performance improvements
    • Removed off-screen work in draw
    • Changed segment data structure
    • Improved basic I/O routines
  • Fixed behavior regression seen in tires/trash bags
  • Fixed trigger widths not saving/loading properly for some triggers (will still be broken on vanilla, however)

7.7.1 Changelog

  • Level Scripts!
  • NG+ works correctly for custom nexuses
  • First version of custom level scripts
  • Fixed non-virtual dustman being loaded on tutorial replays
  • Fixed rare trashcan game crash
  • Allowed some visual dustmod triggers to be used on normal maps (z_wind_trigger, z_wind_generator, z_particle_trigger, z_text_prop_trigger)
  • Added console toggle (for scripting, primarily)
  • Added some padding around entity/prop selection boxes
  • Added screen scaling for consistent network play, enabled use of mouse in network play
  • Improved performance of custom nexus tome with thousands of levels

Hi everyone! After quite a pause in Dustmod update while I worked on making multiplayer work, I want to start pushing Dustmod updates again that contain the multiplayer logic.  Unfortunately due to including engine builds now it would be difficult for me to make the in game updater work so you’ll need to grab an appropriate archive below to install manually (future updates again will work in game).

Dustmod Archives

Pick the archive suitable for your version of Dustforce and copy the contained files into your Dustforce direction (the directory that contains the Dustforce executable).  Note that the installation now sits side by side with the existing installation of Dustforce so you can easily switch between vanilla or Dustmod.  If you’re playing on Steam you might like to add the Dustmod executable to your game launcher by navigating to “Games” ->  to “Add a Non-Steam Game to my Library” and finding the dustmod executable, typically at “C:\Program Files (x86)\Steam\steamapps\common\Dustforce\dustmod.exe”).  Steam will still recognize the game as Dustforce once the game is running.

Dustmod is freely available, however donations are always appreciated. Donate

The Changelist

  • Added online multiplayer support via rollbacks
  • Added multiplayer nexuses now accessible where the multiplayer nexus use to be
  • Now sends replays to dustkid proxy without hosts file change
  • Added some polish to multiplayer mode
  • Support for multiplayer replays
  • Determistic menu/world step interleavings
  • Removed save/load checkpoint for save/load state in frame advance tools
  • Fixed excessive camera shake bug from last update
  • Properly track apple count in game for the meme
  • Added draw/input frame rate tracker
  • NG/NG+ will now properly reset nexus checkpoints
  • Performance improvements for those with a lot of custom level times (i.e. the pause when trying to open some doors)
  • Added dust projection visualization to help understand what dust gets cleaned by attacks
  • A ton of smaller things I don’t remember

Notes On Multiplayer

I’m still working on multiplayer so many things may not work.  You’re welcome to try it out but please understand that you may run into technical issues in addition to the lobby system being fairly simplistic.

Nexus TASing with Dustmod

This blog post is meant to detail how to use the “Load Nexus Script” functionality in Dustmod.

What is Nexus TASing?

Nexus TASing allows you to feed Dustforce a sequence of inputs that can be played back directly in the game.  This is different then the normal replay system as the play back can function within the nexus and can navigate the menu system.

TAS Script Format

TAS scripts are text files that will be fed into Dustmod.  Dustmod will look for these files in a “tas” directory within the folder that contains the Dustforce executable.  The scripts use a line based format.  Each line is either a command or describes the inputs for a frame.  Trailing whitespace or anything after a ‘#’ character is ignored for a line.

Input lines

Input lines are a sequence of 9 ‘1’s or ‘0’s describing whether each of the below inputs is pressed or not during the frame.

  1. left
  2. right
  3. up
  4. down
  5. jump
  6. dash
  7. light
  8. heavy
  9. escape

Whitespace between each ‘0’ or ‘1’ character is ignored.  As an example the line “010011000” describes a frame where right, jump, and dash are each pressed.

Command lines

Command lines are assumed to be any line that does not begin with a 0 or 1.  Commands that take arguments should separate the command name and arguments using the ‘:’ character.

  • LOAD – The LOAD command takes 3 parameters; character_id, save_id, level_file.  character_id should be a number between 0-3 identifying the character to load.  save_id should be name of the save file (see the ‘Creating a save file’ section) to load.  level_file should be the file name of the level to load (e.g. “Nexus DX”).e.g.
    LOAD:0:outsidedahlia:Nexus DX
  • SYNCLOAD – Pauses the script until the first frame that your character can take inputs again.  While the script is paused all inputs are set to 0.
    SYNCLOAD
  • STATS – Load a stats file containing key state, door state, and level scores.  The command takes 1 parameter which is the identifier of the stat file to load which unfortunately currently needs to be an integer.  You can copy a stats file in much the same way you would copy a save file for the LOAD command.
    STATS:4 # Load in stats data from user/stats4
  • INCLUDE – Execute commands from a script file.  The script will begin executing this frame.
    INCLUDE:tunnels.txt
  • MOUSE – Sets the mouse state for the next frame.  This command should appear before the input line that is meant to occur on the same frame.  It takes 3 parameters, mouse x-position, mouse y-position, and mouse button state.  Mouse positions can be found using the extended debug data display.  Note that the origin (0, 0) is the center of the display and that the majority (all?) of menus in the game have fixed positions independent of game resolution.
    MOUSE:75:-25:10000

    Button state is a sequence of ‘0’ and ‘1’ characters that indicate the pressed state of the mouse related buttons in this order.

    1. Left Click
    2. Right Click
    3. Middle Click
    4. Scroll Up
    5. Scroll Down

Creating a Save File

Save files are used to initialize your position for a TAS.  These are simply the checkpoint files already generated by Dustforce whenever you leave a nexus level.  The intention is that this will allow TASers to accurately initialize their position in front of a starting door based on where it was originally entered in the previous segment.

Whenever you leave a nexus level your position information will be saved to “user/save/1_LEVEL_NAME”.  For example when you enter downhill the game will save your position outside of the downhill door to “user/save/1_Nexus DX”.

To use a save in a nexus TAS script you should copy this save file and rename it to something like “user/save/outsidedownhill_Nexus DX” and then load it with a command like “LOAD:0:outsidedownhill:Nexus DX” at the start of your script.

Running a Script In Dustmod

To run a TAS script first create a folder in the Dustforce directory named “tas” and save your script within.  Then within Dustforce navigate to Dustmod -> Tools -> Frame Advance.  Then type the file name of your script (including any extension) into the ‘Load Nexus Script’ text area and push enter.

If successful your script should begin to execute.  Pushing escape at anytime will terminate the script executation.  You may also press F5 at to reload the script from the same file.  If the file could not be loaded for any reason the text area will blank and nothing further will happen.  Any format errors in the script itself will be silently ignored.

Give me an example script

LOAD:3:tunnels:Nexus DX

# Give a couple inputs
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
100000000
010000000
010000000
010000000
010000000
010000000
010000000
010000000
010000000
010000000
010000000
010000000
010000000
010000000
010000000
010000000
010000000
010000000
010000000
010000000
010000000
010000000
010000000
010000000
010000000
010000000
010000000
010000000
010000000
010000000
010000000
010000000
010000000
010000000
010000000
010000000
010000000
010000000
010000000
010000000
010000000
010000000
000000100
001000000
000000000
000000000
000000000
000000000
000000000
000000000
000000000
000000000
000000000
000000000
000000000
000000000
000000000
000000000
000000000
001000000
000000000
000000000
000000000
000000000
000000000
000000000
000000000
000000000
000000000
000000000
000000000
000000000
000000000
000000000
100000000
000000000
100000000
000000000
100010000

Dustmod

This page has been replaced by https://dustkidblog.wordpress.com/2016/11/19/dustmod-has-updated/

 

Hello Dustfam!  This is your starting point for downloading the latest version of Dustmod. You can find the replacement main2 scripts below.  Dustmod now packages additional content which you can download in game using Menu -> Dustmod -> About -> Download.

Download links: Steam version – DRM free version

Installation Instructions

To participate and view Dustmod’s leaderboards and update in-game you should first consider setting up dustkid.com on your client.  However this step is not strictly required.

To install download the appropriate version of the main2 script (Steam or DRM free) linked above (use ‘Save As’; some browsers may offer to open it with a text editor which may damage the file’s encoding).

Next, locate your existing copy of the main2 script; for typical Windows/Steam installations this can be found at: (you can also find the directory from Steam from Properties -> Local Files -> Browse Local Files)

C:/Program Files (x86)/Steam/steamapps/common/Dustforce/content/scripts/

Create a backup of this file and rename the dustmod main2 file to “main2”.  Some browsers may save the file with a “.txt” extension, make sure this is not there.  At this point you should be able to restart Dustforce and access the Dustmod menu.

Features

  1. Gives access to the ‘Dustmod’ options menu in the Main Nexus.  From here all of the Dustmod options can be changed.Screenshot from 2016-07-05 14:27:54
  2. Extends the Main Nexus to include a door leading to the Community Nexus.Screenshot from 2016-07-05 14:29:06.pngThe community nexus includes doors to other Nexus’ that have been created by members of the community.  It also includes a door that will automatically load the Dustkid Daily, a daily challenge map for dusters to compete on.Screenshot from 2016-07-05 14:29:25.png
  3. Automatically integrates with dustkid.com to enable viewing character leaderboards and mod leaderboards in game.  Click on the character icons on the score screen to filter by character.Screenshot from 2016-07-05 15:27:29.png

The Minecraft Mod

Note: This mod has been replaced by Dustmod.  Play minecraft mode from this instead.

Hey all!  The Minecraft Mod is now ready for play with it’s own custom in game leaderboards so you can challenge yourself and record replays playing in Dustforce’s hidden Minecraft mode.

Screenshot from 2016-02-06 12:37:39

What is Minecraft Mode?

Minecraft mode is a game mode created by the Hitbox devs that was disabled prior to release.  When enabled, your light and heavy attacks gain the capability of destroying any tile type!  Check out http://www.twitch.tv/msg555/v/37261286 for an example.

How to play this Mod?

First, you must have dustkid.com setup to be able to use the leaderboard functionality.  You can find instructions on how to do that at http://dustkid.com/setup.

Next, find your current content/scripts/main2 file and make a backup. On most Windows installations this will be located at:

C:\Program Files (x86)\Steam\SteamApps\common\Dustforce\content\scripts\main2

Then replace this main2 script file with the appropriate modded script file.  Steam users should use main2_minecraft_steam while those using the DRM free version should use main2_minecraft_drmfree.  When you’re done playing in minecraft mode you’ll need to replace the main2 script with the original version again.

Where can I find leaderboards on the web?

Leaderboards for minecraft mode are managed by dustkid.com.  The top times for each stock level can be found at http://dustkid.com/records/minecraft/all.  For any individual level you can find the minecraft leaderboard by navigating to that level on dustkid and clicking the pixelated broom icon in the top right.

What are the features of this mod?

The current version supports the following

  • Minecraft mode disabled outside of normal levels (you cannot destroy your nexus)
  • In game leaderboards powered by dustkid.com
  • Modified upload script to avoid times appearing on Hitbox leaderboards