hambeast Posted June 4, 2014 Report Share Posted June 4, 2014 FYI, this guide is for advanced arma coders. This guide will assume you know how to pack/unpack PBO's, edit files, and are comrfortable with coding. You must also have an understanding of locality as in client vs server side. A note on locality: Your mpMissions folder is NOT only client side. When I started coding I made this assumption and I was wrong. Lesson 1: Event Handlers Basics Event handlers are the bread and butter of Arma2 MP coding. They are little logic functions that the server sets aside until they are called by a public variable. In my experience they have very low overhead so don't be afraid to make use of them. example 1: Change players skin Add this code to the bottom of your init.sqf (in your mpMission) // expects: [_playerUID,_CharacterID,_skinClassName] // this line says ONLY run on the ClientSide. The server will see this and ignore it. This means that when a client gets this command, they and only they will execute this. if (!isDedicated) then { "PV_ChangePlayerSkin" addPublicVariableEventHandler { // handle our packet. _this select 0 returns the PV name, _this select 1 returns our input packet _packet = _this select 1; // should contain [_playerUID, _characterID, _skinClassName] _playerUID = _packet select 0; _characterID = _packet select 1; _skinClassName = _packet select 2; // set our player to the skin [_playeruid,_characterID, _skinClassName] spawn player_humanityMorph; }; }; Ok so now we got our event handler set up, if any client sends the PV "PV_ChangePlayerSkin" all clients connected will execute this event handler. Here is how we send the command to all players. This code can be called anywhere, on a client, or from the server itself. example: PV_ChangePlayerSkin = [_playerUID,_CharacterID,_skinClassName]; publicVariable "PV_ChangePlayerSkin"; But you may be asking, how do I set just a single player's skin instead of everyone on the server? We do this with publicVariableClient. I am unsure if you can call this command from clientside as I only use it serverside but here is how you do it regardless. // lets assume we want to set our cursorTarget's skin (the player we are looking at) _player = cursorTarget; _owner = owner _player; // owner command returns the client # we will need for the next step. _playerUID = getPlayerUID _player; _characterID = _player getVariable ["CharacterID","0"]; _skinClassName = "FR_GL"; // my personal skin PV_ChangePlayerSkin = [_playerUID, _characterID, _skinClassName]; _owner publicVariableClient "PV_ChangePlayerSkin"; // only send the PV to the specific client Now when we send our public variable we only send it to the client we wish to. There are a myriad of ways to get player objects loaded into memory but that will be covered later. Ghostrider-GRG, MatthewK, raymix and 7 others 10 Link to comment Share on other sites More sharing options...
hambeast Posted June 4, 2014 Author Report Share Posted June 4, 2014 Lesson 2: Handling JIP clients What is JIP? JIP stands for "Join in Progress" aka players who join after the mission has already started. You know how to change a players skin by sending out public variables but how do you make sure every player who joins has their skin changed? For this example, we will assume there is an event running and for some reason you want to make sure every player who joins the server knows the event is running and if the event is started, lets make sure they get their skin. We will also be introducing the idea of server side and client side event handlers in this lesson. Brief flow of events: * Client connects * Client asks server if event is running * Server checks to see if event is running * If event is running, server changes players skin Server Side JIP Check and Validator: This code will handle requests from the client. // server side check, make sure only the server runs this code if (isDedicated) then { // DEBUG: Manually set our event to running... You would normally do this thru a menu etc. // note, that this variable is only set on the server itself, so the client has no idea of the value // if you wanted, you could pass this thru instead of a skin but that's out of the scope of this tutorial Server_Event = true; // expects: [player] // Handles our client JIP requests "PV_JIP_Event_Check" addPublicVariableEventHandler { private ["_packet","_player","_owner","_skinClassName"]; // deserialize our packet _packet = _this select 1; _player = _packet select 0; _owner = owner player; _skinClassName = "FR_GL"; // my personal skin // check to see if Server_Event has been set by an admin/script. if (!isNil "Server_Event") then { // validate Server_Event is true, if true, our even is running if (Server_Event) then { // our event is running, change skin of JIP player PV_ChangePlayerSkin = ["FR_GL"]; _owner publicVariableClient "PV_ChangePlayerSkin"; }; }; }; }; Client Side JIP Check: This code will be fired off when the client finishes loading their mission. // client side, JIP checker, this runs whenever the user loads their mission file if (!isDedicated) then { // call our JIP check to see if a mission is running PV_JIP_Event_Check = [player]; // only send the public variable to the server! publicVariableServer "PV_JIP_Event_Check"; }; Client Side Skin Changer: A slightly modified version of the 1st lesson's skin changer PV handler. // client side, Skin changer, this runs whenever our server sends the PV to the client. Modified to use less bandwidth // this line says ONLY run on the ClientSide. The server will see this and ignore it. This means that when a client gets this command, they and only they will execute this. if (!isDedicated) then { // expects: [_skinClassName] "PV_ChangePlayerSkin" addPublicVariableEventHandler { private ["_packet", "_skinClassName", "_playerUID", "_characterID"]; // handle our packet. _this select 0 returns the PV name, _this select 1 returns our input packet _packet = _this select 1; // should contain [_skinClassName] _skinClassName = _packet select 0; // since we are only running this on the local client, we don't need the playeruid and characteruid passed // we can just grab them from the local player object _playerUID = getPlayerUID player; _characterID = player getVariable ["CharacterID","0"]; // set our player to the skin [_playeruid,_characterID, _skinClassName] spawn player_humanityMorph; }; }; Place all of this code (in this order if you like) at the bottom of your init.sqf in the your mpmission. Now when a player connects to your server, they will have their skin changed. If you want to play around with this, You could add a custom menu in "fn_playerActions.sqf" that only admins see that sends a PV to the server to say set "Event_Status" to true of false. However, this guide is quick and dirty so it will always set a player skin, since we declare "Event_Status" as true. david, 31_D!4b10 and MatthewK 3 Link to comment Share on other sites More sharing options...
hambeast Posted June 4, 2014 Author Report Share Posted June 4, 2014 Lesson 3: PV security There is an old saying, that you can't have total security and total freedom at the same time. BI seems to favor freedom over security which can be a good thing but we all know the darker side of this as server admins / scripters. So how do we apply security to a game with almost no concept of it? 1. Localization. Not quite security but it allows us to keep all of our most sensitive code (accessing the database with your custom addon for example) away from prying eyes. This also lets us store values away from clients that they probably should not see. 2. Logging. Lets us see who called what and when. Possibly even where if you want to go that far. 3. Analysis. Using a tool like battleye to analyze our public varibles and values to see if bad code is being passed through. This also covers manual and automated log scanning. 4. Validation. Confirming our code is run by who we want it to and preventing execution from outside our environment. It should be clear that there is no way to be 100% secure in your arma2 code especially with all of the hackers around. An anti hack solution such as infistar is recommended however, I can't garuntee there will not be conflicts. You will have to resolve these yourself (or with infistar's help). hambeast note: PV's when sent out to everyone are only executed on machines that are not the sender. So if you want your own client to get event to fire, you must pass it to the server first, then the server will send it out to everyone (except the server of course) In this guide, I will attempt to cover all of the key points above and show you how to implement or integrate them into your system. This lesson will show you how to create an admin menu which allows us to start and stop events. When the event is started, all players (including JIP) should have a menu shown to TP to a predetermined location. When the event is finished, the menu will disappear. Here's a brief flow of the events: 1. Admin uses menu to start event 2. Players get message stating event has started 3. Players get menu to tp to event if they like 4. When admin ends event, players menu goes away Server Side: Open up your dayz_server pbo and edit init\server_functions.sqf. This will be where we keep our server side event handlers for now. Add the following somewhere near the top. This is our list of admins. You may have another method of populating this but this will work. AdminList = ["123456789","12121212"]; Now add the following near the bottom somewhere. These are our event handlers // expects: [sender,status] // set the status of our event and send to all connected clients if (isDedicated) then { "PV_EventSetStatus" addPublicVariableEventHandler { private ["_packet","_sender","_status","_logString","_isAdmin",]; _packet = _this select 1; _sender = _packet select 0; _status = _packet select 1; // check to see if user is an admin too. _isAdmin = (getPlayerUID _sender in AdminList); // validation: make sure our user in the admin list if (!isNil "_status" && _isAdmin) then { // log who sent it, we can cross reference against BE logs to see if people // are falsifying PVs _logString = format ["sender: %1 status: %2", _sender, _status]; diag_log _logString; // set status serverside. this value will stay until the server restarts Dayz_Epoch_Event_Running = _status; // send the value down to all clients PV_EventStatusClient = [Dayz_Epoch_Event_Running]; publicVariable "PV_EventStatusClient "; }; }; }; // expects: [sender] // handle event checking status if (isDedicated) then { "PV_EventStatusCheckJIP" addPublicVariableEventHandler { private ["_packet","_sender","_owner"]; _packet = _this select 1; _sender = _packet select 0; _owner = owner _sender; // make sure our variable has been set, if not ignore it if (!isNil "Dayz_Epoch_Event_Running") then { PV_EventStatusClient = [Dayz_Epoch_Event_Running]; _owner publicVariableClient "Dayz_Epoch_Event_Running"; }; }; }; Client Side: Open up your init.sqf in your mission and add the following to the top. This is our client side admin list. Not as important as the server side one as hackers can modify this. But if they hackers are setting themselves as admins, I think this is the least of your concern. Heck if they are doing that, it just makes it easier to catch them. Anyways, put this code near the top: AdminList = ["123456789","12121212"]; Now add these event handlers near the bottom: // Initial JIP check if (!isDedicated) then { PV_EventStatusCheckJIP = [player]; publicVariableServer "PV_EventStatusCheckJIP"; }; // expects: [status] // get the status update from the server if (!isDedicated) then { "PV_EventStatusClient" addPublicVariableEventHandler { private ["_packet","_status"]; _packet = _this select 1; _status = _packet select 0; // set the value client side - this value will persist until the client aborts Dayz_Epoch_Event_Running = _status; }; }; Client Side Continued... Now for the menus. You will need to know how to override your fn_selfActions.sqf. If you don't understand look up kryxes' self bloodbag script. I shamelessly rip his menu logic off in these examples. This is how we learn, so long as we give credit its ok. open fn_selfActions.sqf and add this near the top. This is our admin check: _isAdmin = (getPlayerUID player in AdminList); Now somewhere around there we are going to be adding some menus to handle the admin and player event menus. The admin menu will only show if a player has the playeruid you specified in your AdminList variable in init.sqf and the server_functions.sqf. As I said earlier, if players are spoofing this you got bigger problems. Thankfully battleye records who sends what PV's and we also log who says they turned the event on. // admin menu if (_isAdmin) then { if((speed player <= 1)) then { if (s_player_admin_option < 0) then { s_player_admin_option = player addaction[("<t color=""#E65C00"">" + ("Admin Menu") +"</t>"),"event\AdminMenu.sqf","",5,false,true,"", ""]; }; } else { player removeAction s_player_admin_option; s_player_admin_option = -1; }; }; // player TP menu if((speed player <= 1) && Dayz_Epoch_Event_Running) then { if (s_player_event_option < 0) then { s_player_event_option = player addaction[("<t color=""#FF0000"">" + ("-- EVENT ACCESS --") +"</t>"),"event\PlayerMenu.sqf","",5,false,true,"", ""]; }; } else { player removeAction s_player_event_option; s_player_event_option = -1; }; Client Side Continued More... We need to create a folder called "events" inside your mission folder. You can call it what you like but for this example, we are calling it "events". Create two text files inside name them "AdminMenu.sqf" and "PlayerMenu.sqf" Add the following to AdminMenu.sqf: private ["_isAdmin"]; _isAdmin = (getPlayerUID player in AdminList); // quit our script if useris not an admin if (!_isAdmin_) exitWith {}; AdminStartEvent = { Dayz_Epoch_Event_Running = true; [] call AdminSendStatus; }; AdminStopEvent = { Dayz_Epoch_Event_Running = false; [] call AdminSendStatus; }; // handle sending event to the server AdminSendStatus = { PV_EventSetStatus = [player, Dayz_Epoch_Event_Running]; publicVariableServer "PV_EventSetStatus"; }; // show the menu opt_main_admin = [ ["",false], ["-- Admin Event Control -- ", [0], "", -5, [["expression", ""]], "1", "0"], ["Admin Event START", [0], "", -5, [["expression", "[] spawn AdminStartEvent; "]], "1", "1"], ["Admin Event STOP", [0], "", -5, [["expression", "[] spawn AdminStopEvent; "]], "1", "1"], ["", [-1], "", -5, [["expression", ""]], "1", "0"], ["Exit", [13], "", -3, [["expression", ""]], "1", "1"] ]; showCommandingMenu "#USER:opt_main_admin"; and add this to PlayerMenu.sqf // bring player to event TpToEvent = { player setPosATL [1234.1,1234.1,0]; }; // show the menu opt_main_player = [ ["",false], ["-- Event Access -- ", [0], "", -5, [["expression", ""]], "1", "0"], ["TP Me to the Event", [0], "", -5, [["expression", "[] spawn TpToEvent; "]], "1", "1"], ["", [-1], "", -5, [["expression", ""]], "1", "0"], ["Exit", [13], "", -3, [["expression", ""]], "1", "1"] ]; showCommandingMenu "#USER:opt_main_player"; Now just adjust your Admin_List if you haven't already and you should be good to go. That's it, we're done. david and 31_D!4b10 2 Link to comment Share on other sites More sharing options...
hambeast Posted June 4, 2014 Author Report Share Posted June 4, 2014 Lesson 4: tips and tricks <reserved> Link to comment Share on other sites More sharing options...
ZamboniBambino Posted June 4, 2014 Report Share Posted June 4, 2014 It would also be an idea to mirror this over to the BIS community wiki, too. That deserves an upgrade in readability. Good work :) hambeast 1 Link to comment Share on other sites More sharing options...
collumjiggas Posted June 4, 2014 Report Share Posted June 4, 2014 [popcorn] this is very helpful. awaiting the completion of this tutorial so I can pester you with obnoxiously obvious questions since I'm a total noob. Link to comment Share on other sites More sharing options...
david Posted June 4, 2014 Report Share Posted June 4, 2014 Very nice, eagerly awaiting the next guides. Thanks. Link to comment Share on other sites More sharing options...
raymix Posted June 4, 2014 Report Share Posted June 4, 2014 Subbing, this is awesome. Might come up with some derpy script for our admins to play with when bored Link to comment Share on other sites More sharing options...
hambeast Posted June 4, 2014 Author Report Share Posted June 4, 2014 just updated Lesson #2. I'll be going over how to secure your PV's so that we only expose what we need to to the clients connecting to your server in the next elsson. I will also show you have to put event handlers and functions inside of your server PBO. This example will cover an admin menu to turn your event on and off, and a system for players to teleport to the event when it is up and running. Pretty cool right? Link to comment Share on other sites More sharing options...
david Posted June 4, 2014 Report Share Posted June 4, 2014 Nice and intuitive, you have my beans and looking forward to learn more on the security aspects. Keep it up :) Link to comment Share on other sites More sharing options...
raymix Posted June 4, 2014 Report Share Posted June 4, 2014 Very eager to see what you post in security part, as it is first thing I usually think of whenever I do something (apart from performance). Also - high five for the avatar, best series ever. Period. hambeast 1 Link to comment Share on other sites More sharing options...
hambeast Posted June 5, 2014 Author Report Share Posted June 5, 2014 Very eager to see what you post in security part, as it is first thing I usually think of whenever I do something (apart from performance). Also - high five for the avatar, best series ever. Period. did you try turning it off and on again? raymix and computermancer 2 Link to comment Share on other sites More sharing options...
raymix Posted June 5, 2014 Report Share Posted June 5, 2014 did you try turning it off and on again? It's not shit, it's chocolate, look! hambeast 1 Link to comment Share on other sites More sharing options...
raymix Posted June 5, 2014 Report Share Posted June 5, 2014 I'm a little stuck here. Trying to launch a snow/color correction scripts for admin scroll menu, that would make all clients execute same script. Idea is not to use JIP, so players can still relog if they want effect to be cleared. this is under !isDedicated in init "PV_wOriginal" addPublicVariableEventHandler { execVM "custom\ActionMenu\sky\1.sqf"; //executes color correction code }; This is accessed via action menu: ["Original", [2], "", -5, [["expression", format[EXECscript2 ,"11.sqf"]]], "1", "1"], 11.sqf contains: publicVariable "PV_wOriginal"; Nothing happens at all. Link to comment Share on other sites More sharing options...
hambeast Posted June 5, 2014 Author Report Share Posted June 5, 2014 I'm a little stuck here. Trying to launch a snow/color correction scripts for admin scroll menu, that would make all clients execute same script. Idea is not to use JIP, so players can still relog if they want effect to be cleared. this is under !isDedicated in init "PV_wOriginal" addPublicVariableEventHandler { execVM "custom\ActionMenu\sky\1.sqf"; //executes color correction code }; This is accessed via action menu: ["Original", [2], "", -5, [["expression", format[EXECscript2 ,"11.sqf"]]], "1", "1"], 11.sqf contains: publicVariable "PV_wOriginal"; Nothing happens at all. you need to declare the public variable before you call it. (and it looks like it's a zero not an "o" in your 11.sqf) so 11.sqf should be PV_wOriginal= []; publicVariable "PV_wOriginal"; also add some logging to your PV code so you can see when its being called and not simple as diag_log "my PV has been called"; then look in the arma2oa.rpt clientside for the log entry. Link to comment Share on other sites More sharing options...
raymix Posted June 5, 2014 Report Share Posted June 5, 2014 No matter what I do, I can't get execVM to work. Other scripts I find online are using it perfectly fine, so that's rather confusing. Neither of these works and I am out of ideas: "PV_wOriginal" addPublicVariableEventHandler { player execVM "custom\ActionMenu\sky\1.sqf"; }; "PV_wSnow" addPublicVariableEventHandler { (_this select 1) execVM "custom\ActionMenu\sky\2.sqf"; }; "PV_wWasteland" addPublicVariableEventHandler { [_this select 1] execVM "custom\ActionMenu\sky\3.sqf"; }; Everything else works fine, it's just this part. I'll see maybe there's another way for admins to force clients to execute color correction files. Link to comment Share on other sites More sharing options...
Halvhjearne Posted June 5, 2014 Report Share Posted June 5, 2014 No matter what I do, I can't get execVM to work. Other scripts I find online are using it perfectly fine, so that's rather confusing. Neither of these works and I am out of ideas: "PV_wOriginal" addPublicVariableEventHandler { player execVM "custom\ActionMenu\sky\1.sqf"; }; "PV_wSnow" addPublicVariableEventHandler { (_this select 1) execVM "custom\ActionMenu\sky\2.sqf"; }; "PV_wWasteland" addPublicVariableEventHandler { [_this select 1] execVM "custom\ActionMenu\sky\3.sqf"; }; Everything else works fine, it's just this part. I'll see maybe there's another way for admins to force clients to execute color correction files. using execVM within a public variable event is bad practice imho, you should rather fire up some functions Link to comment Share on other sites More sharing options...
hambeast Posted June 5, 2014 Author Report Share Posted June 5, 2014 Ok guys, Updated the "security" section. A bit more on the "how to put stuff in the server file and call it there" vs actual security but hey, its ARMA we work with the tools given. Link to comment Share on other sites More sharing options...
hambeast Posted June 5, 2014 Author Report Share Posted June 5, 2014 using execVM within a public variable event is bad practice imho, you should rather fire up some functions agreed. Plus you can re-use functions and we should always strive to build modular re-usable code. also, Raymix, mind showing us how you're calling these PV's. Do you get any logs in battleye? Are you using any logging at all inside your PV? Link to comment Share on other sites More sharing options...
hambeast Posted June 5, 2014 Author Report Share Posted June 5, 2014 It would also be an idea to mirror this over to the BIS community wiki, too. That deserves an upgrade in readability. Good work :) Zamboni, like the idea but I'm too invested in other projects to edit wikis. You are free to copy all of the info here over there if you like. Link to comment Share on other sites More sharing options...
Guest Posted June 9, 2014 Report Share Posted June 9, 2014 EDIT: Moved to Scripting Help Link to comment Share on other sites More sharing options...
hambeast Posted June 13, 2014 Author Report Share Posted June 13, 2014 EDIT: Moved to Scripting Help sry watte, I saw your question but have been extremely busy with real life lately. I'd be happy to help you here if you want or if you want to PM me, that's fine too. Link to comment Share on other sites More sharing options...
Barra81 Posted July 11, 2014 Report Share Posted July 11, 2014 can you help me with my script ? Im searching for days now but I cant find a solution. I want to build a roof/hangar that is hideable by a switch, to start or land an aircraft. for testing purposes BE and Infistar are OFF. _nearestPanelorBox = nearestObjects [vehicle player, ["Infostand_2_EP1","MAP_phonebox"], 40]; _nearestOne = _nearestPanelorBox select 0; _nearestGates = nearestObject [_nearestOne, "MAP_SS_hangar"]; _hide = format["{ _nearestGates hideObject true ;} forEach playableUnits;"]; _hide2 = format["{ _nearestGates hideObject false ;} forEach playableUnits;"]; _inMotion = _nearestOne getVariable ["inMotion",0]; if (_inMotion == 0) then { _nearestOne setVariable ["inMotion", 1, true]; sleep 0.1; player setVehicleInit _hide; sleep 0.1; processInitCommands; sleep 0.1; clearVehicleInit player; rcrHideRoof = [player,_nearestGates]; publicVariable "rcrHideRoof"; } else { _nearestOne setVariable ["inMotion", 0, true]; sleep 0.1; player setVehicleInit _hide2; sleep 0.1; processInitCommands; sleep 0.1; clearVehicleInit player; rcrUnHideRoof = [player, _nearestGates]; publicVariable "rcrUnHideRoof"; }; this is my script activated from an addaction call at the fn_selfactions.sqf for the executing player the script works BUT only for him. this is what i have in my init.sqf : if (isDedicated) then { "rcrHideRoof" addPublicVariableEventHandler { _packet = _this select 1; _nearestGates = _packet select 1; _player = _packet select 0; _hide = format["{ _nearestGates hideObject true ;} forEach playableUnits;"]; sleep 0.1; _player setVehicleInit _hide; sleep 0.1; processInitCommands; sleep 0.1; clearVehicleInit _player; }; "rcrUnHideRoof" addPublicVariableEventHandler { _packet = _this select 1; _nearestGates = _packet select 1; _player = _packet select 0; _hide = format["{ _nearestGates hideObject false ;} forEach playableUnits;"]; sleep 0.1; _player setVehicleInit _hide; sleep 0.1; processInitCommands; sleep 0.1; clearVehicleInit _player; }; }; but it wont work somehow :( Link to comment Share on other sites More sharing options...
igoooor Posted January 8, 2015 Report Share Posted January 8, 2015 Thank you sir, I learned a lot today, I now know how to cutText to the cursorTarget ^^! However I think there is some mistakes in your code, lesson2: // server side check, make sure only the server runs this code if (isDedicated) then { // DEBUG: Manually set our event to running... You would normally do this thru a menu etc. // note, that this variable is only set on the server itself, so the client has no idea of the value // if you wanted, you could pass this thru instead of a skin but that's out of the scope of this tutorial Server_Event = true; // expects: [player] // Handles our client JIP requests "PV_JIP_Event_Check" addPublicVariableEventHandler { private ["_packet","_player","_owner","_skinClassName"]; // deserialize our packet _packet = _this select 0; // shouldn't be select 1 according to lesson1? <=================== HERE _player = _packet select 0; _owener = owner player; // wrong var name <=================== AND HERE _skinClassName = "FR_GL"; // my personal skin // check to see if Server_Event has been set by an admin/script. if (!isNil "Server_Event") then { // validate Server_Event is true, if true, our even is running if (Server_Event) then { // our event is running, change skin of JIP player PV_ChangePlayerSkin = ["FR_GL"]; _owner publicVariableClient "PV_ChangePlayerSkin"; }; }; }; }; I know this is not big mistakes, but if someone copy/paste to give it a try, he might encounter some issues ^^ hambeast 1 Link to comment Share on other sites More sharing options...
hambeast Posted January 8, 2015 Author Report Share Posted January 8, 2015 Thank you sir, I learned a lot today, I now know how to cutText to the cursorTarget ^^! However I think there is some mistakes in your code, lesson2: // server side check, make sure only the server runs this code if (isDedicated) then { // DEBUG: Manually set our event to running... You would normally do this thru a menu etc. // note, that this variable is only set on the server itself, so the client has no idea of the value // if you wanted, you could pass this thru instead of a skin but that's out of the scope of this tutorial Server_Event = true; // expects: [player] // Handles our client JIP requests "PV_JIP_Event_Check" addPublicVariableEventHandler { private ["_packet","_player","_owner","_skinClassName"]; // deserialize our packet _packet = _this select 0; // shouldn't be select 1 according to lesson1? <=================== HERE _player = _packet select 0; _owener = owner player; // wrong var name <=================== AND HERE _skinClassName = "FR_GL"; // my personal skin // check to see if Server_Event has been set by an admin/script. if (!isNil "Server_Event") then { // validate Server_Event is true, if true, our even is running if (Server_Event) then { // our event is running, change skin of JIP player PV_ChangePlayerSkin = ["FR_GL"]; _owner publicVariableClient "PV_ChangePlayerSkin"; }; }; }; }; I know this is not big mistakes, but if someone copy/paste to give it a try, he might encounter some issues ^^ good catch. always nice to have code review. I'll edit the samples so they are correct Link to comment Share on other sites More sharing options...
Recommended Posts
Please sign in to comment
You will be able to leave a comment after signing in
Sign In Now