Author Topic: Using forceRequiredAddon to avoid duplicating datablocks  (Read 15299 times)

Could someone type up a tutorial about this and I'll sticky it. There are too many people re-including default gun sounds/particles or vehicles sounds/particles/whatever when they could just use forceRequiredAddon and reduce their datablock consumption by like 80%.

Thanks to those below - Further reading from Iban:

Specific Functions
« Last Edit: October 28, 2015, 11:03:47 AM by Badspot »

Some add-ons have been found to duplicate datablocks from other add-ons.
For example, the flying jeep uses some of the jeep's datablocks and makes slight changes.

Let's understand what datablocks the flying jeep uses that are in the jeep add-on:
Code: (Vehicle_FlyingWheeledJeep) [Select]
datablock WheeledVehicleData(FlyingWheeledJeepVehicle)
{
    //...

    defaultTire  = jeepTire;
    defaultSpring = jeepSpring;
    flatTire     = jeepFlatTire;
    flatSpring  = jeepFlatSpring;

   //...
};
These are just 4 of many datablocks from the jeep, jeepTire, jeepSrping, jeepFlatTire, and jeepFlatSpring: shared by both the regular jeep and the flying jeep. Well, we have them in the regular jeep's files, so why repeat? We can just load the regular jeep in order to use its datablocks:
Code: [Select]
forceRequiredAddOn("Vehicle_Jeep");
Great! Now, there are several error-handling procedures needed. We may be missing Vehicle_Jeep.zip, or the host may have not wanted to the jeep to be enabled. Here, we set the regular jeeps' uiName to blank, so that it is unselectable, fulfilling the host's requests:
Code: [Select]
%error = ForceRequiredAddOn("Vehicle_Jeep");

if(%error == $Error::AddOn_Disabled)
{
   JeepVehicle.uiName = "";
}

Now, Vehicle_Jeep.zip may be missing, so if it's not found, we can't make a new vehicle. If it is found, we can continue to execute the code for our vehicle, the flying jeep:
Code: [Select]
if(%error == $Error::AddOn_NotFound)
{
   error("ERROR: Vehicle_FlyingWheeledJeep - required add-on Vehicle_Jeep not found");
}
else
{
   exec("./Vehicle_FlyingWheeledJeep.cs");
}

It will then execute the flying jeep's script if the file is found.
The code in its full implementation is here:
Code: [Select]
//we need the jeep add-on for this, so force it to load
%error = ForceRequiredAddOn("Vehicle_Jeep");

if(%error == $Error::AddOn_Disabled)
{
   //A bit of a hack:
   //  we just forced the jeep to load, but the user had it disabled
   //  so lets make it so they can't select it
   JeepVehicle.uiName = "";
}

if(%error == $Error::AddOn_NotFound)
{
   //we don't have the jeep, so we're screwed
   error("ERROR: Vehicle_FlyingWheeledJeep - required add-on Vehicle_Jeep not found");
}
else
{
   exec("./Vehicle_FlyingWheeledJeep.cs");
}

Congratulations, now you don't have to waste datablocks! You may also want to consider inheritance for some cases.

Like Kalphiter said - using inheritance can save a lot of datablocks too.

Once your sure the mod you are inheriting from is installed, actually using stuff is easy.

Example from unlimited mining mod - it re-uses the RPG_Tool pickaxe model

Code: [Select]
datablock itemData(DiggingPickaxeItem : rpgPickaxeItem)
  {
    uiName = "Pickaxe";
    image = DiggingPickaxeImage;
    colorShiftColor = $Dig_PickaxeColor;
  };

the key part here is: DiggingPickaxeItem : rpgPickaxeItem
This tells torque to do 2 things:
1) create a new datablock named DiggingPickaxeItem
2) copy all the data from rpgPickaxeItem into this new datablock.
Then you have a normal looking (but short) datablock where you change only what you need.  In the example, the uiName, the Image and the color is changed.  Everything else is left alone.


Now -- since every "ItemData" also needs a "ShapeBaseImageData" in order to work right, here is the datablock to make it work right:
Code: [Select]
datablock shapeBaseImageData(DiggingPickaxeImage : rpgPickaxeImage)
  {
   item = DiggingPickaxeItem;
   projectile = DiggingPickaxeProjectile;
   colorShiftColor = $Dig_PickaxeColor;
   stateSound[0] = "";
  };
This does the same thing as the first example:  make a new datablock called DiggingPickaxeImage and copy all the values from rpgPickaxeImage.  Then we change a few things:
set the item to our newly created item
set the projectile to use one of our own
set the color
disable one of the sounds.

In the end we have made a new version of the RPG_Tools pickaxe:
  - it uses the same model
  - it uses the same animations
  - it has a new color
  - it has a new name
  - it uses a different projectile

