Jump to content

[zero]is there no way for unit:setlevel to target player's pet?


psyk3d

Recommended Posts

21 hours ago, Rochet2 said:

Try this:


local pet = player:GetMap():GetWorldObject(player:GetPetGUID())
if pet then
    pet:SetLevel(10)
end

 

this is brilliant, thank you.

So what you did here is that you saved the pet as a world object in the pet variable, using it's GUID. And since Unit inherits WO functions, you were able to use the SetLevel function on the pet world object?

Also, is it ok to feel like this is an advanced method of doing something, that I am completely unaware of (im relatively new here). On another note, how much can be accomplished with Eluna without the need to tweak the engine? and what are it's limits? and how does one go about accessing other C++ functions in Lua?

In short, thanks and how far do "hooks" go?

Link to comment
Share on other sites

1 hour ago, psyk3d said:

So what you did here is that you saved the pet as a world object in the pet variable, using it's GUID. And since Unit inherits WO functions, you were able to use the SetLevel function on the pet world object?

Also, is it ok to feel like this is an advanced method of doing something, that I am completely unaware of (im relatively new here). On another note, how much can be accomplished with Eluna without the need to tweak the engine? and what are it's limits? and how does one go about accessing other C++ functions in Lua?

In short, thanks and how far do "hooks" go?

Yes that is what was done. GetWorldObject can find entities that inherit WorldObject class. However there is no need to call ToPet or similar after getting the worldobject, because that is done automatically by eluna. This is true for any object in Eluna. It should automatically have all methods available.
Read https://github.com/ElunaLuaEngine/Eluna/blob/master/docs/IMPL_DETAILS.md#automatic-conversion
And this too https://github.com/ElunaLuaEngine/Eluna/blob/master/docs/USAGE.md if you havent yet.
Note that some of the documentation links may still be dead. refer to http://elunaluaengine.github.io/

Im not entirely sure what you refer to with "this is an advanced method". We simply called a bunch of functions in succession. In C++ the code would look very similar and that carries to lua quite a bit. If you were looking for GetPet or a similar function, such is not implemented, at least yet. And im not sure if it will be since GetPetGUID exists. On the top of my head I feel like it may have existed at a point in time, but was removed due to a complication with the implementation at the time.

"How much can be accomplished" is not a good question. However to answer the question in a way:
People keep asking about things that would really require changing the functionality of the entire core, which is relatively obviously out of reach from Eluna. Even with normal c++ script you would not most of the time be able to do those things and would need to edit the core functionality.

Another thing that people may find limiting is that a function may not just be implemented (yet). In many cases people look for functions that dont even exist in C++.

And like Talendrys said, you can go look yourself if you are interested in the hooks.
And about crashes, if you manage to crash the core with Eluna (lua), you should post an issue about it to our github issue tracker or on mangos issue tracker.

Link to comment
Share on other sites

2 hours ago, Rochet2 said:

Yes that is what was done. GetWorldObject can find entities that inherit WorldObject class. However there is no need to call ToPet or similar after getting the worldobject, because that is done automatically by eluna. This is true for any object in Eluna. It should automatically have all methods available.
Read https://github.com/ElunaLuaEngine/Eluna/blob/master/docs/IMPL_DETAILS.md#automatic-conversion
And this too https://github.com/ElunaLuaEngine/Eluna/blob/master/docs/USAGE.md if you havent yet.
Note that some of the documentation links may still be dead. refer to http://elunaluaengine.github.io/

Thank you.

Quote

Im not entirely sure what you refer to with "this is an advanced method". We simply called a bunch of functions in succession. In C++ the code would look very similar and that carries to lua quite a bit. If you were looking for GetPet or a similar function, such is not implemented, at least yet. And im not sure if it will be since GetPetGUID exists. On the top of my head I feel like it may have existed at a point in time, but was removed due to a complication with the implementation at the time.

I'm sorry what I meant to say is that it's really been a while since I touched any code and I'm just getting back into the world of wow emulation. It is also because I did not know what to do with a GUID or what it was until you told me :)

Quote

"How much can be accomplished" is not a good question. However to answer the question in a way:
People keep asking about things that would really require changing the functionality of the entire core, which is relatively obviously out of reach from Eluna. Even with normal c++ script you would not most of the time be able to do those things and would need to edit the core functionality.

Another thing that people may find limiting is that a function may not just be implemented (yet). In many cases people look for functions that dont even exist in C++.

I hear you. The reason I asked this question is actually not what you think. I have some working C++ scripts that I used with MaNGOS and I was wandering how much of them can be "converted" to Lua. I was looking to see how I would call something like 

((Pet*)pet)->SetLoyaltyLevel(BEST_FRIEND);

in Eluna, but it seems the best option will be to re-implement the whole function in my Lua script, if I find that it is possible.

Link to comment
Share on other sites

On 22/03/2017 at 6:43 PM, psyk3d said:

Thank you.

I'm sorry what I meant to say is that it's really been a while since I touched any code and I'm just getting back into the world of wow emulation. It is also because I did not know what to do with a GUID or what it was until you told me :)

