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

[Wurst] How can I debug Wurst code most effectively?

Status
Not open for further replies.
Level 4
Joined
Aug 14, 2005
Messages
49
Hi everyone

I was wondering: How can I effectively debug Wurst code? Obviously, it's always possible to use print(...) statements to put some variable values on the screen, and even though it works, it's cumbersome and inefficient. Moreover, there are some bugs which I can't fix like this.

Right now, I am fighting with trying to make a closure work (with a functional interface, see this last post of minehttps://www.hiveworkshop.com/threads/how-can-i-accomplish-hashmap-item-function.305409/ )
But, unfortunately, I am getting a NULL pointer exception and even after staring at the code and tinkering around for an hour, I don't know what I'm doing wrong.

At the same time, I don't want to annoy the maintainers of Wurst or the members of this forum every time I run into a small problem. Hence my desire to debug this myself. I've searched Google, the forums and the manual, but I can't find any mention on how I could attack a problem like this. (Full disclaimer: I'm not a VSCode guru, so if there already is an option there that I overlooked in my search, I apologize).
 

Jampion

Code Reviewer
Level 15
Joined
Mar 25, 2016
Messages
1,327
Wurst usually tells you at what line the problem occurs, including a stack trace.
In that line you just check which objects are used and that should give you an idea what could be null.

Furthermore you can search in the compiled map script for the error message. That will tell where exactly in the map script the problem occurs.

If you know which variable is null, it should be quite easy to fix the problem.

Make sure that the hashmap itself is not null. Keep in mind, that by using initlater, variables are initialized later, so they will not yet be accesible in the other package during the init phase.
 
Level 4
Joined
Aug 14, 2005
Messages
49
Hi there, Jampion. Thank you for again taking the time to reply.

Unfortunately, I can't use your advice this time. The error doesn't occur in Wurst, unfortunately, but only when I actually run my map. Wurst doesn't seem to be telling me anything (or if so, I don't know where to look).
When I run the map and get to the place of the code that causes the problem, the game throws the following message at me:

error - Error: Nullpointer exception when calling On_string_enter.GlobalSystems_On_string_enter_on_string_enter

I will post my code here below. It uses the idea you told me last time, except this time for chat strings. This particular system will be deleted in the final version and is only there to allow me to do fast testing on the map. This includes things like giving me gold, lumber, spawn items, that sort of stuff. Since we discussed functional interfaces and closures, I decided to give it a try with this. It's probably not well written, but I was hoping it would do the job for now.

Wurst:
let debug_commands = new HashMap<string, On_string_enter>()

function fillHashMap()
    debug_commands.put("-give gold ", (pl, str, arg_s, arg_e) -> begin
        pl.addGold(S2I(str.substring(arg_s, arg_e)))
    end)

function debug_commands()
    let entered_command = GetEventPlayerChatString()
    if not entered_command.startsWith("-")
        return
    let triggering_player = GetTriggerPlayer()
    int argument_start = entered_command.indexOf("(")
    int argument_end = -1
    int command_length = entered_command.length()
    if argument_start >=0
        command_length = argument_start
        argument_end = entered_command.indexOf(")")
    let hashmap_key = entered_command.substring(0, command_length)
    if debug_commands.has(hashmap_key)
        debug_commands.get(entered_command).on_string_enter(
            triggering_player,entered_command, argument_start+1, argument_end)
      
init
    fillHashMap()
    doAfter(0.05) ->
        let trig = CreateTrigger()
        for i = 0 to bj_MAX_PLAYER_SLOTS
            trig.registerPlayerChatEvent(players[i], "-", false)
        trig.addAction(function debug_commands)

Now, I know for a fact that the "if debug_commands.has(hashmap_key) is executed. The error occurs when trying to call the actual function. I'm quite sure that I am doing something insanely stupid, but I can't see it. If you see this or something else that is wrong, inefficient or badly written in the code, I'd also be glad to know.

All this said, I'm still wondering: How could I debug problems like these or find the right answer without asking on the forums each time?

Thanks and kind regards
 
Last edited by a moderator:

Jampion

Code Reviewer
Level 15
Joined
Mar 25, 2016
Messages
1,327
You use hashmap.has on hashmap_key
but hashmap.get on entered_command
So you lookup in the hashmap for a string including the arguments, which is not there and you want to execute it.

You should have a file compiled.j.txt in your _build directory.
Open it in vscode and search for "Nullpointer exception when calling On_string_enter.GlobalSystems_On_string_enter_on_string_enter"
without "".
It should give you only one match. Here you need to inspect the conditions under which this message is printed.
There will be a comparison of an array and the name of this array will give you an idea which object is null.

This file contains the jass code, so you can always use it to debug your map. This is what the game uses.

You should change let debug_commands ... to constant debug_commands ...
let and var are for local variables, constant is for global variables
I am not sure if this is mandatory, but I think this is the intended usage of those keywords.
 
Level 4
Joined
Aug 14, 2005
Messages
49
Oh my good grief, I am an idiot.
Again, thank you so much. The system works absolutely beautifully now. I cannot begin to describe how much easier this makes spells, items and units that require special scripting treatment.

Thanks also for the guidance on compiled.j.txt - This will surely prove useful in the future if I get any additional problems.

And of course thanks for the hint about constant vs let/var. I wasn't aware of this difference.
 
Status
Not open for further replies.
Top