• 🏆 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!

This Summer in Wurst

Status
Not open for further replies.

Cokemonkey11

Code Reviewer
Level 29
Joined
May 9, 2006
Messages
3,522

Hello! This is the first issue in a regular series of news posts about wurst and the wurstscript community. Actual years have passed since we last summarised wurst-related content for hive workshop news, so keep in mind that this is a very sparse summary, whereas our future news posts will more densely discuss current events.

Background on wurst: wurstscript is a programming language that compiles to JASS, and is developed alongside a suite of tools for a coherent development experience. It can even work alongside maps written in vJass. A usual workflow looks like this:
  • Design a terrain in a world editor (vanilla editor, WEX, or anything really)
  • Define objects, either using the object editor, or using the wurst “objectediting” subsystem
  • Write scripts, get instant feedback, and compile & build in the lightweight vscode editor
  • Check in your code to version control
Unlike vJass, wurstscript is a higher level programming language with a strict type system and a powerful optimiser. The result tends to be shorter code written quicker, without any sacrifice to performance.

So, what’s changed recently?

The Wurstscript community has been steadily active with frequent and regular changes, not only in the Wurstscript language, but across the whole map editing toolchain.

Wurstscript has found its niche as the toolchain that aims to maximise productivity and consistency of the development experience, without sacrificing quality.

The maintainers of Wurstscript are typically programmers first, and mappers second. Sadly, time constraints mean that we’ve not spent much time publicizing our progress for the larger modding community. This is something we’re keen to change, with more frequent curated summaries of what’s going on in our bubble.

With that context in mind, we hope this will be the first of many “Best of the Wurst” recap posts, wherein we highlight major changes - certainly more frequently than once every three years. There are too many changes to count, so in this post we’ll discuss some of the changes made just this summer that we’re excited about.


GUI tool for compiler updates and map project setup

oQDohHx.png

Probably the most major development this summer is a new tool for maintaining your installation of wurst, bootstrapping new map projects using a template and importing existing projects.

This tool maintains a global instance of the wurst compiler, automatically updates it, and can generate & update projects in a way that’s friendly for version control repositories as well as the vscode plugin.

The key point here is that we’ve done some refactoring of the wurstscript project structure to make wurst play more nicely and consistently with vscode. With the addition of dependency management and template projects, we envisage great strides in productivity as the project template (or templates!) progress.


New runmap/run-arguments design, with readonly terrain mapfile

Alongside great improvements to the JMPQ3 library, wurst now accesses your map project as a read-only archive file. Instead of overwriting it (as done traditionally), the compiler now writes built mapfiles out to a separate _build directory. This has tremendous gains, including:
  • Map files can more safely be version controlled since they’re accessed read-only by the wurst compiler.
  • In the extreme case, alongside native objediting, you can maintain your map end-to-end using your checked-in mapfile only for terraining purposes.
  • Better integration with existing maps that have JASS/vJass, because wurst can reuse the existing map script without mutating the source file.
  • Building and compiling wurst maps is now done independently in vscode by default - thus there is no need to use a custom editor (apart from for terraining) or even have warcraft3 installed at all.
Map metadata in wurst.build

c2Jd8z9.png

The overall structure of a wurst map project has changed, and now comprises two new metadata files: wurst.build and wurst_run.args - the first providing build artifacts, and the second for passing arguments to the wurst compiler.

One advantage of using the wurst.build file is that consistency is maintained from build to build - dependencies are segregated, and maintaining library code can be more modular and convenient.

Another advantage is that the world editor is no longer needed for some metadata like the map's name, description, author, etc - that metadata is sourced from the build file and injected into the final map.

The setup tool also interacts with this metadata by importing the wurst.build file, thus updating the project's dependencies to keep the standard library and other used packages up-to-date.


New docs and website, at a new address

