Posts: 313
Threads: 32
Joined: Feb 2012
Thanks: 98
Given 14 thank(s) in 13 post(s)
06-05-2012, 11:34 PM
Okay, here's the deal:
I'm getting serious and going to use MCS seriously. I mean, on a public server. Thus I got to write several plugins, for which I would like to have several new hooks. Such as:
OnCrafting( cCraftOperation )
By cCraftOperation I mean some way to get cPlayer (who's crafting) and cItem of recipe result, that was recognized by MCS. This hook should return cItem as well (the one that will be displayed as crafting result and will be grabbed by player).
What for:
For example, I would like to make "classes" - some classes could craft diamond instruments, some couldn't. With such a hook I can easily change diamond axe input into iron axe output. Or I can take into account the fact that player is standing in special "area" that allows him to craft items with full HP instead of damaged.
If plugin returns nil, then default recipe is used (such behavior could be used for "exp for crafting" plugin)
LateTick()
This one could be really handy for organizing plugin<->plugin interactions through .ini-s. Or you can add some structures for shared data access. (Oh, I just got an idea that cIniFile could be such a structure, am I right? I mean, it stores all .ini keys and values in RAM till it will be written, right?)
OnChunkPopulate( cChunk or something like that )
What for: adding new blocks, changing existing population methid (Yessss, strategic oregen!)
Posts: 6,485
Threads: 176
Joined: Jan 2012
Thanks: 131
Given 1075 thank(s) in 852 post(s)
06-06-2012, 12:00 AM
(This post was last modified: 06-06-2012, 12:39 AM by xoft.)
OnCrafting:
- the internal C++ implementation uses an array of cItems, together with the dimensions, to describe the crafting grid. It seems easier to use than a custom object just for the callback.
- the internal C++ implementation not only provides the output item, it also "processes" the recipe - it removes the ingredients that the recipe specifies, from the crafting grid. That's the only way to specify recipes that take more items in a single slot (a currently unused feature, but still present in the code)
- I could probably write this hook, I'm not too sure on Lua interfacing yet, but I think there's enough sample code for me to manage
LateTick:
- I have no idea what you mean
- When should it be called, who should call it, what parameters?
OnChunkPopulate:
- Called only for freshly generated terrain, or for a chunk loaded from storage as well?
- If you want to change generator, you should split this callback into two - one called before the actual generator kicks in, one after. Why let it generate terrain, if you're gonna overwrite it all?
- I could probably write both of these. The post-generation is much easier; pre-generation will be more tricky, due to the data transfer.
Seems a bit more difficult than anticipated - chunks can be generated even before the plugin subsystem is fully initialized - when the world is generating the spawn for the first time. This will need some extra care.
Posts: 6,485
Threads: 176
Joined: Jan 2012
Thanks: 131
Given 1075 thank(s) in 852 post(s)
Wow, I'm good
OnChunkGenerated hook is available in Rev 558. It is called by the chunk generator each time a new chunk is generated. At the time of calling, the chunk is already valid in cWorld, so it can be modified directly using cWorld's methods (note that they are notoriously slow, you don't want to query an entire chunk block-by-block!)
Here's a quick sample plugin that uses that hook. It logs every chunk generated and then places a glowstone block at the XZ center of each chunk in Y=40:
Code: function Initialize( Plugin )
PLUGIN = Plugin
Plugin:SetName( "GeneLog" )
Plugin:SetVersion(1)
PluginManager = cRoot:Get():GetPluginManager()
PluginManager:AddHook(Plugin, cPluginManager.E_PLUGIN_CHUNK_GENERATED)
LOG( "Initialized " .. Plugin:GetName() .. " v." .. Plugin:GetVersion() )
return true
end
function OnChunkGenerated(World, ChunkX, ChunkZ)
LOG("Lua GeneLog: Generated chunk [" .. ChunkX .. ", " .. ChunkZ .. "] in world " .. World:GetName() .. ".")
World:SetBlock(ChunkX * 16 + 8, 40, ChunkZ * 16 + 8, E_BLOCK_GLOWSTONE, 0)
end
Posts: 313
Threads: 32
Joined: Feb 2012
Thanks: 98
Given 14 thank(s) in 13 post(s)
LateTick:
Called after all Tick() are done... I suppose, server is calling Tick(), right? So, it should call LateTick() too
Parameters - same deltaTime as in Tick()
OnChunkPopulate:
Called only for freshly generated terrain, AND for regenerated as well. Not for loaded from storage.
Quote:If you want to change generator, you should split this callback into two - one called before the actual generator kicks in, one after. Why let it generate terrain, if you're gonna overwrite it all?
Fair point. Maybe OnChunkWillPopulate() (if returned true - no generator work needed then, if false - generator continues) plus OnChunkPosPopulate() (no difference between false and true returned)
Quote:chunks can be generated even before the plugin subsystem is fully initialized
Well, then ChunkWorx can regenerate spawn area as well (because it seems to be the only zone which can be generated before plugin system initialisation)
Posts: 6,485
Threads: 176
Joined: Jan 2012
Thanks: 131
Given 1075 thank(s) in 852 post(s)
I still can't quite fathom why you'd need anything like LateTick() - isn't Tick() enough? And if it isn't, would one LateTick() be enough, or soon there'll be demand for LateLateTick(), LateLateLateTick(), ...
(06-06-2012, 01:29 AM)Taugeshtu Wrote: Maybe OnChunkWillPopulate() (if returned true - no generator work needed then, if false - generator continues) plus OnChunkPosPopulate() (no difference between false and true returned) A few good frameworks use the schema "OnDoing", "OnDone", so I'm sticking to names "OnChunkGenerated" (already implemented, called after the chunk is generated) and "OnChunkGenerating" (called just before generating)
Why would you need two "OnChunkGenerating", again? One is IMHO enough - it can write all chunk data instead of the generator, and if it returns true, the generator will skip builtin generating. It also needn't modify the data and be used as a notification only; return false in that case.
Posts: 313
Threads: 32
Joined: Feb 2012
Thanks: 98
Given 14 thank(s) in 13 post(s)
LateTick isn't needed right now, I thought that I could use this that way:
One plugin calculates some information about player, writes it into .ini. It all happens in Tick()
Another plugin reads that .ini on LateTick(), so it's sure that first plugin had done all it's logic. But then I had that thought about cIniFile class And still had no time to check it...
As for generation:
Two example situations. In first you write your own ore distribution, and completely replaces generator work. In another you simply add some ore type (or structures!), and want to add it AFTER generator (or another plugin!) did all it's job.
I can see no way one hook can handle both situations. I mean, in one case you have to abort generator's work, in another you want to add some changes after it's done. And you can even want to add something BEFORE generator start!
Posts: 6,485
Threads: 176
Joined: Jan 2012
Thanks: 131
Given 1075 thank(s) in 852 post(s)
That would work, but what if the second plugin wanted to communicate something back to the first plugin? Then you'd need a third hook. And a fourth, later. Generally, this is a bad idea, we can come up with something better. At the very least, "OnPluginBroadcast()", which is triggerred whenever a plugin calls a "Broadcast()" method.
Generation: Misunderstanding. I thought you wanted two more hooks, in addition to the OnChunkGenerated(). Now I get it and we're in agreement here, except for the names
This is the generator pseudo-code, as we both want it:
Code: // received another chunk for generating
if (!CallHook("OnChunkGenerating", ChunkData))
{
// Hook didn't generate the chunk, we need to do it ourselves:
GenerateChunkUsingInternal(ChunkData);
}
cWorld->ChunkGenerated(ChunkData); // Send the chunk data to cWorld
CallHook("OnChunkGenerated", ChunkCoords);
Posts: 313
Threads: 32
Joined: Feb 2012
Thanks: 98
Given 14 thank(s) in 13 post(s)
Quote:except for the names
I would be happy even if you would call it OnCallBeetleJuice()
Posts: 1,450
Threads: 53
Joined: Feb 2011
Thanks: 15
Given 120 thank(s) in 91 post(s)
Good, but I wouldn't go with the LateTick. I suggest using a more robust method of inter-plugin communication like the ones already discussed in another thread
Posts: 313
Threads: 32
Joined: Feb 2012
Thanks: 98
Given 14 thank(s) in 13 post(s)
Trying to fill the wiki, run into problems with new hooks. I look into Bindings.cpp:
Code: cPluginManager
constant E_PLUGIN_CHUNK_GENERATED, cPluginManager::E_PLUGIN_CHUNK_GENERATED
constant E_PLUGIN_CHUNK_GENERATING, cPluginManager::E_PLUGIN_CHUNK_GENERATING
constant E_PLUGIN_BLOCK_TO_DROPS, cPluginManager::E_PLUGIN_BLOCK_TO_DROPS
Everything is fine.
Now:
Code: cPlugin
function OnChunkGenerated Plugin_OnChunkGenerated00
And that's it. No OnChunkGenerating, no OnBlockToDrops. Am I missing something, or there's something wrong?
Could someone explain, please?
And, well, since it's about hooks, can someone explain how server behaves when OnCollectItem hook returns true and false?
|