• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

New and have a problem:

Status
Not open for further replies.
Hey all,

I've got a major issue with my map. The map is a diplomacy type that uses a naval system I developed, a few custom models and my team and I made, a dialog UI and as of right now:

Abilities: 47
Actors: 524
Behaviors: 107
Buttons: 144
Effects: 195
Footprints: 10
Movers: 9
Requirements: 156
Turrets: 38
Units: 99
Upgrades: 75
Validators: 31
Weapons: 92

I hope the point got across that I've put a lot of work into this.

Ok now for the issue: I'm a data guy not so much a trigger guy. Right now I'm trying to re-implement an AI system for my diplomacy map.

The idea behind it is if you invade a neutral nation it will build units and fight you.

The map has 7 human players and 7 computer players. There is 1 computer player assigned to each human (ie 1-8, 2-9 etc) and that computer remains neutral to other humans unless attacked.

So whats my problem?

Well I had it working somewhat before. It would sparadically fail or work for a while and then fail but right now it isn't working at all.

Here is the relevant code as of right now:

Action Def: AI_SetPlayerAI
  • AI_SetPlayerAI
    • Options: Action, Create Thread
    • Return Type: (None)
    • Parameters
      • PlayerID = 0 <Integer>
    • Grammar Text: AI_SetPlayerAI(PlayerID)
    • Hint Text: (None)
    • Custom Script Code
    • Local Variables
      • tempwhilecheat = 0 <Integer>
    • Actions
      • UI - Display "SetPlayerAI Fired" for (All players) to Chat area
      • AI - Start the campaign AI for player PlayerID
      • AI Advanced - Set the APM count for player PlayerID to 300
      • Player - Modify player PlayerID Minerals: Add 999999
      • AI_Research(PlayerID)
      • AI_OrderScuicide(PlayerID)
      • AI Advanced - Make 5 objects of type "Rifleman" in player PlayerID's town -1 with priority 5, even if they exist already
      • AI Advanced - Make 2 objects of type (String(Machine Gunner)) in player PlayerID's town -1 with priority 5, even if they exist already
      • AI Advanced - Make 1 objects of type (String(AT Gun (Flatbed, Construction))) in player PlayerID's town -1 with priority 5, even if they exist already
      • AI Advanced - Make 1 objects of type (String(Howitzer (Flatbed, Construction))) in player PlayerID's town -1 with priority 5, even if they exist already
      • AI Advanced - Make 1 objects of type (String(Light Tank (Tank Mode))) in player PlayerID's town -1 with priority 5, even if they exist already
      • AI Advanced - Make 1 objects of type (String(Infantry Tank (Tank Mode))) in player PlayerID's town -1 with priority 5, even if they exist already
      • UI - Display ("AI Minerals: " + (Text((Player PlayerID Minerals)))) for (All players) to Chat area
      • UI - Display ("AI Supply made: " + (Text((Player PlayerID Supplies Made)))) for (All players) to Chat area
      • UI - Display ("AI Supply limit: " + (Text((Player PlayerID Supplies Limit)))) for (All players) to Chat area
Then Action Def: AI_OrderScuicide

  • AI_OrderScuicide
    • Options: Action, Create Thread
    • Return Type: (None)
    • Parameters
      • PlayerID = 0 <Integer>
    • Grammar Text: AI_OrderScuicide(PlayerID)
    • Hint Text: (None)
    • Custom Script Code
    • Local Variables
      • tempInt = 0 <Integer>
      • tempWhileTrick = 0 <Integer>
    • Actions
      • General - While (Conditions) are true, do (Actions)
        • Conditions
          • tempWhileTrick == 0
        • Actions
          • AI Advanced - Make 5 objects of type (String(Rifleman)) in player PlayerID's town -1 with priority 5, even if they exist already
          • AI Advanced - Make 2 objects of type (String(Machine Gunner)) in player PlayerID's town -1 with priority 5, even if they exist already
          • AI Advanced - Make 1 objects of type (String(AT Gun (Flatbed, Construction))) in player PlayerID's town -1 with priority 5, even if they exist already
          • AI Advanced - Make 1 objects of type (String(Howitzer (Flatbed, Construction))) in player PlayerID's town -1 with priority 5, even if they exist already
          • AI Advanced - Make 1 objects of type (String(Light Tank (Tank Mode))) in player PlayerID's town -1 with priority 5, even if they exist already
          • AI Advanced - Make 1 objects of type (String(Infantry Tank (Tank Mode))) in player PlayerID's town -1 with priority 5, even if they exist already
          • AI Advanced - Train 7 units of type Rifleman in player PlayerID's town -1 with priority 5
          • AI Advanced - Train 3 units of type Machine Gunner in player PlayerID's town -1 with priority 5
          • AI Advanced - Train 1 units of type AT Gun (Flatbed, Construction) in player PlayerID's town -1 with priority 5
          • AI Advanced - Train 1 units of type Howitzer (Flatbed, Construction) in player PlayerID's town -1 with priority 5
          • AI Advanced - Train 1 units of type Light Tank (Tank Mode) in player PlayerID's town -1 with priority 5
          • AI Advanced - Train 1 units of type Infantry Tank (Tank Mode) in player PlayerID's town -1 with priority 5
          • AI Advanced - Train 2 units of type Armored Car in player PlayerID's town -1 with priority 5
          • AI - Enable suicide for (Idle Units for player PlayerID)
          • General - Wait 5.0 Game Time seconds
