Replacing a function

Everything about mods can be found here.

Moderator: Morax

Re: Replacing a function

Postby Uveso » 21 Jan 2020, 01:21

All starts with the unit class:
Code: Select all
Unit = Class(moho.unit_methods)

moho.unit_methods is a c-class imported to LUA, the root file with all basics for the unitclass can be found in:
Code: Select all
Supreme Commander\Gamedata\mohodata.SCD\lua\sim\Unit.lua

Now we create the StructureUnit. We are using the Unitclass as base.
That means everything included in the unitclass ist also part of the StructureUnit (if we not overwrite something)
Code: Select all
StructureUnit = Class(Unit) {}

Finaly we creating the FactoryUnitclass.
Code: Select all
FactoryUnit = Class(StructureUnit) {}

At this point the FactoryUnit has all function from the unitclass and all added functions from the StructureUnitclass.

If you now want to hook the FactoryUnit, first copy the original FactoryUnit:
Code: Select all
local oldFactoryUnit = FactoryUnit


Now we are creating our own FactoryUnitclass:
Code: Select all
FactoryUnit = Class(oldFactoryUnit)


We don't need to add the StructureUnitclass because (old)FactoryUnit is a child from StructureUnitclass that is also a child from unitclass.
User avatar
Uveso
Supreme Commander
 
Posts: 1788
Joined: 11 Dec 2015, 20:56
Location: Germany
Has liked: 70 times
Been liked: 291 times
FAF User Name: Uveso

Re: Replacing a function

Postby BlackYps » 21 Jan 2020, 17:15

I am familiar with the concept of Inheritance in classes in general. But I am unsure how it works when also hooking some functions.
The final defaultunits.lua loaded in the game looks like this I assume:

Code: Select all
StructureUnit = Class(Unit) {
--a ton of functions
}

FactoryUnit = Class(StructureUnit ) {
--more functions
}

--now comes the hooked part from the mod

local oldStructureUnit = StructureUnit
StructureUnit = Class(oldStructureUnit) {
    OnKilled = function(self)
        LOG('***---*** StructureUnit OnKilled HOOK')
        oldStructureUnit.OnDestroy(self)
        local orient = self.TarmacBag.Orientation
        local currentBP = self.TarmacBag.CurrentBP
        self:DestroyTarmac()
        self:CreateTarmac(true, true, true, orient, currentBP, currentBP.DeathLifetime or 300)
    end,
   
    OnDestroy = function(self)
        LOG('***---*** StructureUnit OnDestroy HOOK')
        Unit.OnDestroy(self)
    end,
}


So a part of the class definition comes after the subclasses are created. The changes from the mod seem to not always work.
I attached the mod so you can have a look.
Note that the Aircraftcarrier automagically uses the new function defined in seaunit.
However the changes in Structureunit seem to not be used by the child classes.
This doesn't make any sense to me. Like, at all!

I really appreciate your help!
Attachments
oil_slicks.zip
(3.79 MiB) Downloaded 20 times
BlackYps
Avatar-of-War
 
Posts: 74
Joined: 15 Feb 2019, 19:46
Has liked: 7 times
Been liked: 31 times

Re: Replacing a function

Postby Uveso » 22 Jan 2020, 20:44

Yes this is a bit tricky.
Structures have a class for every faction.

Create a new file:
Code: Select all
\Mods\oil_slicks\hook\lua\cybranunits.lua


insert this to the empty file:
Code: Select all
local oldCLandFactoryUnit = CLandFactoryUnit
CLandFactoryUnit = Class(oldCLandFactoryUnit) {

    OnCreate = function(self)
        WARN('***---*** CLandFactoryUnit OnCreate HOOK')
        oldCLandFactoryUnit.OnCreate(self)
    end,

    OnKilled = function(self, instigator, type, overkillRatio)
        WARN('***---*** CLandFactoryUnit OnKilled HOOK')
        oldCLandFactoryUnit.OnKilled(self, instigator, type, overkillRatio)
    end,

    OnDestroy = function(self)
        WARN('***---*** CLandFactoryUnit OnDestroy HOOK')
        oldCLandFactoryUnit.OnDestroy(self)
    end,
}