and the final completed 3 datablocks: (copy & paste from unlimited mining mod)
Code: [Select]

// pickaxe to mine stuff with -- projectile
datablock projectileData(DiggingPickaxeProjectile : hammerProjectile)
  {
   directDamage = 5;
   lifeTime = 100;
   explodeOnDeath = false;
  };

// pickaxe to mine stuff with -- item for the tools inventory
datablock itemData(DiggingPickaxeItem : rpgPickaxeItem)
  {
    uiName = "Pickaxe";
    image = DiggingPickaxeImage;
    colorShiftColor = $Dig_PickaxeColor;
  };

// pickaxe to mine stuff with -- Image for player to hold in their hand
datablock shapeBaseImageData(DiggingPickaxeImage : rpgPickaxeImage)
  {
   item = DiggingPickaxeItem;
   projectile = DiggingPickaxeProjectile;
   colorShiftColor = $Dig_PickaxeColor;
   stateSound[0] = ""; // disable cheesy sword draw sound
  };

Lastly - there another benefit from inheriting vs copying.
Pretend there is a bug somewhere in the RPG_Tool addon.  The author finds this bug, fixes it, and releases a new version.  Since the DiggingPickaxe uses inheritance, there is nothing to change in order to get the fixes, since the data is copied from the rpgPickaxe datablocks.   If the unlimited mining mod copied code directly from the RPG_Tools addon, then a new version of unlimited mining would also be needed to get the bugfix in RPG_Tools.


Problem with that - copied/inherited datablocks are identical in terms of the 4096 datablock limit, they just make it easier to define. For instance, the Tank shell ("tankShellProjectile : gravityRocketProjectile") uses a new datablock but the other effects don't ("gravityRocketExplosion" is the same for both projectiles)
« Last Edit: March 09, 2011, 01:18:15 PM by Space Guy »

A minimalized/optimized version of some forceRequiredAddon code:

Code: [Select]
if((%error = forceRequiredAddOn("Weapon_Gun")) == $Error::AddOn_Disabled){
   gunItem.uiName = "";
} else if(%error == $Error::AddOn_NotFound) {
   error("ERROR: Weapon_AlternateGun - required add-on Weapon_Gun not found");
   return;
}

--- code for Weapon_AlternateGun here ---
« Last Edit: March 10, 2011, 11:48:37 AM by Ephialtes »

A minimalized/optimized version of some forceRequiredAddon code:

Code: [Select]
if((%error = forceRequiredAddOn("Weapon_Gun")) == $Error::AddOn_Disabled){
   gunItem.uiName = "";
else if(%error == $Error::AddOn_NotFound) {
   error("ERROR: Weapon_AlternateGun - required add-on Weapon_Gun not found");
   return;
}

--- code for Weapon_AlternateGun here ---

If you're going to post code in a tutorial thread please make sure it executes ... I've added your missing parenthesis for you.

If you're going to post code in a tutorial thread please make sure it executes ... I've added your missing parenthesis for you.
It also looks hard to read because of his formatting.

Nothing wrong with adding in extra linebreaks and tab spacing to make it more pleasing for other coders to look at.

Code: [Select]
if((%error = forceRequiredAddOn("Weapon_Gun")) == $Error::AddOn_Disabled)
{
gunItem.uiName = "";
}
else if(%error == $Error::AddOn_NotFound)
{
error("ERROR: Weapon_AlternateGun - required add-on Weapon_Gun not found");
return;
}

--- code for Weapon_AlternateGun here ---

But I guess that's just my OCD acting up.

There's no reason to compress already short code into giblets because you have some sort of disorder that makes clutter look really nice.

This is a tutorial. If you're TS-competent enough to understand that, you won't be following this guide, or you're more than capable of compressing it on your own.


PNetwork's forceRequiredAddonTutorial
"Why tons of datablocks when you can just use other add-ons?"

Contents:
1-Criteria to force
2-Why force addons?
3-Function Usage

1: Criteria to force
So you want to use the forceRequiredAddOn function, eh? Well, make sure the add-on you wanna use the function with matches this criteria:
1: Has atleast one .cs file
Lol, that was easy, right?

Why force addons?
Why use the forceRequiredAddon function, you say?
You get two advantages.
1: You can be lazy and not have to do all the work.
2: People who DL your add-on get benefit so they have to load less datablocks.

Function Usage
Step 1:First you'll have to memorize all the .cs files inside the add-on you are trying to use the function with. But whatever, you can write them down on a piece of paper.
Step 2: Go back to the script from YOUR addon.
Step 3: First type this. We're using SciFiBuild particle as an example.
And we will use %fa as our variable that will help us in various parts.
Code: [Select]
%fa = ForceRequiredAddOn("particle_sciFiBuild"); //Force that.
This is our starting line which basically says,
Oh hey theres a faTMAN who wants science fiction particles to be required!
But this is basically a piece of crap so far. It does nothing to make sure this is enabled , really.
We have to add more code, like this.
(Sci fi build has more than one emitter but just say it only have RedSheildL Particle. If you were to have an addon like this though, you would copy+paste the statement [Thing.uiName = "";]
and edit "Thing" to the datablock name which is found inside the code of the other addon.
Code: [Select]
%error = ForceRequiredAddOn("particle_sciFiBuild");

if(%fa == $Error::AddOn_Disabled)
{
   RedSheildLParticle.uiName = "";

}
Ok. Here's the final element that does the real business.
Code: [Select]
if(%fa == $Error::AddOn_NotFound)
{
   error("ERROR: [ Your addon name here] - required add-on particle_sciFiBuild "); // Oops i don't have that addon
}
else // Otherwise,  if i do have the addon
{
   exec("./Particle_SciFiBuild.cs");
}
Let's look closely at the exec() line.
There's something to understand.

 If you open the server.cs of the addon you want to force, and
A: You see only exec() lines. No other code.
B: You see exec and other code.
C: You see only other code, no exec() at all.

For A users:
Don't modify the exec() line above in the code statement at all.
(Particle_SciFiBuild.cs is obvious to change though)
For B users:
Modify the exec() line above in the code statement to say
   exec("./server.cs");
This way the server.cs is run and the exec function in the server.cs file executes sub-scripts like Particle_SciFiBuild and then also executes server.cs's own code.
For C users:
Same thing as above. Change it to ./server.cs

You're done! You can also use this to run remote scripts.
« Last Edit: June 29, 2011, 02:17:01 PM by PNetwork2011 »


Lol to pn's
lol there's like 4 or 5 tutorials of the same thing.

Fancy talk.. My brain hurts. T_T


Some add-ons have been found to duplicate datablocks from other add-ons.
For example, the flying jeep uses some of the jeep's datablocks and makes slight changes.

Let's understand what datablocks the flying jeep uses that are in the jeep add-on:
Code: (Vehicle_FlyingWheeledJeep) [Select]
datablock WheeledVehicleData(FlyingWheeledJeepVehicle)
{
    //...

    defaultTire  = jeepTire;
    defaultSpring = jeepSpring;
    flatTire     = jeepFlatTire;
    flatSpring  = jeepFlatSpring;

   //...
};
These are just 4 of many datablocks from the jeep, jeepTire, jeepSrping, jeepFlatTire, and jeepFlatSpring: shared by both the regular jeep and the flying jeep. Well, we have them in the regular jeep's files, so why repeat? We can just load the regular jeep in order to use its datablocks:
Code: [Select]
forceRequiredAddOn("Vehicle_Jeep");
Great! Now, there are several error-handling procedures needed. We may be missing Vehicle_Jeep.zip, or the host may have not wanted to the jeep to be enabled. Here, we set the regular jeeps' uiName to blank, so that it is unselectable, fulfilling the host's requests:
Code: [Select]
%error = ForceRequiredAddOn("Vehicle_Jeep");

if(%error == $Error::AddOn_Disabled)
{
   JeepVehicle.uiName = "";
}

Now, Vehicle_Jeep.zip may be missing, so if it's not found, we can't make a new vehicle. If it is found, we can continue to execute the code for our vehicle, the flying jeep:
Code: [Select]
if(%error == $Error::AddOn_NotFound)
{
   error("ERROR: Vehicle_FlyingWheeledJeep - required add-on Vehicle_Jeep not found");
}
else
{
   exec("./Vehicle_FlyingWheeledJeep.cs");
}

It will then execute the flying jeep's script if the file is found.
The code in its full implementation is here:
Code: [Select]
//we need the jeep add-on for this, so force it to load
%error = ForceRequiredAddOn("Vehicle_Jeep");

if(%error == $Error::AddOn_Disabled)
{
   //A bit of a hack:
   //  we just forced the jeep to load, but the user had it disabled
   //  so lets make it so they can't select it
   JeepVehicle.uiName = "";
}

if(%error == $Error::AddOn_NotFound)
{
   //we don't have the jeep, so we're screwed
   error("ERROR: Vehicle_FlyingWheeledJeep - required add-on Vehicle_Jeep not found");
}
else
{
   exec("./Vehicle_FlyingWheeledJeep.cs");
}

Congratulations, now you don't have to waste datablocks! You may also want to consider inheritance for some cases.

Thanks for randomly quoting it.