I have both methods of forcing the AI to build units listed.


Anyways once the game starts and the game has confirmed there is a player for that AI, 5 seconds later it will start the AI. I know from exp that starting an AI is not limited to the map int in SC2. AI can be started inside action defs.

Now I'm at the end of my rope here and the only thing I can think of is that "Priority 5" part. Priority 5 worked before but I still don't even know what that is.

Now a dig into the MPQ's also didn't give me any enlightenment on this issue either.

So... ya... kinda in a bind here. I can't see what I'm doing wrong I just know something is wrong lol.

Can I get some help here?

And yes I will answer a few other posts to encourage myself getting some help :)

Edit: Well I just helped 5 others who hadn't had their problems solved yet so I hope I can get some help with mine :)

Thanks!
 
Last edited:

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,255
What triggers fire these? Why must they run in a separate thread?

Do make sure that the player is an Computer player. Empty slots and human players cannot have an AI started for them.

AI is a rather tricky and difficult area of triggering. It could even be some internal problem with the Campaign AI you are using that makes it depend on SC2 melee units rather than generic units.

The best approach would be to have the map so we can try out various solutions. If that is not possible atleast an example extract of the map that recreates the problem.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,255
I was looking in game for buildings that they own and could not find any after conquering most of Europe. I am trying to understand where the AI is meant to be working from and where their units come from before I start touching the AI itself.

That said, I will try again later.
 
Sorry for double post.

Umm... Just an FYI... In SC2 you don't tell the AI where it make it's units. Just you tell it what units to make and it will find it by itself. It will even find custom units.

Sorry for posting again.

The AI buildings are on the "creep" of each nation.

They are the infantry HQ, support HQ and armor HQ. Each of those buildings you can make and many are already pre-placed on the map. The AI can only build from these pre-placed buildings. Its not supposed to be a smart AI.

Second of all when you attack an AI it should swap any player 15 units in that nation over to the appropriate AI player. So for local testing it would be player 8 "Player 1 AI".

The reason I can't use one AI is that we've had cases of a person agroing 4 nations around him and then leaving when he got owned. After that a huge stream of units would come towards us and flay us alive.
 
Last edited by a moderator:

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,255
So let me get this straight. The AI is owned by a player but when you attack them all the nation you attacked gets transferred to another dummy AI that is named "Player 1" so that when they attack they will not coordinate with other AI nations? Ok I will look into the problem.

The reason I can't use one AI is that we've had cases of a person agroing 4 nations around him and then leaving when he got owned. After that a huge stream of units would come towards us and flay us alive.
That sounds kind of fun. Comp Stomp!!!

EDIT

Found and fixed a fault with the AI system.

You used a condition "(Enemies of player DefendingUnitPlayerID) != (Player group(AttackingUnitPlayerID))"
This always returns true as they are 2 unique player groups. Changed to check if the attacking owner is not in the player group of enemies of the defending player.

Still looking and understanding how it opperates.

EDIT 2

Sorry but it is still not fixed. I had to do some AI tests to get the hang of the StarCraft II AI system. I think I understand it now and hopefully will have results later.

EDIT 3