Now create and destroy a CYBRAN LAND Factory.
User avatar
Uveso
Supreme Commander
 
Posts: 1788
Joined: 11 Dec 2015, 20:56
Location: Germany
Has liked: 70 times
Been liked: 291 times
FAF User Name: Uveso

Re: Replacing a function

Postby BlackYps » 24 Jan 2020, 19:02

I see.
Is there a way to have all structures use a hooked function without copying it in every subclass specifically, though?
I hooked the OnCreate function of the StructureUnit class (in defaultunits.lua) and noticed that it works for point defenses, all factories, missile launchers and defense and artillery. This is for all factions.
It seems that in the hooking process not all classes get regenerated with my newly hooked function. However I can't see any systematics behind this. Do you know what is going on?
BlackYps
Avatar-of-War
 
Posts: 74
Joined: 15 Feb 2019, 19:46
Has liked: 7 times
Been liked: 31 times

Re: Replacing a function

Postby Uveso » 24 Jan 2020, 20:16

Sadly not.
Most classes that uses the StructureUnit as base have already a hook for the OnDestroy function. So they are overwriting a hook that was made inside the Structure class.
Also the hooked OnDestroy function from all subclasses of StructureUnit should call the StructureUnit.OnDestroy on the end, but they call Unit.OnDestroy instead.

So if you want to hook the OnDestroy inside Structures you need to make a hook in the parentclass of Structureunits, and this is the unitclass.
Make a hook inside unit.lua for the OnDestroy function. This will be called from any mobile and structure units.
This way the original OnDestroy function will be called and your hook will be executed after the original StructureUnit.OnDestroy.

All other changes like not executing the OnDestroy function in subclasses, you need to hook every single OnDestroy function you want to change.
User avatar
Uveso
Supreme Commander
 
Posts: 1788
Joined: 11 Dec 2015, 20:56
Location: Germany
Has liked: 70 times
Been liked: 291 times
FAF User Name: Uveso

Re: Replacing a function

Postby BlackYps » 24 Jan 2020, 20:38

Then I will probably have to copy the function a few times to classes that do not accept the new function.
I was hoping to avoid that, but if there is no other way, that will do.

Still, thank you very much for your help!
BlackYps
Avatar-of-War
 
Posts: 74
Joined: 15 Feb 2019, 19:46
Has liked: 7 times
Been liked: 31 times

Re: Replacing a function

Postby Uveso » 24 Jan 2020, 20:57

You are welcome.
User avatar
Uveso
Supreme Commander
 
Posts: 1788
Joined: 11 Dec 2015, 20:56
Location: Germany
Has liked: 70 times
Been liked: 291 times
FAF User Name: Uveso

Re: Replacing a function

Postby BlackYps » 24 Jan 2020, 22:10

I got the solution now!

I realized that the problem is with all classes that do NOT override the specific function on their own.
So when you hooked a function like this
Code: Select all
local oldStructureUnit = StructureUnit
StructureUnit = Class(oldStructureUnit) {
    OnCreate = function(self)
        oldStructureUnit.OnCreate(self)
        LOG('*** we hooked sucessfully')
    end,
}

you have to make all subclasses, that do not override that function anyway, use the new function like this:
Code: Select all
local oldRadarUnit = RadarUnit
RadarUnit = Class(oldRadarUnit) {
    OnCreate = function(self)
        StructureUnit.OnCreate(self)
    end,
}

You do this for all subclasses that inherit from the original class and do not override the function. These can be a lot, but at least you don't have to paste in your function every time.
This is still not perfect, because when in a later game patch modifies the function in one of the subclasses you override this change right away.
But at least it is working now \o/
BlackYps
Avatar-of-War
 
Posts: 74
Joined: 15 Feb 2019, 19:46
Has liked: 7 times
Been liked: 31 times

Previous

Return to Mods & Tools

Who is online

Users browsing this forum: No registered users and 1 guest