I hear you. The reason I asked this question is actually not what you think. I have some working C++ scripts that I used with MaNGOS and I was wandering how much of them can be "converted" to Lua. I was looking to see how I would call something like 


((Pet*)pet)->SetLoyaltyLevel(BEST_FRIEND);

in Eluna, but it seems the best option will be to re-implement the whole function in my Lua script, if I find that it is possible.

So, when a method is not exposed to Eluna, in this case SetLoyaltyLevel, there are several ways to implement similar functionality. First of all, we should see how SetLoyaltyLevel is actually handled in the core;

https://github.com/mangoszero/server/blob/756c8ff79723f3bf46eccc4bb819fc0e30ff3cc1/src/game/Object/Pet.cpp#L737

As you can see in the above link, SetLoyaltyLevel is handled by setting one of the pets' Byte values. While SetLoyaltyLevel in and of itself is not an Eluna method, SetByteValue however is.

http://www.elunaengine.com/Object/SetByteValue.html

As you can see from that link, SetByteValue as Eluna uses it is exactly the same as the way the core uses it. Thus we can re-create the functionality in Eluna as long as we also have the same values as passed to the core function;

Before we start recreating the functionality by using Elunas' SetByteValue, we need to know the correct values to pass to the method. In this case we need Index, Offset and Value.

 

So the first value (index), which is the unit byte we want to edit, can be found here.
https://github.com/mangoszero/server/blob/d0a4af096e528533044e7029446d1c5c9e98a16c/src/game/Object/UpdateFields.h#L137
This is written in hex. Eluna does support using hex values as well, though for simplicity I usually convert it to a decimal. 

UNIT_FIELD_BYTES_1 = 0x84 + OBJECT_END (0x06)

This means we have 0x84+0x06. In decimal this would mean UNIT_FIELD_BYTES_1 = 138.

 

The next value, which is the offset, is 1. This can simply be copied directly from the SetLoyaltyLevel function.

 

Third and final value, as shown in your own example, is BEST_FRIEND. This is defined in the loyalty level enum as shown below.
https://github.com/mangoszero/server/blob/d0a4af096e528533044e7029446d1c5c9e98a16c/src/game/Object/Pet.h#L80
The value we want is BEST_FRIEND, as shown in the above link = 6.

 

Now, with all the values, we can use Rochet's script as a template for how we retrieve the actual pet, and how we change its loyalty using all of the above values we have determined is needed;

local pet = player:GetMap():GetWorldObject(player:GetPetGUID())
if pet then
    pet:SetByteValue(138, 1, 6) -- Sets pet loyalty to best friend
end

This should set your pets loyalty level to best friend. I have not tested it though, this was more of an example as to how functionality can be implemented in Eluna without having to modify the engine itself.

 

PS: You should probably not use "magic numbers" like I have shown above, as they should be localized properly. Numbers without definition wouldn't make any sense to anyone else trying to read your code.

Link to comment
Share on other sites

On 3/24/2017 at 9:08 PM, Foereaper said:

So, when a method is not exposed to Eluna, in this case SetLoyaltyLevel, there are several ways to implement similar functionality. First of all, we should see how SetLoyaltyLevel is actually handled in the core;

https://github.com/mangoszero/server/blob/756c8ff79723f3bf46eccc4bb819fc0e30ff3cc1/src/game/Object/Pet.cpp#L737

As you can see in the above link, SetLoyaltyLevel is handled by setting one of the pets' Byte values. While SetLoyaltyLevel in and of itself is not an Eluna method, SetByteValue however is.

http://www.elunaengine.com/Object/SetByteValue.html

As you can see from that link, SetByteValue as Eluna uses it is exactly the same as the way the core uses it. Thus we can re-create the functionality in Eluna as long as we also have the same values as passed to the core function;

Before we start recreating the functionality by using Elunas' SetByteValue, we need to know the correct values to pass to the method. In this case we need Index, Offset and Value.

 

So the first value (index), which is the unit byte we want to edit, can be found here.
https://github.com/mangoszero/server/blob/d0a4af096e528533044e7029446d1c5c9e98a16c/src/game/Object/UpdateFields.h#L137
This is written in hex. Eluna does support using hex values as well, though for simplicity I usually convert it to a decimal. 

UNIT_FIELD_BYTES_1 = 0x84 + OBJECT_END (0x06)

This means we have 0x84+0x06. In decimal this would mean UNIT_FIELD_BYTES_1 = 138.

 

The next value, which is the offset, is 1. This can simply be copied directly from the SetLoyaltyLevel function.

 

Third and final value, as shown in your own example, is BEST_FRIEND. This is defined in the loyalty level enum as shown below.
https://github.com/mangoszero/server/blob/d0a4af096e528533044e7029446d1c5c9e98a16c/src/game/Object/Pet.h#L80
The value we want is BEST_FRIEND, as shown in the above link = 6.

 

Now, with all the values, we can use Rochet's script as a template for how we retrieve the actual pet, and how we change its loyalty using all of the above values we have determined is needed;