The AI is working perfectly, just the AI players have no units to build. If you look at it from the AI perspective you will see that there are no units to train in their structures.

The obvious cause for this is your strange unit swap system. I will look into it now.
 
Last edited:
I will definatly be damned.

You were right.

I added a extra action defintion that set the upgrades for the AI to the defaults and it worked.

Holy shit thanks a bunch you have no idea how much of a headache this has been for me!

Well I think its fair to say I will contribute to this site to the best of my ability.

Although I will do so in any cause, I have a few other issues that need some fixing if you can spare the time.

Before that:
1. I am aware the map needs to be retriggered.

Now that that part is over with I have the following questions:

1. If you look at all of the naval ships you will notice that the attack animation (muzzel flash of the cannons which I removed) only comes from the center unit of the naval warships, no matter if I custom modeled it or not. Can you please help me fix this?

2. The Diplomacy system has a bug in the beginning of the game. The first few requests to accept an alliance or another offer will fail. After that it works fine.

3. The city capture system is not always working. I know the map has a huge lag load but for some reason either the city won't capture, or the shipyard along with it won't capture. Can you help me code that part more efficiently?

After that:

Do you have a guides section for StarCraft 2? I hope you do cause the shit I'm about to contribute will make a huge difference to HiveWorkShop. I've made StarCraft 2 bend in ways few people have :) NVM I'm blind.

Just a little FYI Dr Super Good.

You will need to wrap your head around a little issue with StarCraft 2.

Trigger initilization is a *major* source of lag for battle.net. Almost nothing in the triggers compair to the lag causes by this. I know I made a 3rd person movement/shooter system one time.

The only real solution is to do everything in triggers already running. It is more efficient and will result in less lag to do an infinate while loop inside a trigger than to use the periodic event.

What "Create Thread" does it makes it so the trigger can do mulitple things at once. This has proven to be more efficient than having tons of triggers.

So essentially: the fewer the triggers the better.
 
Last edited by a moderator:

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,255
What "Create Thread" does it makes it so the trigger can do mulitple things at once. This has proven to be more efficient than having tons of triggers.
You are aware it makes and runs another trigger right? Look at the Galaxy source code it compiles to.

When the action is invoked it calls a function which then orders a trigger to execute. The executed trigger then runs the body of the action. Parameters are passed via globals and copied into locals. There is no way this is more efficient than running the code directly in the calling thread.

Also trigger threads are not real operating system threads. They cannot be executed in parallel and instead are executed in some order. There is no pre-emption of trigger threads and waiting inside a thread will cause the thread to be rescheduled at a later time. It is best to keep the number of threads down to a minimum because creating new threads adds a lot of overhead.

The only real solution is to do everything in triggers already running. It is more efficient and will result in less lag to do an infinate while loop inside a trigger than to use the periodic event.
That is true. Resuming a thread from a wait should be much faster than creating a new thread from an event (if it is anything like the real operating system threads I am used to programming with). There are some problems with this sort of thread though.
1. Thread crashes are critical. If the thread was to crash due to a fault it will never get started again which could result in a session being unable to progress.
2. More difficult to control. Sometimes it might be needed to pause something periodic which is much harder to do with a running thread.
3. Active threads are a limited resource. You can only have a few hundred active threads at any time before the game starts refusing the creating of new threads until some of the active threads end.

Trigger initilization is a *major* source of lag for battle.net.
It should not generate any lag. All trigger code is run locally and code specified to run at map initialization will run before the session starts while it is still showing the loading screen. Poor initialization processes will result in degraded load performance. A big loading delay is the script compiler which takes a time directly proportional to the length of the Galaxy script being parsed.

It should not even cause frame dropping because it occurs before the session begins. The initial start-up lag and poor performance people experience is caused by other factors. An example could be un-optimized shader configuration in the graphic card because graphic drivers dynamically optimize based on usages and bottlenecks. People with little memory will have many hard page faults for both files and the process virtual memory which could take many seconds to resolve and allow the game a suitable working set.

I know I made a 3rd person movement/shooter system one time.
Those are different. They require use of events that generate net traffic because they use local attributes that are not normally synchronized (mouse and keyboard). If you use events poorly or are playing with people that have bad upload speeds then lag can easily occur.

