Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plugins for SoilMod? Or add other mods' features to SoilMod? #15

Open
DeckerMMIV opened this issue Jul 27, 2014 · 20 comments
Open

Plugins for SoilMod? Or add other mods' features to SoilMod? #15

DeckerMMIV opened this issue Jul 27, 2014 · 20 comments

Comments

@DeckerMMIV
Copy link
Owner

Players are finding that other mods, which also tries to control/overwrite the Utils. functions for foliage-layer manipulation, are conflicting or not working together with SoilMod.

This problem of "conflicting mods" was anticipated, but could there be a future solution for it?

Should (can?) there be some kind of "plugin" ability for SoilMod, so features like green-fertilizing, multi-moving, green-direct-cut and similar, can be added when the players so chooses?

Or should such extra features just be build into SoilMod's scripts, to keep it within "one package"?

@webalizer-gt
Copy link
Contributor

Hi!
I think this is the case with choppedStraw. I saw you added support for the layers. Thanks for that!
For the future i would prefer a plugin system for soilMod because i think not everyone needs or wants the whole package. So do i at the moment.
I saw the other issue where a suggestion was to give chopped straw a fertilizing effect. Well that's what i wanted a long time even for my urf-seeder spec.
Maybe we can work toghether here. But my skills are far beyond yours.

Regards
Tom
Aka webalizer

@upsidedownLS13
Copy link

To make plugins it would be really helpfull if you could make the other main tables besides fmcSoilMod global. The way it is set up at the moment its really hard to get access to tables like fmcGrowthControl from outside mods.

That would be all the "plug in"-support I would need to make mods like "green-fertilizing, multi-moving, green-direct-cut" compatible.

Plus it would make a number of custom map things much easier. I already have a pile of scripting requests from my mapper (MIG-Celle map) I cant solve. At least not without some ugly setfenv()-hacks that are likely to cause more trouble than good.

@DeckerMMIV
Copy link
Owner Author

If you look at SoilMod's scripts, then at what points - functions / internal-statements - would you need to access (i.e. inject extra code), to accomplish your chosen feature(s)?
Or asked differently; can you explain how or what (foliage-layer) effects you want to make with what equipment(s) and/or environment (weather, days/time, etc.)? - This could give me an indication of where the "inject points" should be in the SoilMod scripts.

For fmcGrowthControl:updateFoliageCellXZWH() I could probably make some sort of prioritized table-of-functions, where each function is given the parallelogram for the square to update, and then performs the particular foliage-layer changes.
This should make it able to dynamically add other 'growth cycle' effects, which hopefully could be extended in the future with more meta-data to control "when" it occurs:

  tableOfFunctions = {}
  table.insert(tableOfFunctions, function(x,y,wx,wy,hx,hy)
    -- Increase growth ...
  end);
  table.insert(tableOfFunctions, function(x,y,wx,wy,hx,hy)
    -- Remove spray moisture ...
  end);
  table.insert(tableOfFunctions, function(x,y,wx,wy,hx,hy)
    -- Lime/Kalk and soil pH ...
  end);
  ...etc...

function fmcGrowthControl:updateFoliageCellXZWH(x,z, wh, pctCompleted, noEventSend)
  for _,foliageEffect in pairs(tableOfFunctions) do
    foliageEffect(x,y,wx,wy,hx,hy)
  end
end;

For the Utils. functions, I recon it will be more tricky.

For the "fertilization by cutted/existing crops" effects, I guess it will be the cultivator/plough tools that "creates" such effects, so it would be Utils.updateCultivatorArea and Utils.updatePloughArea that needs to have code injected. However I guess this should probably be before calling destroy common area, that a call to "plugin(s)" must be placed.

The "green direct cut" I am a bit confused about - and am reluctant to use as-is, due to it modifies minHarvestingGrowthState and maxHarvestingGrowthState so very often.
It also indicates to me, that the Utils.cutFruitArea needs a special injection point, where the min/max-harvesting-growth-state "constants" should be modifiable just before using them for the setDensityMaskParams functions. - However, this should only occur when it is a cutter tool that is in use, and unfortunately the Utils.cutFruitArea is not given a reference to whatever object that calls it. Maybe the mod should set an "indicator variable" before calling Utils.cutFruitArea... but then again, this will not work in multiplayer, unless the CutterAreaEvent object was overwritten to send such information too (similar to what I do with SprayerAreaEvent)

