← Back to changelog
What changed
GarageDoor2 · v1.3.3 → v1.3.4 (current)
Diff
2 added · 1 removed · 1054 → 1055 total lines
1
1
/*▄▄▄ ███▄ ▄███▓ ▄████ ▄▄▄██▀▀▀▓█████▄▄▄█████▓
2
2
▓█████▄ ▓██▒▀█▀ ██▒ ██▒ ▀█▒ ▒██ ▓█ ▀▓ ██▒ ▓▒
3
3
▒██▒ ▄██▓██ ▓██░▒██░▄▄▄░ ░██ ▒███ ▒ ▓██░ ▒░
4
4
▒██░█▀ ▒██ ▒██ ░▓█ ██▓▓██▄██▓ ▒▓█ ▄░ ▓██▓ ░
5
5
░▓█ ▀█▓▒██▒ ░██▒░▒▓███▀▒ ▓███▒ ░▒████▒ ▒██▒ ░
6
6
░▒▓███▀▒░ ▒░ ░ ░ ░▒ ▒ ▒▓▒▒░ ░░ ▒░ ░ ▒ ░░
7
7
▒░▒ ░ ░ ░ ░ ░ ░ ▒ ░▒░ ░ ░ ░ ░
8
8
░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░
9
9
░ ░ ░ ░ ░ ░ ░
10
10
Perms:
11
11
GarageDoor2.Turn - Required to use the chat command.
12
12
GarageDoor2.Rotate - Hitting with hammer while holding R key rotates garage doors. (Requires Building Perm)
13
13
GarageDoor2.Skin - Allows using gdskin command /gdskin skinid
14
14
GarageDoor2.Break - Break floor frame by hitting with hammer while holding Shift+R
15
15
GarageDoor2.GUI - Allows using GUI, Right click with hammer
16
16
17
17
Chat Commands:
18
18
/td - Converts garage door into horizontal garage door and back.
19
19
/gdskin skinid - Placed rotated garage doors will have this skin (set 0 to disable)
20
20
21
21
Console Commands:
22
22
garagedoor2.give $player - Gives rotated garage door to that player by there ID or Name
23
23
*/
24
24
using Facepunch;
25
25
using Newtonsoft.Json;
26
26
using Oxide.Core;
27
27
using Oxide.Game.Rust.Cui;
28
28
using System;
29
29
using System.Collections;
30
30
using System.Collections.Generic;
31
31
using System.Linq;
32
32
using UnityEngine;
33
33
namespace Oxide.Plugins
34
34
{
35
-
[Info("GarageDoor2", "bmgjet", "1.3.3")]
35
+
[Info("GarageDoor2", "bmgjet", "1.3.4")]
36
36
[Description("Lets you place a horizontal garage door")]
37
37
public class GarageDoor2 : RustPlugin
38
38
{
39
39
private static GarageDoor2 plugin;
40
40
private readonly string Perm = "GarageDoor2.Turn";
41
41
private readonly string PermR = "GarageDoor2.Rotate";
42
42
private readonly string PermS = "GarageDoor2.Skin";
43
43
private readonly string PermB = "GarageDoor2.Break";
44
44
private readonly string PermG = "GarageDoor2.GUI";
45
45
private const string GarageDoor = "assets/prefabs/building/wall.frame.garagedoor/wall.frame.garagedoor.prefab";
46
46
private const string DoorController = "assets/prefabs/deployable/playerioents/doormanipulators/doorcontroller.deployed.prefab";
47
47
private const string Deploy = "assets/prefabs/deployable/playerioents/industrialconveyor/effects/industrial-conveyor-deploy.prefab";
48
48
private Dictionary<ulong, ulong> LastUsedSkin = new Dictionary<ulong, ulong>();
49
49
private List<ulong> Cooldowns = new List<ulong>();
50
50
51
51
#region DataFile
52
52
private StoredData storedData;
53
53
private class StoredData { public Dictionary<ulong, ulong> SID = new Dictionary<ulong, ulong>(); public List<ulong> Rotated = new List<ulong>(); public List<ulong> Scaled = new List<ulong>(); } //Hold Skin Ids of orignal garage door
54
54
#endregion
55
55
56
56
#region Configuration
57
57
private Configuration config;
58
58
private class Configuration
59
59
{
60
60
[JsonProperty("Pick Up Rotated Garage Doors As Rotated Garage Doors")]
61
61
public bool PickUpRotated = true;
62
62
63
63
[JsonProperty("Add Rotated Garage Doors Into Supply Drops")]
64
64
public bool AddSupplyDrops = false;
65
65
66
66
[JsonProperty("Move Door Controllers And Locks Into Roller")]
67
67
public bool MoveController = true;
68
68
69
69
[JsonProperty("Oversize Garage Doors On Frame Break")]
70
70
public bool Oversize = true;
71
71
72
72
[JsonProperty("Spawning In Supply Drop Percentage Chance (0-100)")]
73
73
public int ChancePercentage = 60;
74
74
75
75
[JsonProperty("SkinID To Use For Rotated Garage Doors")]
76
76
public ulong CustomSkinID = 3148709690;
77
77
78
78
[JsonProperty("CoolDown Between GUI Actions (Sec)")]
79
79
public float CooldownDelay = 0.8f;
80
80
81
81
[JsonProperty("GUI Min X")]
82
82
public string MinX = ".9";
83
83
84
84
[JsonProperty("GUI Min Y")]
85
85
public string MinY = ".68";
86
86
87
87
[JsonProperty("GUI Max X")]
88
88
public string MaxX = "1";
89
89
90
90
[JsonProperty("GUI Max Y")]
91
91
public string MaxY = "1";
92
92
93
93
[JsonProperty("SoundFX To Play On Rotation (Blank = None)")]
94
94
public string SoundFX = "assets/bundled/prefabs/fx/build/promote_toptier.prefab";
95
95
96
96
[JsonProperty("SoundFX To Play On Skin (Blank = None)")]
97
97
public string SSoundFX = "assets/prefabs/deployable/repair bench/effects/skinchange_spraypaint.prefab";
98
98
99
99
[JsonProperty("SoundFX To Play On Frame Break (Blank = None)")]
100
100
public string FSoundFX = "assets/bundled/prefabs/fx/building/wood_gib.prefab";
101
101
102
102
[JsonProperty("Allow breaking door frames (Will break stability of bases)")]
103
103
public bool breakall = false;
104
104
105
105
[JsonProperty("Scaled doors only take damage from player (Only enable if you have other plugin re-enabling stability)")]
106
106
public bool playeronlydamage = false;
107
107
108
108
[JsonProperty("Debug messages on what last caused damage")]
109
109
public bool debug = false;
110
110
111
111
public string ToJson() => JsonConvert.SerializeObject(this);
112
112
113
113
public Dictionary<string, object> ToDictionary() => JsonConvert.DeserializeObject<Dictionary<string, object>>(ToJson());
114
114
}
115
115
116
116
protected override void LoadDefaultConfig() { config = new Configuration(); }
117
117
protected override void LoadConfig()
118
118
{
119
119
base.LoadConfig();
120
120
try
121
121
{
122
122
config = Config.ReadObject<Configuration>();
123
123
if (config == null) { throw new JsonException(); }
124
124
125
125
if (!config.ToDictionary().Keys.SequenceEqual(Config.ToDictionary(x => x.Key, x => x.Value).Keys))
126
126
{
127
127
PrintWarning("Configuration appears to be outdated; updating and saving");
128
128
SaveConfig();
129
129
}
130
130
}
131
131
catch
132
132
{
133
133
PrintWarning($"Configuration file {Name}.json is invalid; using defaults");
134
134
LoadDefaultConfig();
135
135
}
136
136
}
137
137
protected override void SaveConfig()
138
138
{
139
139
PrintWarning($"Configuration changes saved to {Name}.json");
140
140
Config.WriteObject(config, true);
141
141
}
142
142
#endregion Configuration
143
143
144
144
#region Language
145
145
protected override void LoadDefaultMessages()
146
146
{
147
147
lang.RegisterMessages(new Dictionary<string, string>
148
148
{
149
149
{"DoorName", "Rotated Garage Door"},
150
150
{"CantRotate", "Can't Rotate Scaled Doors"},
151
151
{"NeedSkinID", "You must provide a skinid /gdskin 12345"},
152
152
{"InvalidSkinID", "Invalid skinid"},
153
153
{"NoPerm", " You don't have permission to use this command!"},
154
154
{"UpdatedID", "Updated SkinID to {0}"},
155
155
{"Blocked", "Placement Blocked"},
156
156
{"MustHold", "You must be holding a garage door!"},
157
157
{"Rotate", "Rotate"},
158
158
{"Skin", "Skin"},
159
159
{"Break", "Break"},
160
160
{"NoFoundation", "No foundation found, placement blocked!"},
161
161
}, this);
162
162
}
163
163
164
164
private string message(BasePlayer player, string key, params object[] args)
165
165
{
166
166
if (player == null) { return string.Format(lang.GetMessage(key, this), args); }
167
167
return string.Format(lang.GetMessage(key, this, player.UserIDString), args);
168
168
}
169
169
#endregion
170
170
171
171
#region Oxide Hooks
172
172
private void Init()
173
173
{
174
174
plugin = this;
175
175
permission.RegisterPermission(Perm, this);
176
176
permission.RegisterPermission(PermR, this);
177
177
permission.RegisterPermission(PermS, this);
178
178
permission.RegisterPermission(PermB, this);
179
179
permission.RegisterPermission(PermG, this);
180
180
//Unsub if not enabled in config
181
181
if (!config.AddSupplyDrops) { Unsubscribe("OnLootSpawn"); }
182
182
if (!config.MoveController) { Unsubscribe("OnEntitySpawned"); }
183
183
if (!config.playeronlydamage) { Unsubscribe("OnEntityKill"); }
184
184
storedData = Interface.Oxide.DataFileSystem.ReadObject<StoredData>(Name);
185
185
}
186
186
187
187
private object OnEntityKill(Door door)
188
188
{
189
189
if (door.prefabID == 3647679950) //only garage doors
190
190
{
191
191
if (door.lastAttacker == null || UnityEngine.Time.time - door.lastAttackedTime > 10) //No player damage done or in last 10 sec
192
192
{
193
193
if (storedData.Scaled.Contains(door.net.ID.Value))
194
194
{
195
195
if (config.debug) { Puts("Blocked " + door.lastDamage.ToString() + " Damage To GD2"); }
196
196
return true;
197
197
}
198
198
} //No player damage done, give god mode
199
199
}
200
200
return null;
201
201
}
202
202
203
203
private void Unload()
204
204
{
205
205
Interface.Oxide.DataFileSystem.WriteObject(Name, storedData);
206
206
foreach (BasePlayer p in BasePlayer.activePlayerList) { CuiHelper.DestroyUi(p, "GD2P"); }
207
207
plugin = null;
208
208
}
209
209
210
210
private object CanBuild(Planner planner, Construction construction, Construction.Target target)
211
211
{
212
212
if (target.entity != null && IsRotatedGD(target.entity) && construction?.prefabID == 2343730564)
213
213
{
214
214
return false;
215
215
}
216
216
return null;
217
217
}
218
218
219
219
void OnServerInitialized() //Clean up save data from invalid/despawned doors
220
220
{
221
221
// Start cleanup asynchronously
222
222
ServerMgr.Instance.StartCoroutine(CleanUpData());
223
223
}
224
224
private IEnumerator CleanUpData()
225
225
{
226
226
int Cleaned = 0;
227
227
228
228
if (storedData != null)
229
229
{
230
230
List<ulong> Found = Pool.Get<List<ulong>>();
231
231
232
232
// Split workload to prevent blocking
233
233
int count = 0;
234
234
foreach (var s in BaseNetworkable.serverEntities.entityList.Get().Values)
235
235
{
236
236
if (s != null)
237
237
{
238
238
if (s is BasePlayer player)
239
239
{
240
240
List<Item> list = Pool.Get<List<Item>>();
241
241
player.inventory.GetAllItems(list);
242
242
foreach (var i in list)
243
243
{
244
244
if (storedData.SID.ContainsKey(i.uid.Value))
245
245
Found.Add(i.uid.Value);
246
246
}
247
247
Pool.FreeUnmanaged(ref list);
248
248
}
249
249
else if (s is StorageContainer container && container.inventory?.itemList != null)
250
250
{
251
251
foreach (var i in container.inventory.itemList)
252
252
{
253
253
if (storedData.SID.ContainsKey(i.uid.Value))
254
254
Found.Add(i.uid.Value);
255
255
}
256
256
}
257
257
else if (s is Door door && storedData.Scaled.Contains(door.net.ID.Value))
258
258
{
259
259
ScaleDoor(door); //Fix lost scale
260
260
}
261
261
}
262
262
263
263
// Yield every 10K iterations to prevent server lag
264
264
if (++count % 10000 == 0)
265
265
{
266
266
if (Performance.report.frameRate < 15 && ConVar.FPS.limit > 15) { yield return CoroutineEx.waitForSeconds(0.01f); }
267
267
else { yield return CoroutineEx.waitForSeconds(0.0035f); }
268
268
}
269
269
}
270
270
271
271
// Remove invalid entries (single pass instead of repeated O(n) ElementAt lookups)
272
272
List<ulong> staleKeys = Pool.Get<List<ulong>>();
273
273
foreach (var kvp in storedData.SID)
274
274
{
275
275
if (!Found.Contains(kvp.Key)) { staleKeys.Add(kvp.Key); }
276
276
}
277
277
foreach (var key in staleKeys)
278
278
{
279
279
storedData.SID.Remove(key);
280
280
Cleaned++;
281
281
}
282
282
Pool.FreeUnmanaged(ref staleKeys);
283
283
Pool.FreeUnmanaged(ref Found);
284
284
285
285
for (int i = storedData.Rotated.Count - 1; i >= 0; i--)
286
286
{
287
287
if (!BaseNetworkable.serverEntities.Contains(new NetworkableId(storedData.Rotated[i])))
288
288
{
289
289
storedData.Rotated.RemoveAt(i);
290
290
Cleaned++;
291
291
}
292
292
}
293
293
294
294
if (Cleaned > 0)
295
295
{
296
296
Interface.Oxide.DataFileSystem.WriteObject(Name, storedData);
297
297
Puts($"Removed {Cleaned} references to dead/despawned items.");
298
298
}
299
299
}
300
300
}
301
301
302
302
private object CanRecycle(Recycler recycler, Item item)
303
303
{
304
+
if (recycler == null || item == null || item.info == null) { return null; }
304
305
if (item.info.itemid == 1948067030 && item.skin == config.CustomSkinID) { if (config.debug) Puts("Block Recycle from GarageDoor2"); return false; } //Prevent recycling rotated doors.
305
306
return null;
306
307
}
307
308
308
309
private void OnNewSave()
309
310
{
310
311
Puts("Cleared Save Data!");
311
312
storedData.SID.Clear();
312
313
}
313
314
314
315
private object CanPickupEntity(BasePlayer player, BaseEntity entity)
315
316
{
316
317
if (entity?.prefabID == 3647679950 && config.playeronlydamage)
317
318
{
318
319
Door door = entity as Door;
319
320
if (door != null)
320
321
{
321
322
door.lastAttacker = player;
322
323
door.lastAttackedTime = UnityEngine.Time.time;
323
324
}
324
325
}
325
326
if (config.PickUpRotated && PickedUpGrageDoor(player, entity)) { return false; }
326
327
return null;
327
328
}
328
329
329
330
private void OnLootSpawn(LootContainer container)
330
331
{
331
332
if (container is SupplyDrop) //Supply drop
332
333
{
333
334
if (RandomChance((uint)UnityEngine.Random.Range(11111, 99999), config.ChancePercentage)) //Roll a random chance
334
335
{
335
336
//Create Rotated Garage Door And Add To Supply Drop
336
337
Item item2 = ItemManager.CreateByItemID(1948067030, 1, config.CustomSkinID);
337
338
item2.name = message(null, "DoorName");
338
339
item2.MarkDirty();
339
340
if (item2 != null) { if (!item2.MoveToContainer(container.inventory, -1, false, false, null, true)) { item2.Remove(0f); } }
340
341
}
341
342
}
342
343
}
343
344
344
345
//Correct local position
345
346
void OnEntitySpawned(CodeLock cl) { MoveLockPos(cl); }
346
347
347
348
void OnEntitySpawned(KeyLock kl) { MoveLockPos(kl); }
348
349
349
350
//Rotation, Break frame hook
350
351
object OnHammerHit(BasePlayer ownerPlayer, HitInfo info)
351
352
{
352
353
if (ownerPlayer == null || !(info?.HitEntity is Door)) { return null; }
353
354
//Check has reload down and permission
354
355
if (info.HitEntity.prefabID == 3647679950 && ownerPlayer.IsBuildingAuthed())
355
356
{
356
357
if (ownerPlayer.serverInput.IsDown(BUTTON.SPRINT) && ownerPlayer.serverInput.IsDown(BUTTON.RELOAD) && permission.UserHasPermission(ownerPlayer.UserIDString, PermB))
357
358
{
358
359
BreakFrame(info?.HitEntity as Door);
359
360
return true;
360
361
}
361
362
if (ownerPlayer.serverInput.IsDown(BUTTON.RELOAD) && permission.UserHasPermission(ownerPlayer.UserIDString, PermR))
362
363
{
363
364
if (config.Oversize && IsRotatedGD(info?.HitEntity as Door)) { ownerPlayer.ChatMessage(message(ownerPlayer, "CantRotate")); return true; }
364
365
RotateDoor(info?.HitEntity as Door);
365
366
return true;
366
367
}
367
368
}
368
369
return null;
369
370
}
370
371
371
372
//Catch adding door controller / Hammer
372
373
private void OnActiveItemChanged(BasePlayer __instance)
373
374
{
374
375
if (__instance?.GetActiveItem()?.info?.itemid == -502177121 && !__instance.IsBuildingBlocked()) //-502177121 Door Controller
375
376
{
376
377
DoorControllerPlacer AP = __instance.GetComponent<DoorControllerPlacer>(); //Check if player has component
377
378
if (AP == null) { AP = __instance.gameObject.AddComponent<DoorControllerPlacer>(); } //Add component if player doesnt have it
378
379
AP.player = __instance; //Set player variable in component
379
380
}
380
381
//200773292 Hammer
381
382
if (__instance?.GetActiveItem()?.info?.itemid == 200773292 && !__instance.IsBuildingBlocked() && permission.UserHasPermission(__instance.UserIDString, PermG))
382
383
{
383
384
GUIWindow AP = __instance.GetComponent<GUIWindow>(); //Check if player has component
384
385
if (AP == null) { AP = __instance.gameObject.AddComponent<GUIWindow>(); } //Add component if player doesnt have it
385
386
AP.player = __instance; //Set player variable in component
386
387
}
387
388
}
388
389
389
390
private void OnEntityBuilt(Planner plan, GameObject go) { CheckDeploy(plan, go.ToBaseEntity()); } //Tried To Place Something
390
391
391
392
//Remove Tool
392
393
private void OnNormalRemovedEntity(BasePlayer player, BaseEntity entity)
393
394
{
394
395
if (PickedUpGrageDoor(player, entity)) { NextFrame(() => { Take(player, -148794216, 1); }); }
395
396
}
396
397
397
398
[ChatCommand("gdskin")] //Set door skin to use on all rotated garage doors
398
399
private void SetGDSkin(BasePlayer player, string command, string[] args)
399
400
{
400
401
if (permission.UserHasPermission(player.UserIDString, PermS))
401
402
{
402
403
if (args.Length != 1)
403
404
{
404
405
player.ChatMessage(message(player, "NeedSkinID"));
405
406
return;
406
407
}
407
408
ulong skinid = 0;
408
409
if (!ulong.TryParse(args[0], out skinid))
409
410
{
410
411
player.ChatMessage(message(player, "InvalidSkinID"));
411
412
return;
412
413
}
413
414
if (!LastUsedSkin.ContainsKey(player.userID)) { LastUsedSkin.Add(player.userID, skinid); }
414
415
else
415
416
{
416
417
if (skinid == 0) { LastUsedSkin.Remove(player.userID); }
417
418
else { LastUsedSkin[player.userID] = skinid; }
418
419
}
419
420
player.ChatMessage(message(player, "UpdatedID", skinid));
420
421
return;
421
422
}
422
423
player.ChatMessage(message(player, "NoPerm"));
423
424
}
424
425
425
426
[ChatCommand("resetlockpos")] //Turn door
426
427
private void resetlockpos(BasePlayer player, string command, string[] args)
427
428
{
428
429
if (player.IsAdmin)
429
430
{
430
431
foreach (var s in BaseNetworkable.serverEntities.entityList.Get().Values)
431
432
{
432
433
if (s != null)
433
434
{
434
435
if (s is Door && IsRotatedGD(s as Door))
435
436
{
436
437
Door door = s as Door;
437
438
if (door.HasSlot(BaseEntity.Slot.Lock))
438
439
{
439
440
MoveLockPos(door.GetSlot(BaseEntity.Slot.Lock));
440
441
}
441
442
}
442
443
}
443
444
}
444
445
player.ChatMessage("Reset All Locks On Rotated Garage Doors");
445
446
}
446
447
}
447
448
448
449
[ChatCommand("td")] //Turn door
449
450
private void GetDoorChatCommand(BasePlayer player, string command, string[] args)
450
451
{
451
452
if (permission.UserHasPermission(player.UserIDString, Perm))
452
453
{
453
454
Item active = player?.GetActiveItem();
454
455
if (active == null) { return; }
455
456
int slot = active.position;
456
457
if (active.info.itemid == -148794216) //Check player is holding garage door
457
458
{
458
459
Item RotatedGarageDoor = ItemManager.CreateByItemID(1948067030, active.amount, config.CustomSkinID);
459
460
RotatedGarageDoor.name = message(player, "DoorName");
460
461
RotatedGarageDoor.MarkDirty();
461
462
GiveItem(player, RotatedGarageDoor, message(player, "DoorName"), slot);
462
463
RotatedGarageDoor.position = slot;
463
464
storedData.SID.Add(RotatedGarageDoor.uid.Value, active.skin); //Create a turned garage door (ladder hatch skinned) and add to save data
464
465
active.amount = 0;
465
466
active.Remove();
466
467
Interface.Oxide.DataFileSystem.WriteObject(Name, storedData);
467
468
return;
468
469
}
469
470
if (active.info.itemid == 1948067030 && active.skin == config.CustomSkinID) //Check player is holding a turned garage door (skinned ladder hatch)
470
471
{
471
472
if (storedData.SID.ContainsKey(active.uid.Value)) //Check there is save data
472
473
{
473
474
Item NewGarageDoor = ItemManager.CreateByItemID(-148794216, active.amount, storedData.SID[active.uid.Value]); //Create garage door with skin
474
475
storedData.SID.Remove(active.uid.Value); //Remove sav data reference
475
476
active.amount = 0;
476
477
active.Remove();
477
478
GiveItem(player, NewGarageDoor, message(player, "DoorName"), slot);
478
479
NewGarageDoor.position = slot;
479
480
Interface.Oxide.DataFileSystem.WriteObject(Name, storedData);
480
481
return;
481
482
}
482
483
else
483
484
{
484
485
Item NewGarageDoor = ItemManager.CreateByItemID(-148794216, active.amount, 0); //Create garage door with skin
485
486
active.amount = 0;
486
487
active.Remove();
487
488
GiveItem(player, NewGarageDoor, message(player, "DoorName"), slot);
488
489
NewGarageDoor.position = slot;
489
490
}
490
491
}
491
492
player.ChatMessage(message(player, "MustHold"));
492
493
return;
493
494
}
494
495
player.ChatMessage(message(player, "NoPerm"));
495
496
}
496
497
497
498
[ConsoleCommand("garagedoor2.give")]
498
499
private void Cmd(ConsoleSystem.Arg arg)
499
500
{
500
501
if (arg.IsAdmin && arg.Args?.Length > 0)
501
502
{
502
503
var player = BasePlayer.Find(arg.Args[0].ToString()) ?? BasePlayer.FindSleeping(arg.Args[0].ToString()); //Get player from arg
503
504
if (player == null)
504
505
{
505
506
PrintWarning($"Can't find player with that name/ID! {arg.Args[0]}");
506
507
return;
507
508
}
508
509
var item = ItemManager.CreateByName("floor.ladder.hatch", 1, config.CustomSkinID); //Create rotated garage door
509
510
if (item != null)
510
511
{
511
512
//Give to player
512
513
item.text = message(player, "DoorName");
513
514
item.name = item.text;
514
515
player.GiveItem(item);
515
516
}
516
517
}
517
518
}
518
519
519
520
[ConsoleCommand("GD2GUI")]
520
521
private void GD2GUICMD(ConsoleSystem.Arg arg)
521
522
{
522
523
BaseNetworkable info = null;
523
524
BasePlayer player = arg.Player();
524
525
if (player == null) { return; } //Checks from player
525
526
ulong playerid = player.userID;
526
527
if (Cooldowns.Contains(playerid)) { return; }
527
528
Cooldowns.Add(playerid);
528
529
timer.Once(config.CooldownDelay, () => { Cooldowns.Remove(playerid); });
529
530
if (arg.Args?.Length > 1)
530
531
{
531
532
ulong targetId;
532
533
if (ulong.TryParse(arg.Args[1].ToString(), out targetId)) { info = BaseNetworkable.serverEntities.Find(new NetworkableId(targetId)); } //Gets door from id
533
534
}
534
535
if (info == null || Vector3.Distance(info.transform.position, player.transform.position) > 5) { return; } //Checks player isnt far away (exploit)
535
536
if (arg.Args.Length > 0) //Arg passed
536
537
{
537
538
switch (arg.Args[0].ToString())
538
539
{
539
540
case "R":
540
541
if (permission.UserHasPermission(player.UserIDString, PermR))
541
542
{
542
543
if (config.Oversize && IsRotatedGD(info as Door)) { player.ChatMessage(message(player, "CantRotate")); return; }
543
544
RotateDoor(info as Door);
544
545
}
545
546
break;
546
547
case "P":
547
548
if (arg.Args.Length > 2)
548
549
{
549
550
DrawCUI(player, info as Door, arg.Args[2].ToString());
550
551
}
551
552
break;
552
553
case "B":
553
554
if (arg.Args.Length > 2 && permission.UserHasPermission(player.UserIDString, PermB))
554
555
{
555
556
BreakFrame((info as Door));
556
557
DrawCUI(player, info as Door, arg.Args[2].ToString());
557
558
}
558
559
break;
559
560
case "S":
560
561
if (arg.Args.Length > 2 && permission.UserHasPermission(player.UserIDString, PermS))
561
562
{
562
563
ulong skinid;
563
564
if (!ulong.TryParse(arg.Args[2].ToString(), out skinid))
564
565
{
565
566
player.ChatMessage(message(player, "InvalidSkinID"));
566
567
return;
567
568
}
568
569
(info as Door).skinID = skinid;
569
570
if (!string.IsNullOrEmpty(config.SSoundFX)) { Effect.server.Run(config.SSoundFX, info.transform.position); }
570
571
info.SendNetworkUpdateImmediate();
571
572
}
572
573
break;
573
574
}
574
575
}
575
576
}
576
577
#endregion
577
578
578
579
#region Methods
579
580
private List<CuiElement> RustUI(string netid, string skinid, string skinperm, string rotateperm, string breakperm, string[] lang)
580
581
{
581
582
ulong nid;
582
583
bool skin = false;
583
584
bool turn = false;
584
585
bool frame = false;
585
586
if (!ulong.TryParse(netid, out nid) || !bool.TryParse(skinperm, out skin) || !bool.TryParse(rotateperm, out turn) || !bool.TryParse(breakperm, out frame)) { return null; }
586
587
BaseNetworkable bn = BaseNetworkable.serverEntities.Find(new NetworkableId(nid));
587
588
if (bn == null || !(bn is Door)) { return null; }
588
589
589
590
var container = new CuiElementContainer();
590
591
container.Add(new CuiElement
591
592
{
592
593
Name = "GD2P",
593
594
Parent = "Overlay",
594
595
DestroyUi = "GD2P",
595
596
Components =
596
597
{
597
598
new CuiNeedsCursorComponent(),
598
599
new CuiImageComponent{ Color = "1 1 1 0" },
599
600
new CuiRectTransformComponent{ AnchorMin = "0 0", AnchorMax = "1 1", OffsetMin = "0 0", OffsetMax = "0 0" }
600
601
}
601
602
});
602
603
603
604
container.Add(new CuiElement
604
605
{
605
606
Name = "GD2GUI",
606
607
Parent = "GD2P",
607
608
DestroyUi = "GD2GUI",
608
609
Components =
609
610
{
610
611
new CuiNeedsCursorComponent(),
611
612
new CuiImageComponent{ Color = ".18 .18 .18 1" },
612
613
new CuiRectTransformComponent{ AnchorMin = string.Format("{0} {1}", lang[3], lang[4]), AnchorMax = string.Format("{0} {1}", lang[5], lang[6]) }
613
614
}
614
615
});
615
616
616
617
container.Add(new CuiButton
617
618
{
618
619
Button = { Color = (turn ? "1 1 1 1" : ".5 .5 .5 1"), Command = (turn ? "GD2GUI R " + netid : "") },
619
620
Text = { Text = lang[0], FontSize = 18, Align = TextAnchor.MiddleCenter, Color = "0 0 0 1" },
620
621
RectTransform = { AnchorMin = ".5 .5", AnchorMax = ".5 .5", OffsetMin = "-42.84 -72", OffsetMax = "43.23 -48" }
621
622
}, "GD2GUI", "RBtn");
622
623
623
624
container.Add(new CuiButton
624
625
{
625
626
Button = { Color = (skin ? "1 1 1 1" : ".5 .5 .5 1"), Command = (skin ? "GD2GUI S " + netid + " " + skinid : "") },
626
627
Text = { Text = lang[1], FontSize = 18, Align = TextAnchor.MiddleCenter, Color = "0 0 0 1" },
627
628
RectTransform = { AnchorMin = ".5 .5", AnchorMax = ".5 .5", OffsetMin = "-42.84 -45", OffsetMax = "43.23 -21" }
628
629
},
629
630
"GD2GUI",
630
631
"SBtn");
631
632
632
633
container.Add(new CuiButton
633
634
{
634
635
Button = { Color = (frame ? "1 1 1 1" : ".5 .5 .5 1"), Command = (frame ? "GD2GUI B " + netid + " " + skinid : "") },
635
636
Text = { Text = lang[2], FontSize = 18, Align = TextAnchor.MiddleCenter, Color = "0 0 0 1" },
636
637
RectTransform = { AnchorMin = ".5 .5", AnchorMax = ".5 .5", OffsetMin = "-42.84 -99", OffsetMax = "43.23 -75" }
637
638
}, "GD2GUI", "BBtn");
638
639
639
640
container.Add(new CuiElement
640
641
{
641
642
Name = "SIcon",
642
643
Parent = "GD2GUI",
643
644
Components = {
644
645
new CuiImageComponent { Color = "1 1 1 1", SkinId = ulong.Parse(skinid), ItemId = -148794216 },
645
646
new CuiOutlineComponent { Color = "0 0 0 .5", Distance = "1 -1" },
646
647
new CuiRectTransformComponent { AnchorMin = ".5 .5", AnchorMax = ".5 .5", OffsetMin = "-42 10", OffsetMax = "42 90" }
647
648
}
648
649
});
649
650
650
651
container.Add(new CuiElement
651
652
{
652
653
Name = "SLabel",
653
654
Parent = "GD2GUI",
654
655
Components = {
655
656
new CuiTextComponent { Text = lang[1]+":", FontSize = 12, Align = TextAnchor.MiddleLeft, Color = "1 1 1 1" },
656
657
new CuiOutlineComponent { Color = "0 0 0 .5", Distance = "1 -1" },
657
658
new CuiRectTransformComponent { AnchorMin = ".5 .5", AnchorMax = ".5 .5", OffsetMin = "-43.48 -10", OffsetMax = "-.48 10" }
658
659
}
659
660
});
660
661
661
662
container.Add(new CuiButton
662
663
{
663
664
Button = { Color = "1 1 1 1", Close = "GD2P" },
664
665
Text = { Text = "X", FontSize = 7, Align = TextAnchor.MiddleCenter, Color = "1 0 0 1" },
665
666
RectTransform = { AnchorMin = ".5 .5", AnchorMax = ".5 .5", OffsetMin = "43.72 101.11", OffsetMax = "53.99 111.55" }
666
667
}, "GD2GUI", "CBtn");
667
668
668
669
container.Add(new CuiElement
669
670
{
670
671
Name = "SIn",
671
672
Parent = "GD2GUI",
672
673
Components = {
673
674
new CuiInputFieldComponent { Color = "1 1 1 1", FontSize = 10, Align = TextAnchor.UpperLeft, CharsLimit = 11, IsPassword = false, ReadOnly = !skin, Text = skinid , Command = "GD2GUI P " + netid },
674
675
new CuiRectTransformComponent { AnchorMin = ".5 .5", AnchorMax = ".5 .5", OffsetMin = "-15.04 -20", OffsetMax = "43.71 5" }
675
676
}
676
677
});
677
678
return container;
678
679
}
679
680
680
681
private void DrawCUI(BasePlayer player, Door garagedoor, string skinid)
681
682
{
682
683
if (player == null || garagedoor == null) { return; }
683
684
CuiHelper.AddUi(player, RustUI(garagedoor.net.ID.Value.ToString(), skinid, plugin.permission.UserHasPermission(player.UserIDString, plugin.PermS).ToString(), (plugin.permission.UserHasPermission(player.UserIDString, plugin.PermR) && !IsScaledGD(garagedoor)).ToString(), (plugin.permission.UserHasPermission(player.UserIDString, plugin.PermB) && (garagedoor?.GetParentEntity()?.prefabID == 372561515 || config.breakall)).ToString(), new string[] { plugin.message(player, "Rotate"), plugin.message(player, "Skin"), plugin.message(player, "Break"), plugin.config.MinX, plugin.config.MinY, plugin.config.MaxX, plugin.config.MaxY }));
684
685
}
685
686
private bool RandomChance(uint Seed, int Percentage)
686
687
{
687
688
//Create Chance List
688
689
List<bool> chance = Pool.Get<List<bool>>();
689
690
for (int i = 0; i < 100; i++)
690
691
{
691
692
if (i < Percentage)
692
693
{
693
694
chance.Add(true);
694
695
continue;
695
696
}
696
697
chance.Add(false);
697
698
}
698
699
chance.Shuffle(Seed); //shuffle
699
700
bool result = chance.ElementAt(UnityEngine.Random.Range(1, 100)); //Pick Random In Chance List
700
701
Pool.FreeUnmanaged(ref chance);
701
702
return result;
702
703
}
703
704
704
705
private bool IsRotatedGD(BaseEntity entity)
705
706
{
706
707
if (entity?.prefabID == 3647679950 && storedData.Rotated.Contains(entity.net.ID.Value)) // Rotated Garage Door
707
708
{
708
709
return true;
709
710
}
710
711
return false;
711
712
}
712
713
713
714
private bool IsScaledGD(BaseEntity entity)
714
715
{
715
716
if (config.Oversize && entity?.prefabID == 3647679950)
716
717
{
717
718
if (storedData.Scaled.Contains(entity.net.ID.Value))
718
719
{
719
720
return true;
720
721
}
721
722
}
722
723
return false;
723
724
}
724
725
725
726
private void MoveLockPos(BaseEntity baselock)
726
727
{
727
728
NextFrame(() =>
728
729
{
729
730
BaseEntity door = baselock.GetParentEntity();
730
731
if (door != null && IsRotatedGD(door))
731
732
{
732
733
baselock.transform.localPosition = door.transform.right * 1.40f;
733
734
baselock.SendNetworkUpdateImmediate();
734
735
}
735
736
});
736
737
}
737
738
738
739
private void RotateDoor(Door gd)
739
740
{
740
741
if (!string.IsNullOrEmpty(config.SoundFX)) { Effect.server.Run(config.SoundFX, gd.transform.position); }
741
742
gd.transform.localRotation *= Quaternion.Euler(90, 0, 0);
742
743
gd.transform.position += gd.transform.forward * -1.5f + gd.transform.up * -1.5f;
743
744
gd.SendNetworkUpdateImmediate();
744
745
}
745
746
746
747
private bool PickedUpGrageDoor(BasePlayer player, BaseEntity entity)
747
748
{
748
749
if (IsRotatedGD(entity)) //Garage Door
749
750
{
750
751
Item RotatedGarageDoor = ItemManager.CreateByItemID(1948067030, 1, config.CustomSkinID);
751
752
RotatedGarageDoor.name = message(player, "DoorName");
752
753
RotatedGarageDoor.MarkDirty();
753
754
GiveItem(player, RotatedGarageDoor, message(player, "DoorName"), -1, false); //Create a turned garage door (ladder hatch skinned) and add to save data
754
755
storedData.SID.Add(RotatedGarageDoor.uid.Value, entity.skinID);
755
756
storedData.Rotated.Remove(entity.net.ID.Value);
756
757
Interface.Oxide.DataFileSystem.WriteObject(Name, storedData);
757
758
NextFrame(() => { entity.Kill(BaseNetworkable.DestroyMode.None); }); //Destroy the entity that tried to be picked up
758
759
return true; //PickedUp
759
760
}
760
761
return false;
761
762
}
762
763
763
764
private void BreakFrame(Door door)
764
765
{
765
766
if (door != null)
766
767
{
767
768
//Get floor frame from parent
768
769
BaseEntity be = door.GetParentEntity();
769
770
if (be == null)
770
771
{
771
772
List<BuildingBlock> bb = Pool.Get<List<BuildingBlock>>();
772
773
Vis.Entities<BuildingBlock>(door.transform.position, 5, bb);
773
774
foreach (BuildingBlock bp in bb)
774
775
{
775
776
if (bp.prefabID == 919059809)
776
777
{
777
778
be = bp;
778
779
break;
779
780
}
780
781
}
781
782
Pool.FreeUnmanaged(ref bb);
782
783
}
783
784
if (be is BuildingBlock)
784
785
{
785
786
if (be.prefabID == 372561515 || config.breakall) //Floor Frame
786
787
{
787
788
door.grounded = true;
788
789
door.SetParent(null, true, true); //Unparent
789
790
////Recenter door if scaling
790
791
if (config.Oversize)
791
792
{
792
793
door.transform.position = door.transform.position + door.transform.up * -.25f;
793
794
ScaleDoor(door);
794
795
storedData.Scaled.Add(door.net.ID.Value);
795
796
Interface.Oxide.DataFileSystem.WriteObject(Name, storedData);
796
797
}
797
798
NextFrame(() => //Remove floor frame
798
799
{
799
800
if (!string.IsNullOrEmpty(config.FSoundFX)) { Effect.server.Run(config.FSoundFX, be.transform.position); }
800
801
be.Kill();
801
802
});
802
803
}
803
804
}
804
805
}
805
806
}
806
807
807
808
private void ScaleDoor(Door door)
808
809
{
809
810
door.networkEntityScale = true;
810
811
door.transform.localScale = new Vector3(1.11f, 1.11f, 1.11f);
811
812
door.SendNetworkUpdateImmediate();
812
813
}
813
814
814
815
private void GiveItem(BasePlayer player, Item item, string message, int slot, bool SFX = true)
815
816
{
816
817
if (SFX && !string.IsNullOrEmpty(config.SoundFX)) { Effect.server.Run(config.SoundFX, player.transform.position); } //Check if should use SFX
817
818
timer.Once(1f, () =>
818
819
{
819
820
//Wait 1 sec before trying to move item
820
821
if (item.MoveToContainer(player.inventory.containerBelt, slot))
821
822
{
822
823
MessageUI(player, item, message);
823
824
return;
824
825
}
825
826
if (item.MoveToContainer(player.inventory.containerMain, slot)) //Couldnt move into hotbar try main
826
827
{
827
828
MessageUI(player, item, message);
828
829
return;
829
830
}
830
831
item.Drop(player.inventory.containerMain.dropPosition, player.inventory.containerMain.dropVelocity); //Couldnt move onto player so drop
831
832
MessageUI(player, item, message);
832
833
});
833
834
}
834
835
835
836
private void MessageUI(BasePlayer player, Item item, string message) //Give UI notice
836
837
{
837
838
if (!string.IsNullOrEmpty(message)) { player.Command("note.inv", item.info.itemid, item.amount, message, 0); }
838
839
else { player.Command("note.inv", item.info.itemid, item.amount, string.Empty, 0); }
839
840
}
840
841
841
842
private void CheckDeploy(Planner plan, BaseEntity entity) //Check if should place
842
843
{
843
844
if (entity == null || plan == null || entity?.prefabID != 1655365262) { return; } //Only run on ladder hatches
844
845
BasePlayer player = plan?.GetParentEntity() as BasePlayer; //Get player
845
846
if (player == null) { return; } //No player so dont run
846
847
Item LadderHatch = plan.GetItem(); //Get dummy item
847
848
StabilityEntity stabilityEntity = (entity as StabilityEntity);
848
849
//Check if is blocked already
849
850
if (stabilityEntity?.GetNearbyBuildingBlock()?.children?.Count != 0) //Frame is already full
850
851
{
851
852
//Fix for detecting barges which have no foundation
852
853
bool Hasfoundation = false;
853
854
foreach (var bb in stabilityEntity.GetBuilding()?.buildingBlocks)
854
855
{
855
856
if (bb.PrefabName.Contains("foundation"))
856
857
{
857
858
Hasfoundation = true;
858
859
break;
859
860
}
860
861
}
861
862
if (!Hasfoundation && entity.skinID != config.CustomSkinID)
862
863
{
863
864
//Barge so ignore rest of my code
864
865
return;
865
866
}
866
867
Item active = player?.GetActiveItem(); //Get held item incase of stack
867
868
if (active != null && active.amount > 0 && active.info.itemid == 1948067030)
868
869
{
869
870
//Give back to stack
870
871
active.amount++;
871
872
active.MarkDirty();
872
873
}
873
874
else
874
875
{
875
876
//Create new item
876
877
Item NewLadderHatch = ItemManager.CreateByItemID(1948067030, 1, 0); //Create Item To Give Back Since Place Was Blocked
877
878
NewLadderHatch.name = message(player, "DoorName");
878
879
NewLadderHatch.MarkDirty();
879
880
//Check if its a custom ladder hatch if so update sav data file.
880
881
if (storedData.SID.ContainsKey(LadderHatch.uid.Value))
881
882
{
882
883
storedData.SID.Add(NewLadderHatch.uid.Value, storedData.SID[LadderHatch.uid.Value]);
883
884
storedData.SID.Remove(LadderHatch.uid.Value);
884
885
NewLadderHatch.skin = config.CustomSkinID;
885
886
Interface.Oxide.DataFileSystem.WriteObject(Name, storedData);
886
887
}
887
888
//Give item back
888
889
GiveItem(player, NewLadderHatch, message(player, "Blocked"), LadderHatch.position, false);
889
890
}
890
891
NextTick(() =>
891
892
{
892
893
if (!Hasfoundation) { player.ChatMessage(message(player, "NoFoundation")); }
893
894
entity?.Kill();
894
895
}); //Destroy Dummy
895
896
return;
896
897
}
897
898
if (entity.skinID == config.CustomSkinID)
898
899
{
899
900
//Create horizontal garage door in frame
900
901
StabilityEntity Gdoor = GameManager.server.CreateEntity(GarageDoor, entity.transform.position + (entity.transform.right * 1.5f) + (entity.transform.up * 0.18f), entity.transform.rotation * Quaternion.Euler(0, 0, 90f)) as StabilityEntity;
901
902
if (Gdoor == null) { NextTick(() => { entity?.Kill(); }); return; } //Prefab failed to load/spawn, bail out instead of crashing
902
903
Gdoor.Spawn();
903
904
if (LastUsedSkin.ContainsKey(player.userID)) { Gdoor.skinID = LastUsedSkin[player.userID]; }
904
905
else if (storedData.SID.ContainsKey(LadderHatch.uid.Value))
905
906
{
906
907
Gdoor.skinID = storedData.SID[LadderHatch.uid.Value];
907
908
storedData.SID.Remove(LadderHatch.uid.Value);
908
909
}
909
910
Gdoor.creatorEntity = player;
910
911
Gdoor.OwnerID = entity.OwnerID;
911
912
Gdoor.grounded = true;
912
913
Gdoor.pickup.enabled = true;
913
914
storedData.Rotated.Add(Gdoor.net.ID.Value);
914
915
Interface.Oxide.DataFileSystem.WriteObject(Name, storedData);
915
916
BuildingBlock buildingBlock = (entity as StabilityEntity).GetNearbyBuildingBlock();
916
917
if (buildingBlock == null || buildingBlock.prefabID == 372561515)//.ShortPrefabName != "floor.frame") //Fix for stability bunkers parenting to wrong building block.
917
918
{
918
919
int distance = 15;
919
920
foreach (var block in (entity as StabilityEntity).GetBuilding()?.buildingBlocks)
920
921
{
921
922
if (block.prefabID == 372561515)
922
923
{
923
924
float d = Vector3.Distance(block.transform.position, entity.transform.position);
924
925
if (d < distance)
925
926
{
926
927
distance = (int)d;
927
928
buildingBlock = block;
928
929
}
929
930
}
930
931
}
931
932
}
932
933
Gdoor.SetParent((entity as StabilityEntity).GetNearbyBuildingBlock(), true, true); //Parent to frame to stop other things placing
933
934
NextTick(() => { entity?.Kill(); }); //Remove dummy ladder hatch.
934
935
}
935
936
}
936
937
937
938
private void Take(BasePlayer player, int itemid, int amount)
938
939
{
939
940
var collect = Facepunch.Pool.Get<List<Item>>();
940
941
player.inventory.Take(collect, itemid, amount); // Take only calls RemoveFromContainer
941
942
foreach (Item item in collect)
942
943
{
943
944
item.Remove();
944
945
}
945
946
Facepunch.Pool.FreeUnmanaged(ref collect);
946
947
}
947
948
948
949
private BaseEntity FindBaseEntity(Ray ray)
949
950
{
950
951
//Ray cast to find BaseEntity
951
952
RaycastHit hit;
952
953
var raycast = UnityEngine.Physics.Raycast(ray, out hit, 4, -1);
953
954
BaseEntity entity = raycast ? hit.GetEntity() : null;
954
955
if (entity != null) { return entity; }
955
956
return null;
956
957
}
957
958
958
959
private bool AddDoorController(Door garagedoor)
959
960
{
960
961
var pos = garagedoor.transform.position + garagedoor.transform.up * 2.9f + garagedoor.transform.forward * -1.3f; //Roller position
961
962
//Set to normal position
962
963
if (!config.MoveController)
963
964
{
964
965
pos = garagedoor.transform.position + garagedoor.transform.up * 1.2f + garagedoor.transform.forward * -1.3f;
965
966
}
966
967
if (IsScaledGD(garagedoor))
967
968
{
968
969
pos += garagedoor.transform.up * 0.3f; //Add extra offset if door already scaled
969
970
}
970
971
//Create and setup door controller
971
972
DoorManipulator dc = GameManager.server.CreateEntity(DoorController, pos, garagedoor.transform.rotation) as DoorManipulator;
972
973
if (dc != null)
973
974
{
974
975
dc.Spawn();
975
976
dc.OwnerID = garagedoor.OwnerID;
976
977
dc.SetParent(garagedoor, true, false);
977
978
dc.transform.localRotation *= Quaternion.Euler(0, 90, 0);
978
979
dc.SendNetworkUpdateImmediate();
979
980
garagedoor.Invoke(delegate { dc.SetTargetDoor(garagedoor); }, 0.25f);
980
981
return true;
981
982
}
982
983
return false;
983
984
}
984
985
#endregion
985
986
986
987
#region Class
987
988
public class DoorControllerPlacer : MonoBehaviour
988
989
{
989
990
public BasePlayer player;
990
991
991
992
public void FixedUpdate()
992
993
{
993
994
try //Try and catch incase something in the future changes to prevent null references
994
995
{
995
996
if (player == null || player.IsSleeping() || player?.GetActiveItem()?.info?.itemid != -502177121) { Destroy(this); } //Destroy component when conditions are no longer meet
996
997
else if (player.serverInput.WasJustReleased(BUTTON.FIRE_PRIMARY)) //Catch mouse fire button
997
998
{
998
999
if (player.IsBuildingBlocked()) { return; } //Check player isnt building blocked
999
1000
Door door = plugin.FindBaseEntity(player.eyes.HeadRay()) as Door; //Get Door being looked at
1000
1001
if (door != null && plugin.IsRotatedGD(door)) //Garage Door
1001
1002
{
1002
1003
foreach (var child in door.children) { if (child != null && child is DoorManipulator) { return; } } //Make sure doesnt already have door controller
1003
1004
if (plugin.AddDoorController(door))
1004
1005
{
1005
1006
Effect.server.Run(Deploy, player.PivotPoint(), player.transform.up, null, true);
1006
1007
player.inventory.Take(null, -502177121, 1); //Remove door controller from player inventory if it attached
1007
1008
if (player.inventory.GetAmount(-502177121) == 0) { Destroy(this); return; } //Checks player has any door controllers left
1008
1009
}
1009
1010
}
1010
1011
}
1011
1012
}
1012
1013
catch { Destroy(this); } //Something went wrong so remove CUI
1013
1014
}
1014
1015
}
1015
1016
1016
1017
public class GUIWindow : MonoBehaviour
1017
1018
{
1018
1019
public BasePlayer player;
1019
1020
public float tick;
1020
1021
public Vector3 pos = Vector3.zero;
1021
1022
1022
1023
public void OnDestroy() { if (player != null) { CuiHelper.DestroyUi(player, "GD2P"); } }
1023
1024
1024
1025
public void FixedUpdate()
1025
1026
{
1026
1027
try //Try and catch incase something in the future changes to prevent null references
1027
1028
{
1028
1029
//Only check twice a sec
1029
1030
if (tick > UnityEngine.Time.realtimeSinceStartup) { return; }
1030
1031
tick = UnityEngine.Time.realtimeSinceStartup + 0.5f;
1031
1032
if (player == null || player.IsSleeping() || player?.GetActiveItem()?.info?.itemid != 200773292) { Destroy(this); } //Destroy component when conditions are no longer meet
1032
1033
if (pos != Vector3.zero && Vector3Ex.Distance2D(player.transform.position, pos) > 0.5f) //Moved to far away
1033
1034
{
1034
1035
CuiHelper.DestroyUi(player, "GD2P"); //Destory CUI
1035
1036
pos = Vector3.zero; //Reset Position
1036
1037
return;
1037
1038
}
1038
1039
if (player.serverInput.IsDown(BUTTON.FIRE_SECONDARY) || player.serverInput.IsDown(BUTTON.FIRE_THIRD)) //Catch mouse right button
1039
1040
{
1040
1041
if (!player.IsBuildingAuthed()) { return; } //Check player is building Auth
1041
1042
Door door = plugin.FindBaseEntity(player.eyes.HeadRay()) as Door; //Get Door being looked at
1042
1043
if (door != null && door.prefabID == 3647679950) //Garage Door
1043
1044
{
1044
1045
pos = player.transform.position;
1045
1046
plugin.DrawCUI(player, door, door.skinID.ToString());
1046
1047
}
1047
1048
}
1048
1049
}
1049
1050
catch { Destroy(this); } //Something went wrong so remove CUI
1050
1051
}
1051
1052
}
1052
1053
#endregion
1053
1054
}
1054
1055
}