PDA

View Full Version : Sal's useful scripts [perpetual vehicle movement in MP]



Salmo
Feb-12-2014, 03:48
Not to be outdone by the Crimson Canine, I've dug deep into my locker & come up with a script that will get vehicles to move back & forth endlessly on their waypoints. Why not use a spline road & car.cpp script you say? Well because that only works in single player. Spline roads are broken in the multiplayer online environment so if you place a vehicle in an online mission, it will travel to the end of it's waypoints & then stop & remain there until the end of the mission.



public class Mission : AMission
{

// perpetual vehicles movements
#region perpetual vehicles movements
bool PerpetualVehicles = true; // turn perpetual vehicle movements on/off
int CheckVehicleMovementEvery = 120; // seconds
#endregion

public override void OnTickGame()
{
base.OnTickGame();

#region Vehicles travel up & down waypoints endlessly in MP server missions
// ------------------------------------------------------------------------------------------------------
// Vehicles travel back & forth along waypoints endlessly in MP server missions just like on spline roads
// ------------------------------------------------------------------------------------------------------
// By: Salmo 6 Oct 2012 COPYRIGHT Lee Miles 2012 ALL RIGHTS RESERVED
// Purpose:
// A work-around for the broken spline roads/car.cpp script in multiplayer (server) missions.
// How it works:
// a. Place vehicles & waypoints as normal in FMB (one way only). do not attach to spline roads
// or use car.cpp script
// b. The script will detect when a vehicle has reached it's last waypoint & will
// send the vehicle off in the reverse direction. Works endlessly or until vehicle destroyed.
// Known issues:
// 1. Vehicles sometimes are a little erratic following their waypoint path, make sure there are not too many
// objects that could get in their way.
// 2. Vehicles will sometimes reverse or do a circle along their waypoint path.
// ------------------------------------------------------------------------------------------------------
if (PerpetualVehicles && Time.tickCounter() % (CheckVehicleMovementEvery * 32) == 0) // check ground group positions every 2 min
{
try
{
foreach(int army in GamePlay.gpArmies()) // do all armies
{
foreach (AiGroundGroup groundgroup in GamePlay.gpGroundGroups(army)) // every groundgroup in each army
{
if (groundgroup.GroupType() == AiGroundGroupType.Vehicle)
{
AiWayPoint[] way = groundgroup.GetWay(); // remember the ground groups waypoints

// should be able to use line below, but groundgroup.GetCurrentWayPoint() always returns zero (is broken), damn you dev's :(
// if (groundgroup.GetCurrentWayPoint() == way.GetLength(0)) // ground group has reached the end waypoint
// Let's use a work-around instead. See if groundgroup position is close to end waypoint
Point3d EndWayPoint = new Point3d();
EndWayPoint.x = way[way.GetLength(0) - 1].P.x;
EndWayPoint.y = way[way.GetLength(0) - 1].P.y;
EndWayPoint.z = groundgroup.Pos().z;
if (groundgroup.Pos().distance(ref EndWayPoint) < 50) // ground group is close to it's last waypoint
{
// reverse waypoints
for (int j = 0; j < way.GetLength(0) / 2; j++)
{
AiWayPoint tmp = way[j];
way[j] = way[way.GetLength(0) - j - 1];
way[way.GetLength(0) - j - 1] = tmp;
}
// give ground group new reversed waypoints
groundgroup.SetWay(way);
}
}
}
}
}
catch (Exception e)
{
//Console.WriteLine("Error: " + e.Message + " [OnTickGame]");
// nothing to print here, usually a 'object not set to instance of object' error
// if one of the armies does not have any ground groups
}
}
// ------------------------------ end of endless vehicles routine -----------------------------------
#endregion

}

No601_Swallow
Feb-12-2014, 04:00
Not to be outdone by the Crimson Canine, I've dug deep into my locker & come up with a script that will get vehicles to move back & forth endlessly on their waypoints. Why not use a spline road & car.cpp script you say? Well because that only works in single player. Spline roads are broken in the multiplayer online environment so if you place a vehicle in an online mission, it will travel to the end of it's waypoints & then stop & remain there until the end of the mission.




Brilliant!

I must say, if I'd know about Spline roads not working properly online, it would have saved me much angst and hair-pulling a few months ago. I couldn't understand why they weren't working....! Now I can go back and have another go at that mission! :thumbsup:

SoW Reddog
Feb-12-2014, 04:12
Good stuff Salmo. Will almost certainly be using this myself. I also like the explanation. Much clearer than all mine.

=FI=Murph
Feb-13-2014, 00:50
I am already using the script needed for co-op play, so the .cs name for the mission file is being used by that script. I tried copying and pasting this script into the co-op script,but it does not work. What might I be doing wrong?

Salmo
Feb-13-2014, 01:27
I am already using the script needed for co-op play, so the .cs name for the mission file is being used by that script. I tried copying and pasting this script into the co-op script,but it does not work. What might I be doing wrong?

I didn't include refernces to the C# libraries at the beginning of the script. Try putting these refernce lines at the strat of the script ...



using maddox.game;
using maddox.game.world;
using part;
using System.IO;
using System.Reflection;
using maddox.GP;

=FI=Murph
Feb-13-2014, 08:50
It's still not working. How can I post what I've got in the file here so that you can advise me?

Salmo
Feb-13-2014, 16:15
It's still not working. How can I post what I've got in the file here so that you can advise me?

Click on the # button above the post text box. This will place
characters into you post. Copy & past your script code into the thread post between the CODE] and the [/CODE markers.

=FI=Murph
Feb-14-2014, 00:05
using System;
using System.Collections.Generic;
using System.Text;

using maddox.game;
using maddox.game.world;

//$reference parts/core/gamePlay.dll

public class Mission : AMission
{
public override void OnBattleInit()
{
base.OnBattleInit();

if (GamePlay is GameDef)
{
(GamePlay as GameDef).EventChat += new GameDef.Chat(Mission_EventChat);
}
}

void Mission_EventChat(IPlayer from, string msg)
{
if (msg.StartsWith("!help"))
{
Chat("Commands: !aircraft, !select#", from);
}
if (msg.StartsWith("!aircraft") || msg.StartsWith("!select"))
{
List<Tuple<AiAircraft, int>> aircraftPlaces = new List<Tuple<AiAircraft, int>>();
if (GamePlay.gpArmies() != null && GamePlay.gpArmies().Length > 0)
{
foreach (int army in GamePlay.gpArmies())
{
if (GamePlay.gpAirGroups(army) != null && GamePlay.gpAirGroups(army).Length > 0)
{
foreach (AiAirGroup airGroup in GamePlay.gpAirGroups(army))
{
if (airGroup.GetItems() != null && airGroup.GetItems().Length > 0)
{
foreach (AiActor actor in airGroup.GetItems())
{
if (actor is AiAircraft)
{
AiAircraft Aircraft = actor as AiAircraft;
for (int place = 0; place < Aircraft.Places(); place++)
{
aircraftPlaces.Add(new Tuple<AiAircraft, int>(Aircraft, place));
}
}
}
}
}
}
}
}

if (msg.StartsWith("!aircraft"))
{
int i = 0;
foreach (Tuple<AiAircraft, int> aircraftPlace in aircraftPlaces)
{
string playerName = "";
Player player = aircraftPlace.Item1.Player(aircraftPlace.Item2);
if (player != null)
{
playerName = " " + player.Name();
}
Chat("#" + i + ": " + aircraftPlace.Item1.Name() + " " + aircraftPlace.Item1.TypedName() + " " + aircraftPlace.Item1.CrewFunctionPlace(aircraftPlac e.Item2) + " " + playerName, from);
i++;
}
}
else if (msg.StartsWith("!select"))
{
msg = msg.Replace("!select", "");

int i = -1;
if (int.TryParse(msg, out i) && i < aircraftPlaces.Count)
{
Tuple<AiAircraft, int> aircraftPlace = aircraftPlaces[i];
if (aircraftPlace.Item1.Player(aircraftPlace.Item2) == null)
{
from.PlaceEnter(aircraftPlace.Item1, aircraftPlace.Item2);
}
else
{
Chat("Place occupied.", from);
}
}
else
{
Chat("Please enter a valid aircraft number, e.g. !select0, !select1, !select2, ...", from);
}
}
}
}

public void Chat(string line, IPlayer to)
{
if (GamePlay is GameDef)
{
(GamePlay as GameDef).gameInterface.CmdExec("chat " + line + " TO " + to.Name());
}
}
}

using maddox.game;
using maddox.game.world;
using part;
using System.IO;
using System.Reflection;
using maddox.GP;

public class Mission : AMission
{

// perpetual vehicles movements
#region perpetual vehicles movements
bool PerpetualVehicles = true; // turn perpetual vehicle movements on/off
int CheckVehicleMovementEvery = 120; // seconds
#endregion

public override void OnTickGame()
{
base.OnTickGame();

#region Vehicles travel up & down waypoints endlessly in MP server missions
// ------------------------------------------------------------------------------------------------------
// Vehicles travel back & forth along waypoints endlessly in MP server missions just like on spline roads
// ------------------------------------------------------------------------------------------------------
// By: Salmo 6 Oct 2012 COPYRIGHT Lee Miles 2012 ALL RIGHTS RESERVED
// Purpose:
// A work-around for the broken spline roads/car.cpp script in multiplayer (server) missions.
// How it works:
// a. Place vehicles & waypoints as normal in FMB (one way only). do not attach to spline roads
// or use car.cpp script
// b. The script will detect when a vehicle has reached it's last waypoint & will
// send the vehicle off in the reverse direction. Works endlessly or until vehicle destroyed.
// Known issues:
// 1. Vehicles sometimes are a little erratic following their waypoint path, make sure there are not too many
// objects that could get in their way.
// 2. Vehicles will sometimes reverse or do a circle along their waypoint path.
// ------------------------------------------------------------------------------------------------------
if (PerpetualVehicles && Time.tickCounter() % (CheckVehicleMovementEvery * 32) == 0) // check ground group positions every 2 min
{
try
{
foreach(int army in GamePlay.gpArmies()) // do all armies
{
foreach (AiGroundGroup groundgroup in GamePlay.gpGroundGroups(army)) // every groundgroup in each army
{
if (groundgroup.GroupType() == AiGroundGroupType.Vehicle)
{
AiWayPoint[] way = groundgroup.GetWay(); // remember the ground groups waypoints

// should be able to use line below, but groundgroup.GetCurrentWayPoint() always returns zero (is broken), damn you dev's :(
// if (groundgroup.GetCurrentWayPoint() == way.GetLength(0)) // ground group has reached the end waypoint
// Let's use a work-around instead. See if groundgroup position is close to end waypoint
Point3d EndWayPoint = new Point3d();
EndWayPoint.x = way[way.GetLength(0) - 1].P.x;
EndWayPoint.y = way[way.GetLength(0) - 1].P.y;
EndWayPoint.z = groundgroup.Pos().z;
if (groundgroup.Pos().distance(ref EndWayPoint) < 50) // ground group is close to it's last waypoint
{
// reverse waypoints
for (int j = 0; j < way.GetLength(0) / 2; j++)
{
AiWayPoint tmp = way[j];
way[j] = way[way.GetLength(0) - j - 1];
way[way.GetLength(0) - j - 1] = tmp;
}
// give ground group new reversed waypoints
groundgroup.SetWay(way);
}
}
}
}
}
catch (Exception e)
{
//Console.WriteLine("Error: " + e.Message + " [OnTickGame]");
// nothing to print here, usually a 'object not set to instance of object' error
// if one of the armies does not have any ground groups
}
}
// ------------------------------ end of endless vehicles routine -----------------------------------
#endregion

Salmo
Feb-14-2014, 02:30
Thanks Murph,

Some common mistakes there ...
1. All your library references (the 'using' statements) should be at the start of the script & any duplicates removed.
2. You should have only one "public class Mission : AMission" section (all the code enclosed in open & closed curly brakets) per script.
3. Also only ever one instance of any particular method inside the AMission class. So for example, only one OnBattleStarted routine. If you're combining 2 scripts that both have some code in OnBattleZStarted then you'll have to copy paste code from one method instance into the other.
4. Also it's a convention to place global variables (those variables used by the whole script) at the beggining of the AMIssion method.

Here's a corrected code for you, note how it's changed ...



using System;
using System.Collections.Generic;
using System.Text;
using maddox.game;
using maddox.game.world;
using part;
using System.IO;
using System.Reflection;
using maddox.GP;
//$reference parts/core/gamePlay.dll

public class Mission : AMission
{
// perpetual vehicles movements
#region perpetual vehicles movements
bool PerpetualVehicles = true; // turn perpetual vehicle movements on/off
int CheckVehicleMovementEvery = 120; // seconds
#endregion

public override void OnBattleInit()
{
base.OnBattleInit();

if (GamePlay is GameDef)
{
(GamePlay as GameDef).EventChat += new GameDef.Chat(Mission_EventChat);
}
}

void Mission_EventChat(IPlayer from, string msg)
{
if (msg.StartsWith("!help"))
{
Chat("Commands: !aircraft, !select#", from);
}
if (msg.StartsWith("!aircraft") || msg.StartsWith("!select"))
{
List<Tuple<AiAircraft, int>> aircraftPlaces = new List<Tuple<AiAircraft, int>>();
if (GamePlay.gpArmies() != null && GamePlay.gpArmies().Length > 0)
{
foreach (int army in GamePlay.gpArmies())
{
if (GamePlay.gpAirGroups(army) != null && GamePlay.gpAirGroups(army).Length > 0)
{
foreach (AiAirGroup airGroup in GamePlay.gpAirGroups(army))
{
if (airGroup.GetItems() != null && airGroup.GetItems().Length > 0)
{
foreach (AiActor actor in airGroup.GetItems())
{
if (actor is AiAircraft)
{
AiAircraft Aircraft = actor as AiAircraft;
for (int place = 0; place < Aircraft.Places(); place++)
{
aircraftPlaces.Add(new Tuple<AiAircraft, int>(Aircraft, place));
}
}
}
}
}
}
}
}

if (msg.StartsWith("!aircraft"))
{
int i = 0;
foreach (Tuple<AiAircraft, int> aircraftPlace in aircraftPlaces)
{
string playerName = "";
Player player = aircraftPlace.Item1.Player(aircraftPlace.Item2);
if (player != null)
{
playerName = " " + player.Name();
}
Chat("#" + i + ": " + aircraftPlace.Item1.Name() + " " + aircraftPlace.Item1.TypedName() + " " + aircraftPlace.Item1.CrewFunctionPlace(aircraftPlac e.Item2) + " " + playerName, from);
i++;
}
}
else if (msg.StartsWith("!select"))
{
msg = msg.Replace("!select", "");

int i = -1;
if (int.TryParse(msg, out i) && i < aircraftPlaces.Count)
{
Tuple<AiAircraft, int> aircraftPlace = aircraftPlaces[i];
if (aircraftPlace.Item1.Player(aircraftPlace.Item2) == null)
{
from.PlaceEnter(aircraftPlace.Item1, aircraftPlace.Item2);
}
else
{
Chat("Place occupied.", from);
}
}
else
{
Chat("Please enter a valid aircraft number, e.g. !select0, !select1, !select2, ...", from);
}
}
}
}

public void Chat(string line, IPlayer to)
{
if (GamePlay is GameDef)
{
(GamePlay as GameDef).gameInterface.CmdExec("chat " + line + " TO " + to.Name());
}
}

public override void OnTickGame()
{
base.OnTickGame();

#region Vehicles travel up & down waypoints endlessly in MP server missions
// ------------------------------------------------------------------------------------------------------
// Vehicles travel back & forth along waypoints endlessly in MP server missions just like on spline roads
// ------------------------------------------------------------------------------------------------------
// By: Salmo 6 Oct 2012 COPYRIGHT Lee Miles 2012 ALL RIGHTS RESERVED
// Purpose:
// A work-around for the broken spline roads/car.cpp script in multiplayer (server) missions.
// How it works:
// a. Place vehicles & waypoints as normal in FMB (one way only). do not attach to spline roads
// or use car.cpp script
// b. The script will detect when a vehicle has reached it's last waypoint & will
// send the vehicle off in the reverse direction. Works endlessly or until vehicle destroyed.
// Known issues:
// 1. Vehicles sometimes are a little erratic following their waypoint path, make sure there are not too many
// objects that could get in their way.
// 2. Vehicles will sometimes reverse or do a circle along their waypoint path.
// ------------------------------------------------------------------------------------------------------
if (PerpetualVehicles && Time.tickCounter() % (CheckVehicleMovementEvery * 32) == 0) // check ground group positions every 2 min
{
try
{
foreach(int army in GamePlay.gpArmies()) // do all armies
{
foreach (AiGroundGroup groundgroup in GamePlay.gpGroundGroups(army)) // every groundgroup in each army
{
if (groundgroup.GroupType() == AiGroundGroupType.Vehicle)
{
AiWayPoint[] way = groundgroup.GetWay(); // remember the ground groups waypoints

// should be able to use line below, but groundgroup.GetCurrentWayPoint() always returns zero (is broken), damn you dev's :(
// if (groundgroup.GetCurrentWayPoint() == way.GetLength(0)) // ground group has reached the end waypoint
// Let's use a work-around instead. See if groundgroup position is close to end waypoint
Point3d EndWayPoint = new Point3d();
EndWayPoint.x = way[way.GetLength(0) - 1].P.x;
EndWayPoint.y = way[way.GetLength(0) - 1].P.y;
EndWayPoint.z = groundgroup.Pos().z;
if (groundgroup.Pos().distance(ref EndWayPoint) < 50) // ground group is close to it's last waypoint
{
// reverse waypoints
for (int j = 0; j < way.GetLength(0) / 2; j++)
{
AiWayPoint tmp = way[j];
way[j] = way[way.GetLength(0) - j - 1];
way[way.GetLength(0) - j - 1] = tmp;
}
// give ground group new reversed waypoints
groundgroup.SetWay(way);
}
}
}
}
}
catch (Exception e)
{
//Console.WriteLine("Error: " + e.Message + " [OnTickGame]");
// nothing to print here, usually a 'object not set to instance of object' error
// if one of the armies does not have any ground groups
}
}
// ------------------------------ end of endless vehicles routine -----------------------------------
#endregion
}

No601_Swallow
Feb-14-2014, 04:44
Thanks Murph,

Some common mistakes there ...
1. All your library references (the 'using' statements) should be at the start of the script & any duplicates removed.
2. You should have only one "public class Mission : AMission" section (all the code enclosed in open & closed curly brakets) per script.
3. Also only ever one instance of any particular method inside the AMission class. So for example, only one OnBattleStarted routine. If you're combining 2 scripts that both have some code in OnBattleZStarted then you'll have to copy paste code from one method instance into the other.
4. Also it's a convention to place global variables (those variables used by the whole script) at the beggining of the AMIssion method.

Here's a corrected code for you, note how it's changed ...



Thanks for the pointers, Salmo.

For those of us who've never studied programming at all, it's often the simplest, most basic concepts that are so difficult to get. (It took me some weeks of serious concentration, bafflement, and comparing and contrasting, and loading examples into VS Express before pretty much anything at all started to make a bit of sense.) There'd be scope for a "Everything You Ever Wanted to Know About Scripting in CLoD But were Too Embarrassed to Ask" - I was going to say "guide", but what I actually mean is a residential course lasting several months, and leading to a PhD in Rocket Science!

Salmo
Feb-14-2014, 04:51
.... what I actually mean is a residential course lasting several months, and leading to a PhD in Rocket Science!

I have thought of starting some sessions in basic scripting. The problem would be how to teach on-line via only TS. It would be hard to see what students were dong with their codes & difficult to explain concepts with showing examples.

=FI=Murph
Feb-14-2014, 08:47
Salmo, thank you for the correction. This looks like something that will require some study.

=FI=Murph
Feb-14-2014, 20:32
I tested the corrected script that you posted and find that it still does not work. I did not place any spline roads when I built the mission, so that should not be the reason. Vehicles are proceeding to their last WP and stopping.

Salmo
Feb-14-2014, 21:29
I tested the corrected script that you posted and find that it still does not work. I did not place any spline roads when I built the mission, so that should not be the reason. Vehicles are proceeding to their last WP and stopping.

Have a look at this line in the code ...



int CheckVehicleMovementEvery = 120; // seconds


The script checks every 120 seconds (2 minutes) to see whether vehciles have reached their last waypoint. That means that the vehicles could reach their last waypoint & wait there for up to 2 minutes before they recieve their new (reversed) waypoints & take off again. If you don't want them to wait so long, then reduce the number of seconds between checking vehicle positions. Perhaps ...



int CheckVehicleMovementEvery = 30; // check vehicle positions every 30 seconds

=FI=Murph
Feb-15-2014, 01:06
Ah! Thank you, I give it a try.

Basha
Feb-16-2014, 03:56
No idea why i am in this section but what about multiple RDC's for teaching or similar software

http://technet.microsoft.com/en-us/library/cc753380.aspx :getaway:

Basha
Feb-16-2014, 06:26
Here's a programme i used with GSP admin some time ago

http://www.teamviewer.com/en/index.aspx

SoW Reddog
Feb-18-2014, 17:27
Used this with Vogler last night. Dead simple to install and use, and free. Very impressed with it.

No601_Swallow
Feb-20-2014, 03:59
Used this with Vogler last night. Dead simple to install and use, and free. Very impressed with it.

Yep! We use it to remote manage our dedicated server. Works like a charm.

ATAG_Lolsav
Mar-14-2014, 14:31
Bringing this thread up because i had a "wild" attempt to make it work on trains

So, digged up the code and applyed this modification


if (groundgroup.GroupType() == AiGroundGroupType.Vehicle && groundgroup.GroupType() == AiGroundGroupType.Train)

But unfortunatly, althought the vehicles do go to their waypoints the trains just wont (they dont turn around). I was wondering if insted of sending them to their starting waypoint is it possible to reverse the waypoints as in:

crude example: 3 waypoints, wp1, wp2 and wp3. Once it reaches wp3 and send them to wp1, insted send them wp3, wp2, wp1, maybe this way it could make it work?