local pet = player:GetMap():GetWorldObject(player:GetPetGUID())
if pet then
    pet:SetByteValue(138, 1, 6) -- Sets pet loyalty to best friend
end

This should set your pets loyalty level to best friend. I have not tested it though, this was more of an example as to how functionality can be implemented in Eluna without having to modify the engine itself.

 

PS: You should probably not use "magic numbers" like I have shown above, as they should be localized properly. Numbers without definition wouldn't make any sense to anyone else trying to read your code.

Thank you for the extended explanation, I really appreciate it. This does work by the way. I have some questions on what you did here, but I'm gonna try and do my research such that I would ask them properly.

Link to comment
Share on other sites

20 hours ago, Talendrys said:

Don't hesitate :)

Tal'

Thanks again, so here goes;

(After some hours of looking into the core)

To my understanding, what you did here is that you looked at void Pet::SetLoyaltyLevel(LoyaltyLevel level) which happened to have a single function,
 SetByteValue(UNIT_FIELD_BYTES_1, 1, level) already available in Eluna, took 3 arguments, UNIT_FIELD_BYTES_1 , 1 (a constant), and a (variable?) of type LoyaltyLevel the value of which was set to 6 as requested. 

UNIT_FIELD_BYTES_1's value is 0x84 + 0x06, which we could have left as is, but decided to convert it to decimal instead. So filling in those 3 values in pet:SetByteValue would yield the requested result. And I understand that those numbers should be localized to improve readability.

Now to a huge mess;

I took your example and tried to accomplish something similar with another method, void Pet::LooseHappiness()

which ended up being way more complex. See what I tried to do here is that I wanted to utilize the ModifyPower function to rather increase the pet's happiness, and that didn't go very well,..

Looking at ModifyPower, I saw that there is no such thing in Eluna, so I dug deeper to find the underlying function that was, and so I came across 
SetUInt32Value(index, uint32(value)), which happens to be implemented in Eluna, and also happens to take the same arguments.

I got here by going through the definition of ModifyPower here, which led me to SetPower, which led me to SetStatInt32Value, which led me to SetUInt32Value.

So I started to calculate my way through the arguments that I needed to pass (disregarding some of the conditions, as my objective does not require them), going all the way down to SetUInt32Value. Now this is where things got really messy, as I cannot seem to get some values figured out, like addvalue which required the return value of GetLoyaltyLevel() (which does not seem to be a mere "6").

Going down GetLoyaltyLevel(), I came across GetByteValue, the point at which I decided the this should not be done manually.

I figured it would be a lot easier to just compile the core with a tiny script to output these values for me in the MaNGOS console window (right?), as soon as I have the time.

Am I doing this completely wrong? Am I even going after the right function? I have no idea.

Now I might be a complete noob, as programming is in no way my field of expertise, so please be gentle ^_^. I do this as a hobby and am very interested in learning more about Eluna.

Edit: I don't know how I missed SetPower in Eluna, guess sometimes you look too close at something, you end up missing the important stuff,..

Link to comment
Share on other sites

1 hour ago, psyk3d said:

I got here by going through the definition of ModifyPower here, which led me to SetPower, which led me to SetStatInt32Value, which led me to SetUInt32Value.

Eluna has SetPower so stop there.

1 hour ago, psyk3d said:

Now this is where things got really messy, as I cannot seem to get some values figured out, like addvalue which required the return value of GetLoyaltyLevel() (which does not seem to be a mere "6").

You can code it by using http://www.elunaengine.com/Global/bit_rshift.html or http://www.lua.org/manual/5.2/manual.html#pdf-bit32.rshift

local addvalue = bit_rshift(140, GetLoyaltyLevel()) * 125 -- assume GetLoyaltyLevel is implemented elsewhere

 

1 hour ago, psyk3d said:

I figured it would be a lot easier to just compile the core with a tiny script to output these values for me in the MaNGOS console window (right?), as soon as I have the time.
Am I even going after the right function? I have no idea.

Im not sure what you refer to with the values. You mean the addvalue values? That could be possible too.

 

I made a complete example of the conversion here, its basically just converted the c++ to lua: https://pastebin.com/PhbRd97v
I think though that the modifypower could possibly be added as an eluna function.

Link to comment
Share on other sites

9 hours ago, Rochet2 said:

Eluna has SetPower so stop there.

You can code it by using http://www.elunaengine.com/Global/bit_rshift.html or http://www.lua.org/manual/5.2/manual.html#pdf-bit32.rshift


local addvalue = bit_rshift(140, GetLoyaltyLevel()) * 125 -- assume GetLoyaltyLevel is implemented elsewhere

 

Im not sure what you refer to with the values. You mean the addvalue values? That could be possible too.

 

I made a complete example of the conversion here, its basically just converted the c++ to lua: https://pastebin.com/PhbRd97v
I think though that the modifypower could possibly be added as an eluna function.

Thank you, I have learned much from this.

I feel that I can now do a lot more with Eluna, thanks to the example you provided.

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. Privacy Policy Terms of Use