Documentation and tutorials for wurstscript now live at wurstscript.github.io - a new landing page which we believe provides a much more consistent and attractive experience for consuming wurst. We’re encouraging community-written tutorials, and indeed the Wurst for vJass Users is one such tutorial.

Take a look here as well for the wurst setup tool mentioned above!


...And more

As a lightning recap of the last few years, here’s more:
  • Vscode plugin and workflow, which deprecates the Eclipse plugin and workflow.
  • New Github organization - refeactoring work to split up repo; now using gradle for dependency management.
  • Wurst standard library v2 now active and de facto standard.
  • Improved JASS compliance in Jurst (the vjass-friendly wurst dialect).
  • Compiler performance and RAM usage improved.
We hope you’ll find this summary informative. Please do give us some feedback as we plan to write curated content like this more frequently in the future.

As usual, we chat all things wurst at the #inwc.de-maps IRC channel.

Thanks!
--
@Cokemonkey11, @Frotty, and @peq



WurstScript - Blog - Getting Started
 
Last edited:
It's awesome to push Wurst with more publishing. Thumbs up, and I would follow also more of these. First, it's nice to get the technical background in short, but maybe there can also be a tiny wurst example in the future planned events to directly demonstrate its power in practice. Maybe just as gimmick at the end of the news, after showing the changes/features.

Is it planned to push resources on hive here, too? I realized just now that there's not too much information at the moment directly in the section. If it's useful we could put there a sticky, too, with general links, or information.
 
I used to be naysayer for all things new (with wc3 being so old), but ever since I realized how amazing Wurst is, I decided to dedicate the rest of my wc3 days to it. I think anyone who doesn't at least try it is missing out a LOT. If you believe your favorite library won't be on it - please do realize that the standard library has most standard functionalities anyone would want, and it is so easy to code in wurst that you can recreate anything you need.

Wurst per se doesn't make anything that was impossible possible - but it makes things practical. If you've ever had an idea that you've deemed to impractical to do in wc3, try it with wurst, I am sure a lot of them will become pretty simple!
 
Last edited:
Level 7
Joined
Sep 16, 2016
Messages
185
Frotty told me about Wurst... soon one year ago? 7 months? Anyhow, it was quite a long time ago and I've consistently used Wurst since then. And trust my words, I am NOT disappointed.

Keep up the good work on Wurst
 

Cokemonkey11

Code Reviewer
Level 29
Joined
May 9, 2006
Messages
3,522
I have 0 knowledge about proramming . My question is :

Hi, thanks for the comments!

1.This is wc3 related right?

Yes, it's relaetd to wc3 custom maps specifically.

2.What benefits this brings for warcraft 3 in practice (plz be specific and short,sorry but tnx)

Wc3 custom maps use "custom scripts" (triggers) to change gameplay. Wurstscript lets you do more stuff, faster, using programming.
 
Level 7
Joined
Sep 16, 2016
Messages
185
I will go ahead and ask a question too, then;

If beginners find using Wurst is hard, is it possible to contact anyone of you personally and chat, for guidance and support? The IRC channel?
 
Level 23
Joined
Jan 1, 2009
Messages
1,608
I will go ahead and ask a question too, then;

If beginners find using Wurst is hard, is it possible to contact anyone of you personally and chat, for guidance and support? The IRC channel?

The IRC channel is good for wurst related questions and usually the quickest way to get a reply. Most active wurst users reside here to chat and we are always happy to welcome new people.
However it is not the place to be taught wurst/programming step by step, or however intricate you expect "personal guidance" to be.

Sadly there aren't any tutorials teaching wurst to beginners without prior programming knowledge, and I don't know any good Jass tutorials I could recommend.
We want to have such tutorials, but it takes a lot of time and effort to create them.

Maybe specify what exactly you're looking for and just stop by the channel.
 
Last edited:
Tnx for answers but i got more questions . Along with the triggers, is it possible to improve how Wurst is reading for example warcraft 3 tilesets in custom map ?
For example regular wc3 tiles are made of 32 square samples (usualy 64x64 samples on 512x256 wc3 tileset plane, but i use 128x128 samples on 1024x512 tileset plane)...
Lets say my goal is to clone 512x512 pixels sample image by aligning every 128x128 square inside it to be tileable (share same edge) + in artistic way i acomplish almost identical look from 512x512 sample . But theres a problem : Meele maps will read every 128x128 square randomly (i lose original square order) and in World Editor its painfull to draw whole map and search samples to clone original source .
In 1 sentence : is it possible for custom map to program it to read 512x512 or 256x256 tile sample as a whole image on a 1024x512 wc3 tileset panel (plane)
P.S Sorry i am lunatic for this area...
 
Level 23
Joined
Jan 1, 2009
Messages
1,608
In 1 sentence : is it possible for custom map to program it to read 512x512 or 256x256 tile sample as a whole image on a 1024x512 wc3 tileset panel (plane)
P.S Sorry i am lunatic for this area...

I'm still not sure what you're asking for - You can't change wc3's load mechanisms without dll/exe hacks which need to be present on every players' wc3 installation.
In any case, I don't think this is related to Wurst at all.
 
Level 3
Joined
Nov 3, 2017
Messages
34
Are you missing programming experience in general or did you have problems setting it up?

Well, most likely the experience is not enough, so I'm writing on the normal JASS code freely and without problems, but it became interesting and tuned everything but did not understand how much to use, how the code executed in Visual Studio will reflect on my map
 
To put it in simplest terms - the code you write in VSCode is going to be added to the map and executed much like it would in the trigger editor or vJass.

Here's some examples:

JASS:
function InitTrig_SomeTrigger takes nothing returns nothing
    call DoSomething()
    call DoOtherThing()


In ordinary jass, this is the initialization block that is run when you add the trigger script to your map.

JASS:
library SomeLibrary initializer Init

private function Init takes nothing returns nothing
    call DoSomething()
    call DoOtherThing()

This is how you'd do it in vJass.

JASS:
package SomePackage

init
    doSomething()
    doOtherThing()

And this is how it is done in wurst. The only major point in how the code is executed (that should concern you at this point) is that you should know that the init block is executed much like the init block of the function InitTrig_TriggerName takes nothing returns nothing or library SomeLIbrary initializer Init would but, this is not a trigger script in WorldEditor, it is an actual file called SomePackage.wurst that's put in your project folder.

Another great thing about wurst is that you can have as many init blocks as you want, meaning that this is legit:

JASS:
package SomePackage

init
    doSomething()
    doOtherThing()

init
    callSomeOtherThings()

But more importantly most of the time you want to do this if you are making object data as well:

JASS:
package SomeObjectGeneratingPackage
import ObjectIdGenerator
import UnitObjEditing

constant UNIT_ID = compiletime(UNIT_ID_GEN.next())

@compiletime function initialize()
    if compiletime
        new UnitDefinition(UNIT_ID, 'hpea')
        ..setName("Other Peasant")
    else
        doOtherThing()

init
    initialize()

This means you can have one script, that runs your code ordinarily as you write it, as it would in other init blocks, but also generate object data that you can type inside the code. The code you just read creates a new unit in object data, called "Other Peasant", that is in every other way exactly like peasant (except having a different object Id).

While things like these were possible with vJass to some extent, it was never really handy, and the interaction between LUA and JASS was actually very poorly integrated.

If you just want to create ordinary, good old triggers, here's how you can do it in wurst, in a way that resembles how you'd do it in vJass or JASS:

JASS:
package SomePackage

function action()
    print("Hey, this building just started getting built!")

init
    let trig = CreateTrigger()
        ..registerAnyUnitEvent(EVENT_PLAYER_UNIT_CONSTRUCT_START)
        ..addAction(function action)

But wurst also allows you to do this, since it can use anonymous functions/closures:

JASS:
package SomePackage

