• Hit a wall, cannot find the right hook to use.
    26 replies, posted
Basically I'm trying to change the weapon name externally on both server and client, it works perfectly when spawned manually ( using ulx ent for instance ) but if it's spawned automatically (TTT weapon replacement on round start) it doesn't seem to work (it works, halfway. ) Client: [lua] net.Receive( "rnd_send", function( len ) local x = net.ReadEntity() x.PrintName = net.ReadString() print(x) -- half of the times it prints NULL ENTITY, if spawned manually works all the time print(x.PrintName) end) [/lua] Server [lua] util.AddNetworkString( "rnd_send" ) local function printname() for _, x in pairs(ents.GetAll()) do if x:IsWeapon() and x.Primary then x.PrintName = "facepunch" net.Start( "rnd_send" ) net.WriteEntity( x ) net.WriteString( x.PrintName ) end end end hook.Add( "OnEntityCreated", "facepunch", printname ) [/lua] Any help is appreciated. Ignore the title, I edited the post after I solved an old problem.
What you're doing doesn't make any sense. You can use the Initialize hook and use [URL="http://wiki.garrysmod.com/page/weapons/GetStored"]weapons.GetStored(string weaponClass)[/URL] to override it.
Won't weapons.GetStored change the weapon itself instead of the spawned entity? I want to avoid that, each weapon has a different name (even if it's the same class, the name is randomed from a table)
[QUOTE=arcaneex;42902451]Won't weapons.GetStored change the weapon itself instead of the spawned entity? I want to avoid that, each weapon has a different name (even if it's the same class, the name is randomed from a table)[/QUOTE] If you use weapons.GetStored() it will allow you to change anything on the weapon. Can you try and explain what you're trying to do in greater detail, because changing the name of the weapon can be done with weapons.GetStored()
Okay so I have a table with strings. For every entity which is a weapon ( which is already spawned on the map ) I want to change its name to a random string from the table. Let's say there are total of 4 weapon_mac10 on the map (just a random weapon), it's name is MAC10. I want every weapon_mac10 on the map to have a different name, which is randomly picked from the table. That's why I use ents.GetAll() and not weapons.GetStored, then send the printname which is on the server to the client. I need the printname to be the same on the server and on the client.
Just use the TTT hook "TTTPrepareRound" and then change them all. [lua]if CLIENT then net.Receive( "rnd_send", function() local ent, str = net.ReadEntity(), net.ReadString() if IsValid(ent) and str then ent.PrintName = str end end) else util.AddNetworkString( "rnd_send" ) hook.Add("TTTPrepareRound", "TTTPrepareRound_WNames", function() for _, v in pairs(ents.GetAll()) do if v:IsWeapon() and v.NameTable then v.PrintName = table.Random(v.NameTable) net.Start( "rnd_send" ) net.WriteEntity( v ) net.WriteString( v.PrintName ) net.Broadcast() end end end) end[/lua] Also for the original problem or if that doesn't work do this: Check if the entity is not valid on the client side, then if it is not store it and the function in a table. Hook entities being created on the client side, when any entity is created check and see if that entity is stored in the table ("entity" values are just integers that can be assigned and unassigned at any time but are synchronized with the server) and if so pass the entity to the function stored with it in the table.
It still doesn't send it client-wise, even with your5 code. If I change the hook to OnEntityCreated it still doesn't work but atleast it works when it is manually created. It might actually send it, but it doesn't actually replace it, because all the weapons on the map have their default printname.
You know what might help? If you actually sent the data instead of just writing it. [url]http://wiki.garrysmod.com/page/net/Send[/url]
Already noticed the mistake and fixed it before I posted the results.
Then you're going to have to do something like I said earlier: [lua] local EntityTable_N = {} net.Receive( "rnd_send", function() local ent, str = net.ReadEntity(), net.ReadString() if not ent or not str then return end if IsValid(ent) then ent.PrintName = str else EntityTable_N[ent] = str end end) hook.Add("NetworkEntityCreated", "NetEntity_CheckTable", function(ent) if EntityTable_N[ent] then ent.PrintName = Entity_Table_N[ent] EntityTable_N[ent] = nil end end)[/lua] Also, just a note, looking at the net library reveals that if you try to send the clients an invalid integer for an entity the WriteEntity function will rewrite the unsigned integer as zero. (Basically trying to refrence a dead entity will send NULL Entity, but you could override this by using net.WriteUInt with a 32 bit integer.)
After talking to a guy over steam he mentioned that it could be a problem with [URL="https://developer.valvesoftware.com/wiki/PVS"]PVS[/URL], basically the client does not know that the entity exists therefore it makes it null. I'm going to try use networked vars, if that fails I'll try your way, but there are a lot more values than just print name, just gave that as an example so it might get pretty messy.
I would take the approach Ozymandias suggested, if the entity isn't valid when you receive data for it, queue the data to be applied when the entity is created. But, change 'when the entity is created' to 'when the entity becomes valid', so it would apply as soon as the entity enters the PVS as well. You would need to use a timer instead of a hook, unless it was a Think hook.
Another fix you could try is change the name randomly when they pick it up, and then apply that to that weapon so it retains that name.
Here's something I scripted as an example: [lua] if SERVER then AddCSLuaFile() end local TTT_RandomizeWeapons = { ["weapon_zm_revolver"] = { Name = {"50 CAL OP", "SLEEK REVOLVER"}, Damage = {Min = 50, Max = 100} }, ["weapon_zm_rifle"] = { Name = {"HEADSHAWT GUN", "NO SCOPEZ"}, Damage = {Min = 50, Max = 100} } } hook.Add("OnEntityCreated", "TTTWNC.OnEntityCreated", function(ent) timer.Simple(0, function() if !IsValid(ent) then return end local isRandomWep = TTT_RandomizeWeapons[ent:GetClass()] if !isRandomWep then return end local hasRandWepName = isRandomWep.Name ent.PrintName = (hasRandWepName and table.Random(hasRandWepName)) or (ent.PrintName or "") local hasRandomDamage = isRandomWep.Damage ent.Primary.Damage = ((hasRandomDamage and hasRandomDamage.Min and hasRandomDamage.Max) and (math.random(hasRandomDamage.Min, hasRandomDamage.Max))) or ent.Primary.Damage end) end) [/lua]
[QUOTE=arcaneex;42903946]After talking to a guy over steam he mentioned that it could be a problem with [URL="https://developer.valvesoftware.com/wiki/PVS"]PVS[/URL], basically the client does not know that the entity exists therefore it makes it null. I'm going to try use networked vars, if that fails I'll try your way, but there are a lot more values than just print name, just gave that as an example so it might get pretty messy.[/QUOTE] When an entity is created over the network it shouldn't ever be null (unless another NetworkEntityCreated hook has removed it, or it was removed by code ran in it's Initialize function), because that hook is ran right after the entity is created on the client side in the same tick, and it has to be in the same PVS for it to be created over the network, or be in a state of TRANSMIT_ALWAYS which means that the PVS wouldn't have mattered at all.
Brandon that's pretty much what I have, minus the fact that it's shared. I can make it shared and it'll probably make all my problems go away but wouldn't this pretty much make skids with clientside lua grabbers be able to take everything at once? Also @ozy I tried your solution, it didn't seem to work. If the entity is not valid then obviously it wouldn't have fields like .PrintName or .Primary.Damage so it error'd. I tried updating the network state to TRANSMIT_ALWAYS, doesn't seem to help either. Is currently doing this shared the best option?
You're afraid of someone stealing a Lua file that changes the names on weapons randomly? Also, Garry encrypted the Lua cache that's saved on the client's PC so no "skid" can really do anything about it. "Real Coders" however can decrypt it.
As I said above it's way more than just a print name.
[QUOTE=arcaneex;42912199]As I said above it's way more than just a print name. [IMG]http://cloud-2.steampowered.com/ugc/721995326559435712/C5083CF398D2AB91B5133264AC4CCAC71EC081DA/[/IMG][/QUOTE] That looks awesome. I assume you are using custom weapon base, then why not put the variable editing to SWEP:Initialize?
I don't think I can do that unless I edit the weapon internally, which is a thing I cannot do (technically I can, but I'll need to do that to every weapon pack that exists and then upload it together with the addon, seems silly to me) If I can do it and I'm just not aware how, enlighten me please Also glad you like it :dance: What this is supposed to do is show the above info for everyone weapon, not only the base I use. Took me a long time and a lot of weapon packs being downloaded to make this universal, would be pretty sad if I had to make all this shared and having it stolen/leaked at the first day.
[QUOTE=arcaneex;42911639] Also @ozy I tried your solution, it didn't seem to work. If the entity is not valid then obviously it wouldn't have fields like .PrintName or .Primary.Damage so it error'd.[/QUOTE] I don't know if this helps but I do something very much like this and it works for me, my suggested change on Ozys suggestion. (Done in notepad, this exact code is untested) [lua] --Serverside local function SyncEntityData(ent,client) local data = {} --fill data with whatever you need to send across net.Start("syncmessage") net.WritInt(ent:GetEntIndex(),16) --send the entities ID, not the entitiy itself net.WriteTable(data) net.Send(client) end --Clientside local DataToStore = {} local function ProcessData() for k,v in pairs(DataToStore) local testent = if IsValid(Entity(k)) then --Test the entity, k being the entity id we received from server --the entity finally became valid --store your data into it --remove this entry from DataToStore so we dont process it again end end end timer.Create("SyncEnts", 0.25, 0, ProcessData) local function ReceiveEntData(len,client) local entid = net.ReadInt(16) local entdata = net.ReadTable() DataToStore[entid] = entdata --Store the data under the entities id end net.Receive("syncmessage", ReceiveEntData) [/lua] Then I'd use the function SyncEntityData at the appropriate times, like when a player is spawning - loop each entity and synchronise it.
I'm pretty sure the ID changes on client and server, correct me if I'm wrong. [editline]19th November 2013[/editline] I made everything but the actual panel drawing (client) shared, it works but that's not the best solution for obvious reasons. (Skids with lua grabbers = my script leaked under a minute)
WhiteRabbit you do realize that net.WriteEntity is convenience function for net.WriteUInt( ent:EntIndex(), 32 ) which basically makes sure the entity is valid before sending (which is exactly what I said in my last post.) And they are synchronized.
[QUOTE=arcaneex;42912792]I'm pretty sure the ID changes on client and server, correct me if I'm wrong. [editline]19th November 2013[/editline] I made everything but the actual panel drawing (client) shared, it works but that's not the best solution for obvious reasons. (Skids with lua grabbers = my script leaked under a minute)[/QUOTE] IIRC even if they grab the shared file they can only see the clientside part of it anyway. Stop worrying about your shit getting leaked, because everything will be open source sooner or later.
[QUOTE=brandonj4;42913947]IIRC even if they grab the shared file they can only see the clientside part of it anyway. [/QUOTE] No, files are send the way they are on the server. [IMG]http://puu.sh/5n2ZG.png[/IMG] [IMG]http://puu.sh/5n33k.png[/IMG] Edit: [QUOTE=brandonj4;42913947]Stop worrying about your shit getting leaked, because everything will be open source sooner or later.[/QUOTE] I think leaked code is different from open source code. Anyway you should at least try to make it as hard as possible.
I guess I should cope with the fact it'll get leaked sooner or later, hope it will get some sales before it leaks/starts being shared/sold by others.
[QUOTE=OzymandiasJ;42913482]WhiteRabbit you do realize that net.WriteEntity is convenience function for net.WriteUInt( ent:EntIndex(), 32 ) which basically makes sure the entity is valid before sending (which is exactly what I said in my last post.) And they are synchronized.[/QUOTE] Yes, but I have encountered the entities not being valid on the client until after the net message arrives, which is what I thought the problem was here. EDIT: After rereading your posts I guess I should try out the NetworkEntityCreated hook, I wasn't using that in my code when I ran into the problem with invalid entities clientside. Seems like it should definitely solve it. [editline]20th November 2013[/editline] [QUOTE=arcaneex;42912792]I'm pretty sure the ID changes on client and server, correct me if I'm wrong.[/QUOTE] It doesn't change/.
Sorry, you need to Log In to post a reply to this thread.