Question on "name=unit placed" events

The place to post your WML questions and answers.

Moderator: Forum Moderators

Forum rules
  • Please use [code] BBCode tags in your posts for embedding WML snippets.
  • To keep your code readable so that others can easily help you, make sure to indent it following our conventions.
Post Reply
User avatar
Limabean
Posts: 369
Joined: August 26th, 2008, 2:14 pm
Location: New Hampshire, USA

Question on "name=unit placed" events

Post by Limabean »

I ran into a strange bug related to a "name=unit placed" event, and I could use some help understanding it. To give some context, I have a scenario where a player (side=1) controls a large number of walking corpses. At the end of the player's turn, any WCs that haven't moved have their side switched to an AI (side=2). The AI then moves them, and gives control back to the player at the end of its turn. I use a "unit placed" event to make sure any WCs created by plague while the AI is in control are immediately given back to the player.

Now for the bug: it seems like AFTER "side turn" and "turn refresh" for the AI's turn, the WCs are deleted and re-placed, which triggers the "unit placed" event. I am pretty confident that none of my custom events are doing this deletion. So, I'm wondering if there is any internal Wesnoth mechanism that might explain it? At first, I thought maybe they were being stored/unstored as part of the 'resting' mechanic. But then I realized that this was happening after "turn refresh", so that doesn't make sense.

I've attached a save if you want to see for yourself. Just load it and end turn immediately. You'll get a bunch of debug message for each step in this process.
Attachments
2p - Monster Hunt Turn 4 DEBUGGING.gz
(123.07 KiB) Downloaded 41 times
User avatar
Ravana
Forum Moderator
Posts: 3015
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: Question on "name=unit placed" events

Post by Ravana »

I am not going to download this file, but description sounds like unit id conflict.

Note that even if that is not the case, unit placed it allowed to trigger any time and it is your responsibility to filter if it should do something or not.
User avatar
Limabean
Posts: 369
Joined: August 26th, 2008, 2:14 pm
Location: New Hampshire, USA

Re: Question on "name=unit placed" events

Post by Limabean »

Ravana wrote: March 17th, 2024, 11:17 am I am not going to download this file, but description sounds like unit id conflict.

Note that even if that is not the case, unit placed it allowed to trigger any time and it is your responsibility to filter if it should do something or not.
None of the walking corpses have been given an id. I understand that I can control the event with a filter, and I have "solved" my current bug by doing just that. But the fact that this was an issue in the first place still does not make sense to me, and I'm trying to understand it better so I don't have issues with future bugs.

To better illustrate my point: I have removed ALL but 5 [event]s from the attached save. I have also simplified these 5 events as much as possible. The only actual action performed by any of these events is to display a [message] and change unit sides using [modify_unit]. The units are being deleted/re-placed after turn refresh, but before the AI makes any move. None of the 5 events match this timing. So like I said, I'm pretty confident I didn't write any WML that is deleting these units. I'm just trying to figure out what could be responsible.

Code: Select all

	[event]
		first_time_only=no
		name="side_turn"
		
		[message]
		speaker=narrator
		message="TESTING START TURN"
		[/message]

	[/event]
	[event]
		first_time_only=no
		name="turn_refresh"
		
		[message]
		speaker=narrator
		message="TESTING TURN REFRESH"
		[/message]
	[/event]

	[event]
		first_time_only=no
		name="side_turn_end"
		
		[if]
			[variable]
				equals="1"
				name="side_number"
			[/variable]
			[then]

			[message]
			speaker=narrator
			message="GIVE WALKING CORPSES TO AI..."
			[/message]

			[modify_unit]
				side="2"
				[filter]
					type=Walking Corpse
					side=1
				[/filter]
			[/modify_unit]

			[/then]
		[/if]
	[/event]
	[event]
		first_time_only=no
		name="side_turn_end"

		[if]
			[variable]
				equals="2"
				name="side_number"
			[/variable]
			[then]

			[message]
			speaker=narrator
			message="GIVE WALKING CORPSES BACK TO PLAYER..."
			[/message]

			[modify_unit]
				side="1"
				[filter]
					type=Walking Corpse
					side=2
				[/filter]
			[/modify_unit]

			[/then]
		[/if]
	[/event]
	[event]
		first_time_only=no
		name="unit_placed"
		[if]
			[variable]
				equals="2"
				name="unit.side"
			[/variable]
			[and]
				[variable]
					name="unit.canrecruit"
					not_equals=yes
				[/variable]
			[/and]
			[then]

				[message]
				speaker=narrator
				message="UNIT_PLACED EVENT TRIGGERED"
				[/message]

				[modify_unit]
					side="1"
					[filter]
						x="$x1"
						y="$y1"
					[/filter]
				[/modify_unit]
			[/then]
		[/if]
	[/event]
Like I said before, if you want to see for yourself, just load the attached save and end turn.
Attachments
2p - Monster Hunt Turn 4 DEBUGGING.gz
(83.67 KiB) Downloaded 37 times
User avatar
Ravana
Forum Moderator
Posts: 3015
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: Question on "name=unit placed" events

Post by Ravana »

You can simplify side_turn_end to side_1_turn_end, side_2_turn_end.
gnombat
Posts: 710
Joined: June 10th, 2010, 8:49 pm

Re: Question on "name=unit placed" events

Post by gnombat »

Are you sure that unit_placed isn't firing when you give the units to the AI side? (So that they end up being given back immediately.)

Also, are you sure that you even need unit_placed for this at all? I notice that the documentation for unit_placed says, "This event is solely intended for special cases where no other event types suffice..." So it sounds like they are recommending that it be avoided if possible and used only as a last resort. I'm not sure why the documentation recommends this - possibly it is because the event is tricky to use, or perhaps because it is genuinely buggy in some cases. Wouldn't it be possible to avoid using unit_placed by simply transferring all the AI units (including those that were created by plague) at the end of the AI's turn?
User avatar
Ravana
Forum Moderator
Posts: 3015
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: Question on "name=unit placed" events

Post by Ravana »

It is probably just matter of timing, whether attack_end triggers too soon to transfer them.

Changing side at turn end removes chance from AI to kill the corpses.
User avatar
Limabean
Posts: 369
Joined: August 26th, 2008, 2:14 pm
Location: New Hampshire, USA

Re: Question on "name=unit placed" events

Post by Limabean »

Ravana wrote: March 17th, 2024, 6:39 pm You can simplify side_turn_end to side_1_turn_end, side_2_turn_end.
True, but I don't think that explains the deletion of the units.
gnombat wrote: March 17th, 2024, 8:02 pm Are you sure that unit_placed isn't firing when you give the units to the AI side? (So that they end up being given back immediately.)
Yes, I'm quite sure. Using the debug statements I can watch each step of the process. At the end of the side 1 turn, I can see all the corpses switch to side 2. Then, at the start of the side 2 turn it pauses with another debug message and nothing changes. Then, I can watch 'resting' zombies get 2 healing, followed by the debug message at side 2 refresh. All the zombies are still on the map with side=2 at this point. AFTER the refresh event, all the zombies disappear from the map and are placed again (still side=2), one at a time. This triggers the "unit_placed" event each time, which I can watch using a debug message.
gnombat wrote: March 17th, 2024, 8:02 pm Also, are you sure that you even need unit_placed for this at all? I notice that the documentation for unit_placed says, "This event is solely intended for special cases where no other event types suffice..." So it sounds like they are recommending that it be avoided if possible and used only as a last resort. I'm not sure why the documentation recommends this - possibly it is because the event is tricky to use, or perhaps because it is genuinely buggy in some cases. Wouldn't it be possible to avoid using unit_placed by simply transferring all the AI units (including those that were created by plague) at the end of the AI's turn?
You're right, I don't actually need to use unit_placed, although the real scenario is a little more complicated than this example so I can't just modify side for every zombie at the end of the turn. I switched to using unit_placed because it simplified things. I'll note that despite the warning on the wiki, there is no indication that unit_placed itself is misbehaving. Units are in fact being placed, and it is triggering exactly as I would expect. The mystery is why those units are deleted/re-placed after turn refresh and without any obvious events to cause it.
Ravana wrote: March 17th, 2024, 8:23 pm It is probably just matter of timing, whether attack_end triggers too soon to transfer them.

Changing side at turn end removes chance from AI to kill the corpses.
I don't think it is a timing issue, as there are several events between when the zombies change sides, and when they disappear. I'm not sure what you mean re: attack_end?
User avatar
beetlenaut
Developer
Posts: 2827
Joined: December 8th, 2007, 3:21 am
Location: Washington State
Contact:

Re: Question on "name=unit placed" events

Post by beetlenaut »

Limabean wrote: March 17th, 2024, 11:20 pm AFTER the refresh event, all the zombies disappear from the map and are placed again
I tried it, and I see what you mean. There is nothing in the code you showed us that could cause this problem though. I even tried these events in one of my scenarios to make sure there wasn't some sort of engine bug, and apparently there wasn't. They worked as expected, and no units got deleted. The problem is in another part of your code. If you zip up and post the whole add-on, I'm pretty sure someone will find it.
Campaigns: Dead Water,
The Founding of Borstep,
Secrets of the Ancients,
and WML Guide
User avatar
Limabean
Posts: 369
Joined: August 26th, 2008, 2:14 pm
Location: New Hampshire, USA

Re: Question on "name=unit placed" events

Post by Limabean »

beetlenaut wrote: March 18th, 2024, 5:07 pm
Limabean wrote: March 17th, 2024, 11:20 pm AFTER the refresh event, all the zombies disappear from the map and are placed again
I tried it, and I see what you mean. There is nothing in the code you showed us that could cause this problem though. I even tried these events in one of my scenarios to make sure there wasn't some sort of engine bug, and apparently there wasn't. They worked as expected, and no units got deleted. The problem is in another part of your code. If you zip up and post the whole add-on, I'm pretty sure someone will find it.
I've attached the entire scenario if you're curious, but I really don't want anyone to waste their time digging through it. It may be an issue in my code, but in the previously attached save I went and manually removed every single [event] except the 5 I posted in this thread. So if this unit deletion isn't happening in an event, what other tags should I be suspicious of? I also went and deleted all the menus from the attached save, since there's some logic there even if I wouldn't expect it to be executed. At this point, the save seems to be entirely map, side definitions, some default AI candidate actions, and a whole lot of units and variables. But no logic actually using those variables. Just those 5 harmless events.
Attachments
2p - Monster Hunt Turn 4 DEBUGGING.gz
(66.75 KiB) Downloaded 25 times
monster_hunt.zip
(37.96 KiB) Downloaded 22 times
gnombat
Posts: 710
Joined: June 10th, 2010, 8:49 pm

Re: Question on "name=unit placed" events

Post by gnombat »

Limabean wrote: March 17th, 2024, 4:00 am it seems like AFTER "side turn" and "turn refresh" for the AI's turn, the WCs are deleted and re-placed, which triggers the "unit placed" event. I am pretty confident that none of my custom events are doing this deletion. So, I'm wondering if there is any internal Wesnoth mechanism that might explain it?
Upon testing this, it looks like it is in fact an internal Wesnoth mechanism triggering these events: the AI itself seems to be doing it (meaning the code which controls the AI).

The code is in data/ai/lua/battle_calcs.lua - see the comments in lines 1170, 1171, and 1186.

An easy way to reproduce this is:
  1. Add the following code to any scenario in any campaign (I used the first scenario of the WML Guide campaign, but I would guess pretty much any campaign/scenario would work).

    Code: Select all

    [event]
        name=unit_placed
        first_time_only=no
        [lua]
            code = <<
                wesnoth.message(debug.traceback())
            >>
        [/lua]
        [message]
            speaker=narrator
            message="unit_placed $unit.id $unit.x $unit.y"
        [/message]
    [/event]
    
  2. Play a few turns until a battle starts and some AI units are wounded. Then observe what happens on the AI's turn.
User avatar
beetlenaut
Developer
Posts: 2827
Joined: December 8th, 2007, 3:21 am
Location: Washington State
Contact:

Re: Question on "name=unit placed" events

Post by beetlenaut »

So part of the internal AI calculations removes a bunch of units for a millisecond, then puts them right back. I don't think unit_placed events should be triggered by that code. They will be triggered constantly at a time nobody expects. (See: this thread.) I would even say this is a bug, so it could be fixed before 1.18 is final.
Campaigns: Dead Water,
The Founding of Borstep,
Secrets of the Ancients,
and WML Guide
gnombat
Posts: 710
Joined: June 10th, 2010, 8:49 pm

Re: Question on "name=unit placed" events

Post by gnombat »

Well, 1.18.0 has been tagged already, so I doubt the bug is going to be fixed before the release. (Maybe it could be fixed in 1.18.1 or a later bugfix release.)

I guess the safest thing is to do what Ravana suggested and just assume that the unit_placed event can trigger at any time, for any reason at all (or no apparent reason at all).
User avatar
Ravana
Forum Moderator
Posts: 3015
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: Question on "name=unit placed" events

Post by Ravana »

Lua is taken from local file, it is not sent over network unless wrapped in [lua]. It is probably oos to change this behaviour in 1.18 when something reacts to unit placed.
User avatar
Limabean
Posts: 369
Joined: August 26th, 2008, 2:14 pm
Location: New Hampshire, USA

Re: Question on "name=unit placed" events

Post by Limabean »

gnombat wrote: March 19th, 2024, 4:35 am
Limabean wrote: March 17th, 2024, 4:00 am it seems like AFTER "side turn" and "turn refresh" for the AI's turn, the WCs are deleted and re-placed, which triggers the "unit placed" event. I am pretty confident that none of my custom events are doing this deletion. So, I'm wondering if there is any internal Wesnoth mechanism that might explain it?
Upon testing this, it looks like it is in fact an internal Wesnoth mechanism triggering these events: the AI itself seems to be doing it (meaning the code which controls the AI).

The code is in data/ai/lua/battle_calcs.lua - see the comments in lines 1170, 1171, and 1186.

An easy way to reproduce this is:
  1. Add the following code to any scenario in any campaign (I used the first scenario of the WML Guide campaign, but I would guess pretty much any campaign/scenario would work).

    Code: Select all

    [event]
        name=unit_placed
        first_time_only=no
        [lua]
            code = <<
                wesnoth.message(debug.traceback())
            >>
        [/lua]
        [message]
            speaker=narrator
            message="unit_placed $unit.id $unit.x $unit.y"
        [/message]
    [/event]
    
  2. Play a few turns until a battle starts and some AI units are wounded. Then observe what happens on the AI's turn.
Wow, that is awesome, thanks for taking the time to check this out. It was driving me crazy.
Post Reply