For "multi moving", as it also replaces the Utils.cutFruitArea and MowerAreaEvent.runLocally, I wonder if it wouldn't be better to just make an entire new custom cut fruit area function for it? - If it will only work for "mowers" and these only produce windrows/swath, I see no problem with it has its own functionality.

@webalizer-gt
Copy link
Contributor

In urfSeeder at the moment i use a slightly modified sprayer script. So when it comes to

if (table.getn(sprayingAreasSend) > 0) then
SprayerAreaEvent.runLocally(sprayingAreasSend);
g_server:broadcastEvent(SprayerAreaEvent:new(sprayingAreasSend));
end;

i need to create a fertilization state like cultivated/ploughed liquid_manure. Thats what you call Increase growth in your tableOfFunctions i think. This should be the right way.


Regarding choppedStraw i have no idea how to plug in the middle. Somewhere and somehow i have to give SoilMod information that layerXY exists and that cultiviating/ploughing this layer creates a fertitlization effect. Maybe enhance the addFruitToFmcDynamicFoliageLayer with information about fertilizing?
The question is: do you want to allow everybody (like me ;-) ) to use such essential functions of your mod? Will this end up with fertilizing cheat plugins? And if so, should we bother if someone is unwise enough to destroy all the good functions of SoilMod with such cheats?
Just some thoughts...

@DeckerMMIV
Copy link
Owner Author

Regarding urfSeeder. If you look closely at SoilMod's changes to SprayerAreaEvent you will notice that I have added a second argument, to be able to send the 'fill-type' (i.e. "fertilizer", "fertilizer2", etc.)

SprayerAreaEvent.runLocally(cuttingAreasSend, fillType);
g_server:broadcastEvent(SprayerAreaEvent:new(cuttingAreasSend, fillType));

So if you make the same change in your urfSeeder script, and set the fillType value to one of the Fillable.FILLTYPE_FERTILIZER etc., I think it will "just work". (So long as the SprayerAreaEvent object is the global one, which SoilMod has overwritten.)


For "choppedStraw fertilization", "green-direct-cut" etc., I am currently adding plugin-injection-points to the Utils. functions that SoilMod overrides, so other mods should be able to inject additional "foliage-layer modification" at specific points. - So you do not (currently) need to have any idea how to "plug in the middle", as that is what the SoilMod scripts need to supply support for.

But what you need to know and explain is; "how is the effect supposed to happen." - So if "choppedStraw to fertilization" can only happen when using a cultivator, then the "plugin-point" I need to add to the SoilMod scripts, would be somewhere inside Utils.updateCultivatorArea.

Then your mod should implement a specific function (following the requirements that SoilMod's plugin support dictates) that changes the foliage-layer(s) the way you want, and "plug it into SoilMod" using the (yet to be made) API-functions. - I am trying to have SoilMod's own effects use the same plugin method, so I get some understanding of if it works or not.

And if players use "cheat plugins", then let them. - It is their game play, so if they want to play differently/unrealistic, I won't stop them.

@webalizer-gt
Copy link
Contributor

I already tried to send the filltype but i only get a fertilization effect with liquidManure. And of course i don´t want to have the liquidManure texture behind the seeder ;-)

@DeckerMMIV
Copy link
Owner Author

Hmm. That sounds odd, if Fillable.FILLTYPE_FERTILIZER produces slurry. - Oh well, I guess I need to find an URF-seeder somewhere and see how it works.

@webalizer-gt
Copy link
Contributor

No no. If i use fertilizer as fillype it only darkens the ground as expected BUT it don´t fertilize the ground.
Then i tried slurry and it DOES fertilize at midnight.
I think i read somewhere that fertilizer in SoilMod don´t affect crop that has not grown yet?!

@DeckerMMIV
Copy link
Owner Author

Ah, yes. That is correct - so much for my own memory :-/

Okay, so an URF-seeder, adding to the synthetic fertilizer "at the same time as the crop is seeded". It can not use the SprayerAreaEvent the way it is implemented now.

'Katze5' from FS-UK has asked me if there was a way to spray synthetic fertilizer even before any crop was seeded, and I told him to change fmcModifyFSUtils.fertilizerSynthetic_spray_firstGrowthState to zero. - This setting is with v1.1.6 now available to change in the careerSavegame.XML file, instead of the LUA script.

I need to think about how to add this "URF-seeder with synthetic fertilizer" to SoilMod. - I am thinking about changing from 3 to only 2 types of fertilizer/herbicide, as written in this post; http://fs-uk.com/forum/index.php?topic=161700.msg1087861#msg1087861 (the last paragraph.)


For the "plugin" support in SoilMod, my initial experiment @2c0d429 seems to go well.
It is a major re-design of the SoilMod scripts, and not yet finished, as there are more things to add.
So please don't attempt to code towards it for now, as things will change.

@upsidedownLS13
Copy link

I love the plugin-functions already

What kind of feedback-mechanism do you have in mind? Lets say a plugin-function for cutFruitArea wants to change the amount of output. Multipliers as return variables?

@DeckerMMIV
Copy link
Owner Author

What I have attempted, is to have the following "3 phases" in each of the Utils. functions; a 'setup', 'before' and 'after' phase, along with the normal operation of the function:

function Utils.<one-of-the-functions>
  <initialize a 'FruitDesc' if possible>
  <initialize a 'DataStore' and fill with "useful" variables>

  <call all registered "setup" plugins, to let them modify 'DataStore' if they need so>
  <call all registered "before" plugins, to let them modify foliage-layers and/or 'DataStore'>

  <perform the normal game's "foliage-function" but using 'DataStore' values>

  <call all registered "after" plugins, to let them modify foliage-layers and/or 'DataStore'>

  <return the function's normal number of variables, but take them from 'DataStore'>
end

So for example in the latest @eac67342b6859c62391ee37734d8fb00720077f7, if you want to have cutFruitArea return a different volume value, you need to take a look at fmcModifyFSUtils.LUA how it has changed the Utils.cutFruitArea function, to discover what 'dataStore' contains of possible variable-names (plugins can add/modify their own if needed).

Then take a look at fmcSoilModPlugins.LUA, search for addPlugin_CutFruitArea_after (there are 5) to see how SoilMod itself changes the volume value in "after" phase, depending on earlier gathered information during the "before" phase that was stored in 'dataStore'. - The plugin's priority are the sequence they are executed by.

It is important that the same type and count of values are returned from the cutFruitArea function, so the base scripts still thinks they are calling the "normal" cutFruitArea. - So you need to figure out a way to "return a modified value", by studying how the base scripts acts on the returned values.

I have not yet attempted to add these "3 phases" to all of the other FSUtils functions. First I need to make sure that SoilMod itself can use SoilMod's plugin facility ;-)

@upsidedownLS13
Copy link

I finally got around to trying things systematically.
Both the multiMowing and the greenDirectCut are working without any problems.

The multiMowing has a component checking for manure/slurry on gras. Atm this part of the mod is only working with the GMK-mod of marhu. I am not that deep into the soilMod mechanics, so I simply ask: Is there already a component in the cutFruitArea increasing the grass yield if manure/slurry is applied to grass? If yes I can leave things exactly as they are :)

The greenFertilizer needed a small tweak (changing the order in which the Utils functions are tackled). Now the GF is using soilmods Utils-functions and everything is essentially fine.

An updated version or GF is sent to modhoster and will be released today. I will however make a new version once your plugin system is finalized and released to the public. It is a much cleaner way to do things.

@DeckerMMIV
Copy link
Owner Author

The following 'after' plugins in fmcSoilModPlugins.LUA affect the yield (volume) of what CutFruitArea will return:

  • "Volume is affected by percentage of weeds" (line ~187)
  • "Volume is affected by fertilizer(organic)" (line ~220)
  • "Volume is slightly boosted if correct fertilizer(synthetic)" (line ~266)
  • "Volume is affected by soil pH level" (line ~339)

However, slurry will be the only option to increase the fertilizer-level on a field of grass, as (solid)manure has the requirement of being cultivated/ploughed into the ground. And cultivating/ploughing will remove any grass that is already growing there.

@upsidedownLS13
Copy link

Thats good to know. So there is no immediate need for me to do something about the mowing mod.

soilMod compatible greenFertilizer is updated here: http://www.modhoster.de/mods/grundunger-mod

@webalizer-gt
Copy link
Contributor

I read and studied your sample plugins for several hours but i´m not able to get it together with choppedStraw. As i stated before i´m not the best scripter...
In choppedStraw i should use global.lua for the plugin functions i think. How to preserve the "normal" behaviour if there´s no SoilMod?
Do i need a before or after plugin to achieve fertilization when cultivating/plowing choppedStraw?

The fmcSoilModPlugins.fmcUpdateFmcFoliage from your own plugins should be the base for what i need?

regards
tom

@DeckerMMIV
Copy link
Owner Author

@webalizer-gt - The sample plugins are not easy to understand, I know. Trying to grasp what kind of changes SoilMod have done to the Utils. functions, and then how they fit into a "plugin" will be quite difficult to comprehend.

First of, you have to figure out how you want your own mod to work with and/or without SoilMod being present. Either you could make two mods; one that works without SoilMod, and one that requires SoilMod. - But that may confuse players, that there are "two mods for the same thing", and they will most likely just put both of the .ZIP file into their MODS folder, thereby causing a mod-conflict.

Or you could put code into your register.lua, which will only append your special extra lines to updateDestroyCommonArea and updateSowingArea if SoilMod did not "call you" asking for your plugins. - Something like... (Disclaimer: I have not tested the below pseudo-code, if it work as I think it should)
register.lua:

-- Register this mod for callback from SoilMod's plugin facility
getfenv(0)["modSoilModPlugins"] = getfenv(0)["modSoilModPlugins"] or {}
table.insert(getfenv(0)["modSoilModPlugins"], fmcSoilModPlugins)
--
ChoppedStraw_Register.initialized = false
ChoppedStraw_Register.soilModPresent = false
--
function ChoppedStraw_Register.soilModPluginCallback(soilMod)
  -- Mark that SoilMod has "called us"
  ChoppedStraw_Register.soilModPresent = true
  -- <Add plugins to SoilMod. Illustrated later.>
end

function ChoppedStraw_Register:update(dt)
  if not ChoppedStraw_Register.initialized then
    ChoppedStraw_Register.initialized = true -- Only initialize ONCE.
    -- If SoilMod did not "call us", then do it "the old way"...
    if not ChoppedStraw_Register.soilModPresent then
      -- <do the append to Utils.updateDestroyCommonArea and Utils.updateSowingArea here.>
    end
  end
end;

global.lua:

-- Remove appending to Utils.updateDestroyCommonArea and Utils.updateSowingArea 
-- from this file, as it will be done in the ChoppedStraw_Register:update() function.
-- But keep your Utils.updateStrawHaulmArea as it is unique/new.

With the above completed, your mod should be able to work both with and without SoilMod being present.

Next issue... How to 'plug-in' ChoppedStraw's feature into SoilMod. - Let us ignore the "fertilization by chopped straw" for now.

From what I see in your global.lua, it adds its own unique/new function Utils.updateStrawHaulmArea which only ChoppedStraw-mod knows about. This can not be added as a "plugin" to SoilMod (as of now), so it is kept as it is.

But your additions to Utils.updateDestroyCommonArea and Utils.updateSowingArea - where you want to destroy any 'chopped straw' in the foliage when a cultivator/plough or sowing-machine affects it - can be added as a plugin to SoilMod. And this could be added in different ways, depending on how much knowledge you have regarding "what actually happens when calling these functions."

... I was here going to try illustrating the not-so-optimal addition of plugins, but found that it was going to fill too much. So I will instead show the way I would add plugin for "destroy any 'chopped straw'".

Since your additions to Utils.updateDestroyCommonArea basically just destroys/removes from the "Chopped..." foliage-layers, it is more optimal in SoilMod to add these foliage-layer's id-numbers to the list of "dynamic foliage layers" that gets destroyed during Utils.updateDestroyCommonArea:

function ChoppedStraw_Register.soilModPluginCallback(soilMod)
  [...]
  if g_currentMission.fruits[FruitUtil.FRUITTYPE_CHOPPEDSTRAW] then
    soilMod.addDestructibleFoliageId(g_currentMission.fruits[FruitUtil.FRUITTYPE_CHOPPEDSTRAW].preparingOutputId)
  end
  -- and likewise for the next two types.

The above won't affect when sowing, so there is a need to add plugin(s) for Utils.updateSowingArea, which will be a bit different.

function ChoppedStraw_Register.soilModPluginCallback(soilMod)
  [...]
  -- Helper function, to extract the foliage-layer-id if available
  local function getFruitFoliageLayerId(fruitId)
    if g_currentMission.fruits[fruitId] ~= nil then
      if g_currentMission.fruits[fruitId].preparingOutputId ~= nil
      and g_currentMission.fruits[fruitId].preparingOutputId ~= 0 then
        return g_currentMission.fruits[fruitId].preparingOutputId;
      end
    end
    return nil
  end

  -- Only add plugin for fruit-type, if fruit-type exist and has foliage-layer
  if getFruitFoliageLayerId(FruitUtil.FRUITTYPE_CHOPPEDSTRAW) ~= nil then
    local layerId = getFruitFoliageLayerId(FruitUtil.FRUITTYPE_CHOPPEDSTRAW)
    local numChannels = getTerrainDetailNumChannels(layerId)
    soilMod.addPlugin_UpdateSowingArea_before(
      "ChoppedStraw",
      30,
      function(sx,sz,wx,wz,hx,hz,dataStore)
        setDensityParallelogram(layerId, sx,sz,wx,wz,hx,hz, 0, numChannels, 0)
      end
    )
  end
  -- and the same for the next two types.

By early on determining if a "fruit" and its corresponding foliage-layer is not available, then there is no need to add a "plugin" for that. This should be better than having an if-then-(else)-if-then-(else)-... which need to constantly be checked for every call to Utils.updateSowingArea.

There are more to it, but I suggest you take a look through fmcSoilModPlugins.LUA too, to get inspiration and perhaps some ideas.

For the "fertilization by chopped straw" you want to add, I will explain that at a later time how to add that as a plugin to SoilMod.

@webalizer-gt
Copy link
Contributor

Hi!

First of all: Thank you for helping so much! I really appreciate that.

I modified ChoppedStraw with the code you provided.
Functionality WITHOUT SoilMod is given and tested. But with SoilManagement in mod folder i get an error while plugins are loaded:

SoilMod: Included foliage-layer for "destruction" by plough/cultivator/seeder: 'choppedStraw_haulm', id=5797, numChnls=1
SoilMod: Included foliage-layer for "destruction" by plough/cultivator/seeder: 'choppedMaize_haulm', id=5795, numChnls=1
SoilMod: Included foliage-layer for "destruction" by plough/cultivator/seeder: 'choppedRape_haulm', id=5796, numChnls=1
SoilMod: Plugin for update-sowing-area(before): (31) Remove chopped straw
SoilMod: Plugin for update-sowing-area(before): (32) Remove chopped maize
SoilMod: Plugin for update-sowing-area(before): (33) Remove chopped rape


ERROR! Problem occurred during SoilMod's initial set-up. - Soil Management will NOT be available!

Of course i commented out your support for choppedstraw in fmcSoilModPlugins.lua

@DeckerMMIV
Copy link
Owner Author

Oops. My bad. - I forgot that the call-back function soilModPluginCallback must return a boolean, where true means success. - If not, then SoilMod will think something went wrong.

I have just now updated the sample-plugins with it. @19cb6d5208deaebc68bc9a30e1816d8e3aa17e2f

@webalizer-gt
Copy link
Contributor

So, finally i got everything to work as expected. Thanks to your help i was able to change it step by step to what i want. It´s not final because i have to decide if sowing machines should work the same way as cultivator and plough - at the moment i think not.
You may have a look here

Regarding the sowing machine i got a question: is it somehow possible to differentiate if a sowing machine uses direct planting for use with soilmod?

@DeckerMMIV
Copy link
Owner Author

Sowing machine direct planting, it is a boolean variable; dataStore.useDirectPlanting

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants