Get killer name

Hi,
I need some help for my script : I create a simple derma openable with a console command and in it i would like to see ( if the player is dead when he open it ) the killer name and the weapon which kill him.
I tried this :


local killer = ply:GetAttacker() 
local killwith = ply:GetInflictor()
-- and then to test if it works
print( killer )
print( killwith )

But it doens’t work


attempt to call method 'GetAttacker'

Can somebody help me please ? :’[

That only works with CTakeDamageInfo, which you can get in

GM:DoPlayerDeath,

GM:EntityTakeDamage, and

GM:ScalePlayerDamage.
Ply (assuming ply is a player entity) is not a CTakeDamageInfo object, so that’s why it doesn’t work.

[editline]17th August 2017[/editline]

You could display the killer on the menu by using networking to send the killer entity to the killed player from a DoPlayerDeath hook.
However, this is a pretty annoying method. I just can’t think of a better one.

Yes that’s exaclly what i want to do but I don’t know how to use Networking…

In the DoPlayerDeath hook that was posted earlier, send a message containing the killer to the victim. Then on the client save the killer in a variable that you can read in your derma screen

Ok I will try with this thank you ! :slight_smile:

How, with the Net Usage, can I send information from server to client ? I don’t understand very well the library… :confused:

Think of it like 2 people having a conversation.

Person 1 (the server) and person 2 (the client).

Person 1 want’s to say something, so they open there mouth (net.Start) and, for example, say a number (net.WriteInt) and then confirm who there saying it to (net.Send).
Person 2 will listen for when person 1 say’s something relevant (net.Recieve) and will note down what they say (net.ReadInt).

For the scenario above to work it does require a few extra details which are explained in the code below.

Here is how it would look:



-- SERVER
util.AddNetworkString("message") -- make sure your names are unique and descriptive of what they do

local number = 5 -- The number the server will say

net.Start("message") -- Where the server open its mouth
   net.WriteInt(number, 32) -- Where the server says the number, as well as the amount of bits it will use
net.Send(ply) -- Where it defines who will receive this message

----------------------------------------------------------------------

-- CLIENT
net.Recieve("message", function() -- Where the client hears the message
   local number = net.ReadInt(32) -- Where the client notes down the number, you MUST have the same bitcount as used in the server code
end)

Not all data types need to have a bit count defined, check the wiki for the relevant one.

A more complex emample is where we send a message from the client to the server and then back to the client.

**
Person 1 (the server) and person 2 (the client).**

Person 2 would say (net.Start) a message (net.WriteString) to the Person 1 (net.SendToServer).
Person 1 would listen out for the message (net.Recieve) and note down what they have to say (net.ReadString).
Person 2 would then respond (net.Start) with saying the same message (net.WriteString) back to Person 1 (net.Send).
Person 1 would then say the received message in the console (print)



-- CLIENT
local button = vgui.Create("DButton") -- Makes a interface
button:SetPos(0,0)
button:SetSize(50,50)
button:SetText("Sends message to server")
button.DoClick = function() -- When the button is pressed it runs the following code
   net.Start("messageName") -- Client opens its mouth
      net.writeString("hi") -- Client says its message
   net.SendToServer() -- Client sends it to the server
end

--------------------------------------------------------------

-- SERVER
util.AddNetworkString("messageName")  -- make sure your names are unique and descriptive of what they do
util.AddNetworkString("messageName2") -- make sure your names are unique and descriptive of what they do

net.Recieve("messageName", function(_, ply) -- Server hears what the client says and gets there details ( being ply) 
   local message = net.ReadString() -- Server notes down what it says 

   net.Start("messageName2") -- Server opens its mouth 
      net.WriteString(message) -- Server repeats what it noted down earlier 
   net.Send(ply) -- Server defines who its speaking to (it knows this because ply is defined when the original net message was sent) 
end)

--------------------------------------------------------------
-- CLIENT (continued)

net.Recieve("messageName2", function() 
   local message = net.ReadString() 

   print(message) -- Prints "hi" in console 
end)


I hope this explanation helps :slight_smile:

Thank’s very munch for your anwser !
And for my script, the server will have to open the mouse (net.Start) in the Hook OnDeath and say (net.WriteString) the attacker and the inflictor ?
And then the client will have to listen (net.Recieve) and write the informations (net.ReadString) ?

Somethink like this :



util.AddNetworkString("message")


function GM:PlayerDeath( victim, inflictor, attacker )

   net.Start("message")

   net.WriteInt(attacker, 32)
   net.WriteInt(inflictor, 34)

   net.Send(ply)

end 
---------------------------------------------------------------------
-- CLIENT


net.Recieve("message", function() 
   local killer = net.ReadInt(32) 
   local killwith =net.ReadInt(34) 
end)


?

Okay here’s what you had:



util.AddNetworkString("message")


function GM:PlayerDeath( victim, inflictor, attacker )

   net.Start("message")

   net.WriteInt(attacker, 32)
   net.WriteInt(inflictor, 34)

   net.Send(ply)

end 
---------------------------------------------------------------------
-- CLIENT


net.Recieve("message", function() 
   local killer = net.ReadInt(32) 
   local killwith =net.ReadInt(34) 
end)


Here’s it fixed up:



util.AddNetworkString("somebodyDroppedDeadFred")


function GM:PlayerDeath( victim, inflictor, attacker )

   net.Start("somebodyDroppedDeadFred") -- renamed for clarity
   net.WriteEntity(attacker) -- We don't want to send an integer, let's send instead the attacker entity.
   net.WriteEntity(inflictor) -- Let's send the inflictor entity (for local translation)
   net.Send(victim) -- ply isn't defined on the server, victim is
end 
---------------------------------------------------------------------
-- CLIENT


net.Receive("somebodyDroppedDeadFred", function() 
   local killer = net.ReadEntity() -- we can read them off like this, I didn't think ReadEntity needed arguments
   local killwith = net.ReadEntity() 

   chat.AddText("You were killed by " ..killer:Nick().. " with a " .. killwith:GetName())
end)


Okay thank’s very munch everybody, but when i try he say :


attempt to concatenate global 'killwith' (a nil value)


You got the server-client logic right, but you got hooks muddled up and I don’t think you are familiar with datatypes and bits!

So firstly, GM:PlayerDeath is NOT a hook. You shouldn’t touch this unless you are making a gamemode or you know what you are doing.

A hook is like a listener. It To run code every time a hook is run you will use hook.Add. An example if what a hook will look like is:


hook.Add("hookName", "uniqueHookName", function(argument1, agument2) -- (limited to how many the hook has)
-- your code here
end)

You are trying to do is listen to the PlayerDeath hook. You would simple replace “hookName” with “PlayerDeath” and make sure you have the correct arguments.


hook.Add("PlayerDeath", "uniqueHookName", function(victim, weapon, attacker) -- (limited to how many the hook has)
-- your code here
end)

Next you want to send the data to the client. To know what datatype we are going to use we need to know what datatypes are. I made a table of the common datatypes used (there are more but its up to you to research):

If you are even unsure of the datatype of something you can use type() to find out. For example print(type(“hi”)) and it will return string.



print(type("hi")) -- returns "string"


To know what datatypes the arguments are it says on the wiki page of the hook you are calling.

and also

So going back to sending the message to the client, we want to send the data as a entity datatype (we can send player data as an entity datatype as a player is a entity). This is what it will look like:



hook.Add("PlayerDeath", "uniqueHookName", function(victim, weapon, attacker) -- (limited to how many the hook has)
   net.Start("name")
      net.WriteEntity(victim)
      net.WriteEntity(attacker)
   net.Send(victim) -- depends on who you want to send this message to
end)


Another thing I noticed is on your second WriteInt you put 34 bits



local killwith =net.ReadInt(34)


The maximum is 32 bits. If you are unsure of what bits I highlt advise some research in your own time!

Edit:
Milkshaker got to the code before me but I still give some explanations so I wont ninja :slight_smile:

When you use net.WriteEntity you don’t send the entity, you send the entity’s index. net.Read/WriteEntity are Lua functions, you can check the source here.

Very true - I wasn’t thinking 100%. Thanks for spotting that :happy:

He already say


attempt to concatenate global 'killwith' (a nil value)

in the client side.
But it make this like you :



net.Receive("DeathInfo", function() 
	   local killer = net.ReadEntity()
	   local killwith = net.ReadEntity() 
end)



Where are you using killwith? That code shouldn’t cause an error.

Did i need to use the killwith and killer in the net.Receive ?

You should read up on scoping. It will probably help you a lot in the future too.

I know how to use a function() but is net.Receive no… :confused: