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

[General] Triggers stop firing mid-game (TypeScript project)

Status
Not open for further replies.
Level 2
Joined
Mar 31, 2023
Messages
4
Hello, first time posting a question here so forgive me if this isn't the right place. I'm currently learning WC3 modding, and have a TypeScript project setup with
w3ts. My project is in its very early stages, so there isn't a whole lot going on. The code is working for the most part, however one of my triggers appears to stop working mid-game.

Here's the relevant snippet:
TypeScript:
import { Trigger } from 'w3ts';

// In the Warcraft III Editor I've placed player 24 in a separate force to the players
export const AI_PLAYER = MapPlayer.fromHandle(Player(23));

// This function is imported in a `main.ts` file and executed immediately in global scope
export function createOnKillTrigger() {
  const onKillTrigger = new Trigger();
  onKillTrigger.registerPlayerUnitEvent(AI_PLAYER, EVENT_PLAYER_UNIT_DEATH, () => true);
  onKillTrigger.addAction(() => onKillAction());
}

// Simply echo to all players that a unit owned by player 24 has died
function onKillAction() {
  print('kill');
}

The expected behavior is that whenever a unit owned by player 24 dies, the word "kill" is written to chat. This has not been the case for me, instead what I'm observing is that the first 1-3 kills are correctly noted, and then... The message just stops appearing. Elsewhere in my project I'm spawning enemy units in a more involved function, but the relevant lines can be seen here:

TypeScript:
// The `spawnLocation` and `playerUnitLocation` variables are valid locations, since the units spawn successfully

const group = new Group();

for (let i = 0; i < unitCount; i++) {
  const enemyUnit = new Unit(AI_PLAYER, FourCC('h000'), GetLocationX(spawnLocation), GetLocationY(spawnLocation), 0);
  enemyUnit.setFacingEx(AngleBetweenPoints(spawnLocation, playerUnitLocation));
  group.addUnit(enemyUnit);
}

group.orderTarget(OrderId.Attack, playerUnit);

The above code runs on an interval, and it is correctly working. I'm not sure why my trigger suddenly just stops firing. There isn't much else going on in this project, this is the only actual trigger. Any hints or suggestions would be greatly appreciated. I'm wondering if the generated boilerplate of w3ts is just too much for WC3? I don't know how anyone is supposed to use the library in that case, but if that is so, then I'll most likely switch to using Lua or JASS directly.
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,553
I'm no expert on the subject but it sounds like a garbage collection issue. I know with Lua you'll run into issues if you don't use something like this:
 
Level 2
Joined
Mar 31, 2023
Messages
4
I wonder the same thing, but it seems unlikely... But being that I'm new to WC3 modding I couldn't say for sure. The first code snippet in my post is two functions, and the second snippet actually does exist in a function, there are just other things in that function that aren't related, so I didn't feel it was necessary to post the whole thing just for the sake of clarity.

For the sake of thoroughness, I've uploaded the entirety of my project to GitHub. Here's a direct link to the file containing the unit death trigger:
wc3-first-ts-map/on-kill.ts at master · christopherwk210/wc3-first-ts-map
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,553
I think it's very likely as others have experienced similar issues with the same outcome.

For example, this looks like it will get garbage collected:
TypeScript:
let timeToNextSpawn = 10;
This particular case shouldn't break anything since it's only needed during the initial timer creation, but I would try to avoid that.
 
Level 2
Joined
Mar 31, 2023
Messages
4
Okay so after doing a lot of reading, I believe I've solved it. I had to move my code that actually creates the triggers into a place that hooks into the map loading, as seen here:

TypeScript:
addScriptHook(W3TS_HOOK.MAIN_AFTER, () => {
  new Timer().start(2, false, () => {
    main();
    setSpawnEnemyLoop();
    createOnKillTrigger();
  });
});

I can't say for sure that I know why this has fixed my issue, but I'm sure it has to do with triggers being set up before the map has finished initializing.

To address your concern, the timeToNextSpawn variable doesn't seem to be being garbage collected, at least for right now. After making the mentioned change, I let the game run for about 5 minutes and things seemed to continue without issue. I will pay close attention to handling variables though, now knowing that the garbage collector is a thing that requires specific attention.
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,553
Okay so after doing a lot of reading, I believe I've solved it. I had to move my code that actually creates the triggers into a place that hooks into the map loading, as seen here:

TypeScript:
addScriptHook(W3TS_HOOK.MAIN_AFTER, () => {
  new Timer().start(2, false, () => {
    main();
    setSpawnEnemyLoop();
    createOnKillTrigger();
  });
});

I can't say for sure that I know why this has fixed my issue, but I'm sure it has to do with triggers being set up before the map has finished initializing.

To address your concern, the timeToNextSpawn variable doesn't seem to be being garbage collected, at least for right now. After making the mentioned change, I let the game run for about 5 minutes and things seemed to continue without issue. I will pay close attention to handling variables though, now knowing that the garbage collector is a thing that requires specific attention.
Nice. I know when I was messing with Lua I ran into all sorts of problems which went away after I started using Total Initialization. Running things later in the initialization process seems to do the trick.
 
Status
Not open for further replies.
Top