Performance wise such systems are also difficult. The viewing angle is bad for RTS game engines because it allows a lot of terrain to be visible. Especially on poor systems there might not be enough resources to display such views at a decent rate.

1. If you look at all of the naval ships you will notice that the attack animation (muzzel flash of the cannons which I removed) only comes from the center unit of the naval warships, no matter if I custom modeled it or not. Can you please help me fix this?
Do the turrets have a muzzle attachment point? I could give a try at fixing it.

2. The Diplomacy system has a bug in the beginning of the game. The first few requests to accept an alliance or another offer will fail. After that it works fine.
Sounds like an initialization problem. Will look in to it.

3. The city capture system is not always working. I know the map has a huge lag load but for some reason either the city won't capture, or the shipyard along with it won't capture. Can you help me code that part more efficiently?
The problem is how you setup what belongs to a city. Not only is it very inefficient (a lot of iterating through all units on the map) but it also might not be completely reliable. The solution would be to migrate to predefined groups for initialization. This still does solve that newly created buildings might not get included.

In any case send me the latest version of the map (so you do not have to port such changes) and I will look into what can be done about these problems.
 
I was not aware it starts another trigger. Here is what I do know though.

There is a significant, noticable, performance difference in a multiplayer environment between the 2 methods. This I have shown in test after test. I am not sure about it all being done on localmachine. It looks like it is syncronised with the hosting server instead.

I will send the new map to you.

I am also curious to see what the verdict is on the tutorial I wrote for you guys.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,255
There is a significant, noticable, performance difference in a multiplayer environment between the 2 methods. This I have shown in test after test. I am not sure about it all being done on localmachine. It looks like it is syncronised with the hosting server instead.
I am not sure what method you are referring to here as many were discussed. I do not see any real reason why creating multiple threads in action definitions will make the code produce less latency or run faster so more tests will be needed there. I agree that looping with waits should perform better than periodic events but lag should remain the same and the performance gain should be minimal. With user input events it is possible that on top of the initial lag from synchronization there is an end lag for synchronization when the thread terminates in which case starting new threads will allow complex actions to be performed while not increasing lag.

I will send the new map to you.
I still have not received it (in case you tried to send but it failed).

I am also curious to see what the verdict is on the tutorial I wrote for you guys.
Very useful although a bit unclear as to what your definition of water is. It will only look like water if you make it so, otherwise it could be sky or even lava.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,255
Problem 1 is annoying. The only way I can think of now is how the Bunker turret does it and create an explosion model on the gun every attack.

I cannot test for problem 2. I have however gone through all the diplomacy related triggering and performed some optimizations here and there. There was also a problem where you were iterating through array indices that made no sense (buttons which did not exist) that has also been fixed. There is also another optimization I have yet to perform which would make the triggers only respond to the appropriate buttons instead of all buttons reducing both lag and trigger overhead.

There might be a data only solution to problem 3 I will look at later. The idea is that all buildings get captured along with the town centre so you get them to observe the owner of their closest town if it matches themselves. When that changes they then get the town to convert them to the new owner. The towns themselves can then be given a buff behaviour that will get the damage source to be the new owner and then heal to full health.

The problem with this proposal is that buildings would be allocated to their nearest town. In the case of ship yards which are far away from the town this might not be the town you want them allocated to. It might however remove all triggering related to ownership flipping other than statistic tracking.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,255
Getting the main buildings to change owner is as easy as 1 behaviour, 1 effect and 1 trigger. The trigger event is has a small scope so will only execute code when a conversion must be done and the code it does execute is a single action. The system is also generic so getting a building to change owner when low on life is just a behaviour added to the building.

You can even get around the magic repairing problem when a conversion happens as the building is completely un-killable (fatal blows will deal 0 damage and cause a ownership change). To stop ping-ponging the building between players a period of invulnerability can be introduced after every ownership change (just another behaviour).

The only problem are linked buildings (separate units that change ownership at the same time). I have tried a couple of ideas and they do not seem to be working well. However I am not beat yet. I will try an approach of having main buildings compete for ownership over linked buildings based on a behaviour that replaces the furthest away cast to build a link from all main buildings to their closest linkable buildings. Upon conversion I will try and get this link to update ownership to the new main building owner.

The aim is for it to be completely dynamic, like the conversion system, while still retaining high performance.
 
Status
Not open for further replies.
Top