• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Best of the Wurst 3

Status
Not open for further replies.
Level 23
Joined
Jan 1, 2009
Messages
1,608

Best of the Wurst 3


Welcome to the third issue of our Wurstscript blog! And happy new year!

Background: Wurst is a compiled, higher level programming language that provides powerful tools and safety for an integrated development experience in wc3 modding.

The theme of this month's issue is "object-editing in wurstscript".


Updates

Due to increased usage of the Wurst Tools, several critical bugs have been found and addressed in the month of december. Make sure to download a fresh version of the setup tool and update your compiler as well as projects accordingly. We are also glad to have accepted several Pull Requests for the standard library, and are proud to present Wurstbin, a wurst pastebin. Wurst and tools also now found their final home at wurstlang.org.

Compiler

  • A couple of severe dynamic dispatch bugs have been fixed
  • The buildmap command doesn't output maps with corrupted header anymore
  • More jass types and natives like units and groups have been implemented for compiletime
  • Compiletime hashtables now more closely mimic wc3 hashtable behaviour
  • Class array-members can now be initialized during instantiation
  • ObjData .txt output now uses the cascade operator to chain calls
  • Fixed cases where text highlight was off-by-one in vscode
  • Improved unit test console output fidelity
  • Packages ending with "Tests" are now ignored from suggestions
  • Logs from all tools are now stored at ~/.wurst/logs

Standard Library

  • We merged several user-created pull requests, namely fixing OnUnitEnterLeave #20 issues and replacing the broken sync packages #19. Big thanks to @Sir Moriarty and @Trokkin
  • Along with the unit test improvements for the compiler the stdlib package, Wurstunit has also been refactored and Tests for groups and units have been added
  • Added more group and map convience functions
  • UnitIndexer is now more flexible and allows configuring which units to index and how to index them

Setup App

  • The setup no longer crashes if its google network test doesn't respond with 200 OK
  • Proper logging has been added and is saved to ~/.wurst/logs/setup.log
  • Regressions regarding project updates have been fixed
  • The wurst.build file is now recognized as yaml inside vscode

Introducing Wurstbin

An elegant and simple way to share your wurst and jass code snippets. No login required.
Check it out
8bVnUT1.png



ObjectEditing 101

WurstScript ships with a jass "interpreter", which can evaluate Jass code outside of wc3. This is usually done when compiling the project - hence we name the timeslot it occupies "compiletime". This is the opposite of running the map inside the game, which we refer to as "runtime".

bJA1su0.png


You can mark any function to be executed at compiletime, by simply annotating it with .@compiletime. The only caveat of this is that you can only use jass natives that have been implemented for compiletime, and you only have access to resources from your script that have also been initialized at compiletime.

Let's look at a small example:

Unit Generation Example

Wurst:
import UnitObjEditing
@compiletime function createUnit()
    new UnitDefinition('xyz1', 'ewsp')
    ..setName("Wurst Generated Unit")
Here we create a new UnitDefinition based on Wisp, and assign a name for it. These objectdata-classes then get transformed into the approriate binary files, in this case war3map.w3u, which are retained for runtime. Wurst is perfectly capable of managing these assets alongide units defined in the normal object editor.

Retaining variables

You might want to generate values at compiletime and just keep the evaluated result to use at runtime. A very common usecase for this is generating IDs.
Let's enhance our example from above with an automatically generated id which is stored in a global:

Wurst:
import ObjectIdGenerator
constant MY_UNIT_ID = compiletime(UNIT_ID_GEN.next())

@compiletime function createUnit()
    new UnitDefinition(MY_UNIT_ID, 'ewsp')
    ..setName("Wurst Generated Unit")
The UNIT_ID_GEN.next() call refers to an ObjectIdGenerator object that generates only safe IDs inside a range that isn't used by standard units. As you can see, you have to wrap your expression with compiletime() for it to be evaluated and retained for runtime.

Ability generation best practises

When generating abilities one should avoid using AbilityDefinition directly - instead, one of its subclasses, e.g. the concrete AbilityDefinitionFireBolt for Fire Bolt. This way you don't need the original id and can use the functions of the concrete subclass to modify ability-specific fields.

Wurst:
import AbilityObjEditing
@compiletime function generateFireBolt()
    new AbilityDefinitionFireBolt(MY_FIREBOLT_ID)
        // This setter would not be available on
        // the base class [icode=jass]AbilityDefinition[/icode].
        ..setDamage(1, 200)
For custom triggered hero spells, channel is frequently used. Take a look at the API provided by ChannelAbilityPreset:

Wurst:
import ChannelAbilityPreset
@compiletime function generateLeap()
    new ChannelAbilityPreset(MY_LEAP_ID, LEVELS, true)
        ..presetTargetTypes(Targettype.POINT)
        ..presetCooldown((int lvl) -> 30 - (level * 2))
Notice the presetCooldown call with the lambda expression. Next to normal setters, the standard library provides preset* functions that are either convenience wrappers or take closure parameters to fill multiple levels using only one call.


Hiveworkshop Wurst News

  • @Frotty and @Cokemonkey11 are now approved code reviewers for Wurst on hive workshop.
  • The setup app is now an approved resource in the tools section

As always, come and chat with us on IRC or post on this thread to provide us feedback for these monthy blog posts, as well as requesting what you want us to cover next.
 
Last edited:
This is one of the best, if not the best feature of Wurst. I've tested object generation with my newly updated Warcraft 3 v.1.28.5 and I realized that the ObjectMerger won't work anymore. The next thing I did, I ported everything that I made in lua to vscode and voila, it worked.

I was originally going to ask about what would happen to uniquely generated objects when importing the necessary data again, but it turned out fine in the output, so kudos to your efforts.
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
I haven't tried Wurst myself but looking at some sample codes, I'd say that it's incredible! Obvious improvement over vJass! The syntax & structures are very clean & intuitive, it will surely make coding maps much easier.

If only it removed that "eclipse requirement" much earlier, I'd already be wurst user by now.
But that said, it still need adjustments to move from vJass, so I will stick with vJass for now.

But for future coder: waste no time! skip vJass and jump straight into wurst!

To the developer: gratz! it's real achievement you got there! ;]

EDIT:
A question, does it support code regions? Like in c# we can use #region to "fold" certain part of our codes. That'd be a really nice feature.
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
^^ The current Wurst Setup uses VS Code, not Eclipse. I'm not sure if you already knew that.
At some point, iirc, they used Eclipse. That's why I rescinded to test wurst for the first time.
But wait, does it mean we don't have to compile the whole map anymore just to save the code/triggers?

The only real annoying thing with wurst is that there is not that many libraries for it yet.

So if I wanted something like a stun library. There is no public one yet.
Well. You can hog all the credits and start making those libraries. Actually vJass has a lot of good libraries only because of contributions of few users. So you can probably create bunch of libraries and become wurst legendz!
 
Making a straightforward Status library isn't hard in wurst, because the standard library already provides you with most of the things you need - dummy casters, object data generation, enums, table manipulation, etc. The whole point of this is that whatever idea you had in vJass, it's way more intuitive to implement in wurst, but its small userbase means that most of specific things don't come prepackaged. I am making a really versatile BonusMod system, for instance, that lets you add a new bonus in a few lines of code, and that includes object data bonuses of several types, as well as code bonuses.
 
Level 23
Joined
Jan 1, 2009
Messages
1,608
The only real annoying thing with wurst is that there is not that many libraries for it yet.
As usual, system or library requirements are often subjective. As soon as it goes too far into user space, having it in the standard library isn't too advised.
But of course you are right. vJass' advantage is that it was popular during wc3's prime and had a bunch of active content producers before wurst, and the wurst community is still relatively small, so there aren't many third party packages published.
Of course there is the other side of the medal, when back in the day pretty much every big forum (hive, wc3c, thehelper) rolled out their own stack of "core" libraries, which we try to avoid.

At some point, iirc, they used Eclipse. That's why I rescinded to test wurst for the first time.
But wait, does it mean we don't have to compile the whole map anymore just to save the code/triggers?
Eclipse + Xtext is probably still the easiest and fastest way to get nice IDE feature for a custom language, which is why we used it, but it also has many downsides indeed.
I'm not sure what you mean by "save the code/triggers". Your code is in external .wurst files outside of the map, and hence saved when you saved those files.
You get live reconciling (errors, warnings underlined) in vscode when typing your code, without needing to compile the map.
But you still need to compile the entire map to get a playable output file. (in vscode though, not the world editor).

A question, does it support code regions? Like in c# we can use #region to "fold" certain part of our codes. That'd be a really nice feature.

Code folding isn't part of the compiler/language. This is handled by the chosen IDE, in this case vscode.
5HyoTP6.gif
 
Last edited:
^To add to this, wurst scripts are typically 50-300 lines of code, and you should write your code to be as concise and decoupled as meaningfully possible. This means that you shouldn't be writing 1000+ line scripts, since there's any one functionality that would require such a huge script (aside from the Assets/ObjEditing packages) and you shouldn't need #region for this exact reason.
 
Status
Not open for further replies.
Top