init
    let trig = CreateTrigger()
        ..registerAnyUnitEvent(EVENT_PLAYER_UNIT_CONSTRUCT_START)
        ..addAction(() -> begin
            print("Hey, this building just started getting built!")
        end)

One of the biggest advantages of wurst is that it limits your ability as a programmer way less than other languages do, since it is a properly designed programming language. But also, if you're bad at programming or want to stick to wc3 ways a lot - you are allowed to do that. Not encouraged, as there are some differences, but wurst is way more limited by your abilities and knowledge, than it is by the language design.

Any code you write in wurst is going to be added to your map's existing code, meaning you can still have GUI triggers up, as well as ordinary jass, and then use wurst to add more code, but it is kind of hard to make them interact, one of the greatest strengths of wurst is that it uses a full integrated environment on its own which, along with it being a compiled language, can give you way more useful feedback while you're working.

This is a essentially a rundown on how the init block (the point at which wurst code STARTS interacting with your map) works as compared to jass and vJass. Making a new file in wurst (for this package called SomePackage.wurst) in your map project folder, will make it behave much like you'd expect a "trigger" from the WorldEditor (obviously I don't mean the trigger object, but the whole "script" as a trigger. If you have any other questions, feel free to ask. You can also look at the beginner's guide.
 
Last edited:
Awesome writeup! Super happy that you guys moved away from Eclipse. It was a lot of bloat to install for one portion of modding, and a little tricky to set up (at least when wurst first came out). The progress that you've all made on it is amaazing, seriously.

I'm really curious how this works for cross-platform now that you guys have your own java mpq lib. I'd be happy to be a guinea pig for mac. :) Gonna try this out as soon as I can!
 
Level 12
Joined
Mar 13, 2012
Messages
1,121
Just read the Wurst manual, really potent language.

Questions:
-Is a package like a combination of namespace and static class?
-Does switch only work on type int or more?
-I guess every class has a default constructor. When creating a new one the default one can hopefully no longer be accessed, right?


Here some nitpicking:
-Everything in package by default private vs everything in class by default public, seems inconsistent to me
-There are two ways to declare constant and settable fields ("constant"/"let" and "var"/nothing), a single way would be more clear
-"construct(...)" and "ondestroy", why not just MyClass(...) and ~MyClass()?
 
Just read the Wurst manual, really potent language.
It gets much better when you start using it, too!

-Is a package like a combination of namespace and static class?
They are a namespace. Packages can contain static classes, but they themselves aren't a static class. You can't write PackageName.something() if it is not public, and if it is public then you can access directly. If you want a custom namespace that allows you to call Something.someInternalThing() just make a static class.

You should think of package as a (pretty much) self-contained set of functionalities. Package can contain classes that share the namespace, yes, and using "protected" instead of "private" lets every class in the package access members directly. This means that if the implementation doesn't really need getters and setters (it has a lot of internal workings that you don't want people who import it to mess around with) you can use a class' attributes directly from the class which is in the same package. Read up on "public import" as well.

-Does switch only work on type int or more?

It works on string, int and enum.

-I guess every class has a default constructor.

It does.

When creating a new one the default one can hopefully no longer be accessed, right?

Exactly. Once your class has at least one implemented constructor, you can no longer access the default one. However, you can create a default constructor by just adding construct() to the class which is neat.

-Everything in package by default private vs everything in class by default public, seems inconsistent to me

Every top level element in the package is private by default. This means if you have constant THING = "STRING" in one package, and import that package into another one, you won't be able to access this constant. However if you have this:
JASS:
public class SomeClass
    int d // visible from anywhere if the class is public
    public int pub // wurst will tell you the public keyword is invalid - this is because it is, class members are public by default
    private int priv // only accessible from this class
    protected int prot // only accessible from this package and from classes that inherit this class

It's a matter of the logic behind this implementation - if the class itself is public, then so are its contents. Having to write private/protected all the time also makes sure that you don't forget to decide the visibility you are going for - for some things private is preferred but in general for most things protected is the way to go.

-There are two ways to declare constant and settable fields ("constant"/"let" and "var"/nothing), a single way would be more clear

Constant is supposed to be used for true, usually top level constants (either in the package or class), let is supposed to be used in function calls and higher level objects. That's just the writing style though, they are indeed the same thing. It just depends on what meaning you want to convey.

Also, "nothing" doesn't work, that'd result in a compilation error, are you referring to typed vs auto-typed variables? Because int x = 0 and var x = 0 are the same thing, however for most cases in wurst you want to use var something = value because then you don't have to write things like HashMap<player, unit> someMap = new HashMap<player, unit>() and instead you can just write let someMap = new HashMap<player, unit> // don't even need () if there are no arguments. Wurst does allow you to have your own stylistic preferences, in some cases the var keyword just makes the code look better and is faster to write.

-"construct(...)" and "ondestroy", why not just MyClass(...) and ~MyClass()?
Syntactic preference, I guess. Looks better and conveys more meaning this way, imo. My eyes are more easily drawn to keywords construct and ondestroy than they would be to ClassName and ~Classname.
 
Last edited:

Cokemonkey11

Code Reviewer
Level 29
Joined
May 9, 2006
Messages
3,522
Awesome writeup! Super happy that you guys moved away from Eclipse. It was a lot of bloat to install for one portion of modding, and a little tricky to set up (at least when wurst first came out). The progress that you've all made on it is amaazing, seriously

Thanks! Yes, that was also a pain point for me. To be fair, this was a time before the Language Server Protocol (which vscode and sublimetext use), so there wasn't a convenient end-to-end IDE experience that was this lightweight.

IMO wurstscript is a fantastic example of the power of LSP.

I'm really curious how this works for cross-platform now that you guys have your own java mpq lib. I'd be happy to be a guinea pig for mac. :) Gonna try this out as soon as I can!

JMPQ works great but of course there can be bugs. We look forward to your reports, yes. There could also be surprises related to OSX file paths and conventions, so we're looking forward to it. Would be quite cool to "support OSX".
 
Level 15
Joined
Aug 7, 2013
Messages
1,337
Unles you've made some deep-seeded framework in vJass, I would encourage you to try working with wurst and vjass at the same time. I also have some experience translating vJass maps to jurst and later wurst.

Could you elaborate? I did develop some custom Event/Quest/Boss libraries for a project in vJASS (like I'm sure everyone here has).

Is there some functionality that can't be replaced with Wurst? Why do you recommend working with both, rather than me switching to Wurst?
 
Could you elaborate? I did develop some custom Event/Quest/Boss libraries for a project in vJASS (like I'm sure everyone here has).

Is there some functionality that can't be replaced with Wurst? Why do you recommend working with both, rather than me switching to Wurst?

He probably meant that if the implementation is deeply connected to how vJass works, it will be harder to translate the code to jurst/wurst. That being said, everything except ExecuteFunc can be used in wurst, but wurst has a developed closure/anonymous function system so you never even need ExecuteFunc.
 

Cokemonkey11

Code Reviewer
Level 29
Joined
May 9, 2006
Messages
3,522
Actually what I meant was something like:

If your game design is strongly reliant on some framework written in vjass then it might be difficult to write new function in wurst (because it's not encouraged to call vjass function from wurst)

On the other points:

* Why not just translate vjass to wurst?

No reason why not - that's what I usually do (but it can be hard to convince someone if it's your first wurst experience)

* Is there something vjass can do that wurst cannot?

There are some weird features of vjass like hook but otherwise no.

* Is some stuff difficult to translate?

No, nothing in my experience. In practice my preference has always been to translate to jurst and then later to wurst.

Again, just to be clear: my original point was that you really shouldn't need to wait for a new project if you just want to give wurst a try
 
Status
Not open for further replies.
Top