← Back to changelog
What changed
ShredMe · v1.0.0 → v1.0.1 (current)
Diff
4 added · 3 removed · 372 → 373 total lines
1
1
/*▄▄▄ ███▄ ▄███▓ ▄████ ▄▄▄██▀▀▀▓█████▄▄▄█████▓
2
2
▓█████▄ ▓██▒▀█▀ ██▒ ██▒ ▀█▒ ▒██ ▓█ ▀▓ ██▒ ▓▒
3
3
▒██▒ ▄██▓██ ▓██░▒██░▄▄▄░ ░██ ▒███ ▒ ▓██░ ▒░
4
4
▒██░█▀ ▒██ ▒██ ░▓█ ██▓▓██▄██▓ ▒▓█ ▄░ ▓██▓ ░
5
5
░▓█ ▀█▓▒██▒ ░██▒░▒▓███▀▒ ▓███▒ ░▒████▒ ▒██▒ ░
6
6
░▒▓███▀▒░ ▒░ ░ ░ ░▒ ▒ ▒▓▒▒░ ░░ ▒░ ░ ▒ ░░
7
7
▒░▒ ░ ░ ░ ░ ░ ░ ▒ ░▒░ ░ ░ ░ ░
8
8
░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░
9
9
░ ░ ░ ░ ░ ░ ░
10
10
Chat Commands:
11
11
/shredinfo - Output shortname, If shreddable and its output.
12
12
13
13
Config Layout:
14
14
{"EntityShortName": "","scrapReward": [{"ShortName": "","Amount": 0},]},
15
15
*/
16
16
using Facepunch;
17
17
using HarmonyLib;
18
18
using Newtonsoft.Json;
19
19
using Oxide.Core.Plugins;
20
20
using System;
21
21
using System.Collections;
22
22
using System.Collections.Generic;
23
23
using System.Linq;
24
24
using UnityEngine;
25
25
26
26
namespace Oxide.Plugins
27
27
{
28
-
[Info("ShredMe", "bmgjet", "1.0.0")]
28
+
[Info("ShredMe", "bmgjet", "1.0.1")]
29
29
[Description("Makes other entitys shredable")]
30
30
class ShredMe : RustPlugin
31
31
{
32
32
//Store default values to restore on unload
33
33
private int _maxDistanceFromOrigin = -1;
34
34
private float _idleFuelPerSec = -1;
35
35
private float _maxFuelPerSec = -1;
36
36
//List of shortnames to improve lookup speed of things to mod
37
37
private List<string> AllowedMod = new List<string>();
38
38
private Dictionary<string, MagnetLiftable> Defaults = new Dictionary<string, MagnetLiftable>();
39
39
//Co-Routine to prevent locking main thing on large entity servers.
40
40
Coroutine _coroutine;
41
41
42
42
#region Configuration
43
43
private Configuration config;
44
44
45
45
private class Configuration
46
46
{
47
47
[JsonProperty("Magnetic Crane Unlimited Roam Range")]
48
48
public bool OutOfJunkyard = false;
49
49
50
50
[JsonProperty("Magnetic Crane Unlimited Fuel")]
51
51
public bool UnlimitedFuel = false;
52
52
53
53
[JsonProperty("Entity To Make Magnet Liftable/Shredable")]
54
54
public List<Shreddable> ShreddableList;
55
55
56
56
public string ToJson() => JsonConvert.SerializeObject(this);
57
57
58
58
public Dictionary<string, object> ToDictionary() => JsonConvert.DeserializeObject<Dictionary<string, object>>(ToJson());
59
59
}
60
60
61
61
protected override void LoadDefaultConfig() => config = new Configuration();
62
62
63
63
protected override void LoadConfig()
64
64
{
65
65
base.LoadConfig();
66
66
try
67
67
{
68
68
config = Config.ReadObject<Configuration>();
69
69
if (config == null) { throw new JsonException(); }
70
70
if (!config.ToDictionary().Keys.SequenceEqual(Config.ToDictionary(x => x.Key, x => x.Value).Keys))
71
71
{
72
72
PrintWarning("Configuration appears to be outdated; updating and saving");
73
73
SaveConfig();
74
74
}
75
75
}
76
76
catch
77
77
{
78
78
PrintWarning($"Configuration file {Name}.json is invalid; using defaults");
79
79
LoadDefaultConfig();
80
80
}
81
81
if (config.ShreddableList == null)
82
82
{
83
83
PrintWarning("Loading Default Shred List");
84
84
config.ShreddableList = new List<Shreddable>
85
85
{
86
86
new Shreddable().init("minicopter.entity", new Dictionary<string, int> { { "scrap", 150 }, { "metal.fragments", 100 }, { "metalblade", 4 } }),
87
87
new Shreddable().init("scraptransporthelicopter", new Dictionary<string, int> { { "scrap", 250 }, { "metal.fragments", 200 }, { "metalblade", 4 }, { "roadsigns", 5 } }),
88
88
new Shreddable().init("attackhelicopter.entity", new Dictionary<string, int> { { "scrap", 350 }, { "metal.fragments", 300 }, { "metalblade", 4 }, { "roadsigns", 5 }, { "metalpipe", 12 }, { "metal.refined", 5 } }),
89
89
new Shreddable().init("rhib", new Dictionary<string, int> { { "scrap", 80 }, { "metal.fragments", 25 }, { "metalblade", 2 } }),
90
90
new Shreddable().init("rowboat", new Dictionary<string, int> { { "scrap", 50 }, { "wood", 50 }, { "metalblade", 2 } }),
91
91
new Shreddable().init("submarineduo.entity", new Dictionary<string, int> { { "scrap", 60 }, { "metalpipe", 5 }, { "propanetank", 5 } }),
92
92
new Shreddable().init("submarinesolo.entity", new Dictionary<string, int> { { "scrap", 50 }, { "metalpipe", 4 }, { "propanetank", 4 } })
93
93
};
94
94
Config.WriteObject(config, true);
95
95
}
96
96
//Fill List with shortnames
97
97
if (config.ShreddableList != null && config.ShreddableList.Count() != 0)
98
98
{
99
99
foreach (var modlist in config.ShreddableList) { AllowedMod.Add(modlist.EntityShortName); }
100
100
}
101
101
}
102
102
103
103
protected override void SaveConfig()
104
104
{
105
105
PrintWarning($"Configuration changes saved to {Name}.json");
106
106
Config.WriteObject(config, true);
107
107
}
108
108
#endregion Configuration
109
109
110
110
#region Classes
111
111
//Config to hold Info
112
112
public class Shreddable
113
113
{
114
114
public string EntityShortName;
115
115
public List<ScrapReward> scrapReward = new List<ScrapReward>();
116
116
public Shreddable init(string shortname, Dictionary<string, int> reward)
117
117
{
118
118
EntityShortName = shortname;
119
119
foreach (var keyvalue in reward) { scrapReward.Add(new ScrapReward().init(keyvalue.Key, keyvalue.Value)); }
120
120
return this;
121
121
}
122
122
}
123
123
124
124
//Config to hold reward
125
125
public class ScrapReward
126
126
{
127
127
public string ShortName;
128
128
public int Amount;
129
129
public ScrapReward init(string shortname, int amount)
130
130
{
131
131
ShortName = shortname;
132
132
Amount = amount;
133
133
return this;
134
134
}
135
135
}
136
136
#endregion
137
137
138
138
#region Oxide Hooks
139
139
[ChatCommand("shredinfo")] //Gets shortname
140
140
private void shreddableinfo(BasePlayer player, string command, string[] Args)
141
141
{
142
142
if (player.IsAdmin) //limit to admin
143
143
{
144
144
//Find entity being looked at
145
145
RaycastHit hit;
146
146
var raycast = UnityEngine.Physics.Raycast(player.eyes.HeadRay(), out hit, 10, -1);
147
147
BaseEntity entity = raycast ? hit.GetEntity() : null;
148
148
if (entity != null)
149
149
{
150
150
//Output info
151
151
string info = "Shortname: " + entity.ShortPrefabName + " Shredable: ";
152
152
MagnetLiftable comp = entity?.gameObject?.GetComponent<MagnetLiftable>();
153
153
if (comp != null)
154
154
{
155
155
info += (bool)comp + " Output:";
156
156
foreach (var o in comp.shredResources) { info += o.itemDef.shortname + "(" + o.amount + ") "; }
157
157
}
158
158
else { info += (bool)comp; }
159
159
player.ChatMessage(info);
160
160
}
161
161
}
162
162
}
163
163
164
164
private void Init() { Unsubscribe(nameof(OnEntitySpawned)); } //Unsubscribe hook so doesnt waste catching stuff on server startup.
165
165
166
166
private void OnServerInitialized() { if (AllowedMod.Count > 0) { _coroutine = ServerMgr.Instance.StartCoroutine(Startup(true)); } } //Start up in coroutine
167
167
168
168
private void OnEntitySpawned(BaseCombatEntity ent) { NextFrame(() => { ModEntitys(ent, true); }); } //Need to wait a frame for it to fully spawn.
169
169
170
170
private void Unload()
171
171
{
172
172
if (_coroutine != null) { ServerMgr.Instance.StopCoroutine(_coroutine); }; //Stop corutine if still running from startup
173
173
_coroutine = ServerMgr.Instance.StartCoroutine(Startup(false));//Unload everything.
174
174
}
175
175
176
176
#endregion
177
177
178
178
#region Methods
179
179
180
180
//Run in coroutine so large entity count servers to lag playing on load/unload of plugin.
181
181
private IEnumerator Startup(bool Load)
182
182
{
183
183
int checks = 0;
184
184
int last = 0;
185
185
int done = 0;
186
186
int modded = 0;
187
187
int loops = BaseNetworkable.serverEntities.entityList.Get().Count();
188
188
foreach (var ent in BaseNetworkable.serverEntities.entityList.Get().Values.ToList()) //List since might be changed during wait times.
189
189
{
190
190
checks++;
191
191
done++;
192
192
if (Load && ++checks >= 10000) //Check conditions so many loops
193
193
{
194
194
//Limit rate based on FPS
195
195
if (Performance.report.frameRate < 15 && ConVar.FPS.limit > 15) { yield return CoroutineEx.waitForSeconds(0.01f); }
196
196
else { yield return CoroutineEx.waitForSeconds(0.0035f); }
197
197
checks = 0;
198
198
//Output Percentage Debug
199
199
if (done > last)
200
200
{
201
201
last += (loops / 5);
202
202
Puts("Scanning entitys " + (int)Math.Round((double)(100 * done) / loops) + "%");
203
203
}
204
204
}
205
205
try { modded += ModEntitys(ent, Load); } catch { } //Catch catch where something was in process of destroy during the wait.
206
206
}
207
207
Puts((Load ? "Done, Modded " : "Unmodded ") + modded + " Entitys");
208
208
if (Load) { Subscribe(nameof(OnEntitySpawned)); }
209
209
_coroutine = null;
210
210
}
211
211
212
212
private bool IsDivisible(int x, int n) { return (x % n) == 0; }
213
213
214
214
private ItemAmount[] DefaultScrap() { return new ItemAmount[] { new ItemAmount(ItemManager.FindItemDefinition("scrap"), 1) }; } //Default value for if config bad
215
215
216
216
private void AddCustomReward(Shreddable configdata, MagnetLiftable comp)
217
217
{
218
218
if (configdata.scrapReward == null || configdata.scrapReward.Count == 0) //No reward set in config so give a default.
219
219
{
220
220
comp.shredResources = DefaultScrap();
221
221
return;
222
222
}
223
223
//Create config reward
224
224
List<ItemAmount> rewarditems = new List<ItemAmount>();
225
225
foreach (var r in configdata.scrapReward) { if (r != null) { rewarditems.Add(new ItemAmount(ItemManager.FindItemDefinition(r.ShortName), r.Amount)); } }
226
226
comp.shredResources = rewarditems.ToArray();
227
227
//Make sure its not null or empty or shredder gets jammed in null ref.
228
228
if (comp.shredResources == null || comp.shredResources.Length == 0) { comp.shredResources = DefaultScrap(); }
229
229
}
230
230
231
231
private int ModEntitys(BaseNetworkable ent, bool load)
232
232
{
233
233
if (ent == null || ent.IsDestroyed) { return 0; } //Make sure valid
234
234
//Crane mods
235
235
if (ent is MagnetCrane)
236
236
{
237
237
ModCrane((MagnetCrane)ent, load);
238
238
return 1;
239
239
}
240
240
//Everything else
241
241
return MakeShreddable(ent, load);
242
242
}
243
243
244
244
private void ModCrane(MagnetCrane crane, bool load)
245
245
{
246
246
if (config.OutOfJunkyard)
247
247
{
248
248
if (_maxDistanceFromOrigin == -1) { _maxDistanceFromOrigin = (int)crane.maxDistanceFromOrigin; } //Store Value for Unload
249
249
crane.maxDistanceFromOrigin = load ? 0 : _maxDistanceFromOrigin; //0 = unlimited
250
250
}
251
251
if (config.UnlimitedFuel) //Unlimited fuel.
252
252
{
253
253
if (_idleFuelPerSec == -1) //Plugin doesnt have defaults for unload so save them
254
254
{
255
255
_idleFuelPerSec = crane.idleFuelPerSec;
256
256
_maxFuelPerSec = crane.maxFuelPerSec;
257
257
}
258
258
crane.idleFuelPerSec = load ? 0 : _idleFuelPerSec; //0 = unlimited
259
259
crane.maxFuelPerSec = load ? 0 : _maxFuelPerSec; //0 = unlimited
260
260
StorageContainer fuelContainer = BaseNetworkable.serverEntities.Find(crane.GetFuelSystem().GetInstanceID()) as StorageContainer;
261
261
if (fuelContainer != null)
262
262
{
263
263
if (load)
264
264
{
265
265
//Give 1 fuel and lock fuel container
266
266
fuelContainer.inventory.AddItem(fuelContainer.allowedItem, 1);
267
-
fuelContainer.SetFlag(BaseEntity.Flags.Locked, true);
267
+
fuelContainer.SetFlagLocal(BaseEntity.Flags.Locked, true);
268
268
return;
269
269
}
270
270
//Unload
271
271
if (fuelContainer.HasFlag(BaseEntity.Flags.Locked))
272
272
{
273
273
//Remove fuel item and unlock container
274
274
fuelContainer.inventory.Clear();
275
-
fuelContainer.SetFlag(BaseEntity.Flags.Locked, false);
275
+
fuelContainer.SetFlagLocal(BaseEntity.Flags.Locked, false);
276
276
}
277
+
fuelContainer.SendNetworkUpdateImmediate();
277
278
}
278
279
}
279
280
}
280
281
281
282
private int MakeShreddable(BaseNetworkable ent, bool add = true)
282
283
{
283
284
if (AllowedMod.Contains(ent.ShortPrefabName)) //Check its a entity to target
284
285
{
285
286
MagnetLiftable comp = ent?.gameObject?.GetComponent<MagnetLiftable>(); //Get componant if it already has it
286
287
if (!add) //Unload
287
288
{
288
289
if (comp != null)
289
290
{
290
291
if (Defaults.ContainsKey(ent.ShortPrefabName)){comp.shredResources = Defaults[ent.ShortPrefabName].shredResources;}
291
292
else{GameObject.Destroy(comp);}
292
293
}
293
294
return 1;
294
295
}
295
296
foreach (var configdata in config.ShreddableList) //Find config
296
297
{
297
298
if (configdata != null && configdata.EntityShortName == ent.ShortPrefabName) //Found
298
299
{
299
300
if (comp == null)
300
301
{
301
302
comp = ent.gameObject.AddComponent<MagnetLiftable>(); //Add Componant
302
303
AddCustomReward(configdata, comp);
303
304
return 1;
304
305
}
305
306
else if (comp != null) //Mod native item that is MagnetLiftable
306
307
{
307
308
AddCustomReward(configdata, comp);
308
309
return 1;
309
310
}
310
311
}
311
312
}
312
313
}
313
314
else if (ent is BaseVehicle)
314
315
{
315
316
MagnetLiftable comp = ent?.gameObject?.GetComponent<MagnetLiftable>();
316
317
if (comp != null)
317
318
{
318
319
Defaults.Add(ent.ShortPrefabName, comp);
319
320
Dictionary<string, int> dict = new Dictionary<string, int>();
320
321
foreach (var i in comp.shredResources) { dict.Add(ItemManager.FindItemDefinition(i.itemid).shortname, (int)i.amount); }
321
322
Shreddable shreddable = new Shreddable().init(ent.ShortPrefabName, dict);
322
323
config.ShreddableList.Add(shreddable);
323
324
Puts("Found Default Item " + ent.ShortPrefabName);
324
325
AllowedMod.Add(ent.ShortPrefabName);
325
326
Config.WriteObject(config, true);
326
327
}
327
328
}
328
329
return 0;
329
330
}
330
331
#endregion
331
332
332
333
[AutoPatch]
333
334
[HarmonyPatch(typeof(LargeShredder), "OnEntityEnteredTrigger", new Type[] { typeof(BaseEntity) })]
334
335
internal class LargeShredder_OnEntityEnteredTrigger
335
336
{
336
337
[HarmonyPrefix]
337
338
private static bool Prefix(BaseEntity ent, LargeShredder __instance, ref Quaternion ___entryRotation)
338
339
{
339
340
try
340
341
{
341
342
if (ent.IsDestroyed)
342
343
{
343
344
return false;
344
345
}
345
346
Rigidbody component = ent.GetComponent<Rigidbody>();
346
347
if (__instance.isShredding || __instance.currentlyShredding != null)
347
348
{
348
349
if (!component.isKinematic)
349
350
{
350
351
component.velocity = -component.velocity * 3f;
351
352
}
352
353
return false;
353
354
}
354
355
__instance.shredRail.transform.position = __instance.shredRailStartPos.position;
355
356
__instance.shredRail.transform.rotation = Quaternion.LookRotation(__instance.shredRailStartRotation);
356
357
___entryRotation = ent.transform.rotation;
357
358
Quaternion rotation = ent.transform.rotation;
358
359
component.isKinematic = true;
359
360
component.SetActive(false);
360
361
__instance.currentlyShredding = ent;
361
362
ent.transform.rotation = rotation;
362
363
__instance.isShredding = true;
363
364
__instance.SetShredding(true);
364
365
__instance.shredStartTime = Time.realtimeSinceStartup;
365
366
return false;
366
367
}
367
368
catch { }
368
369
return true;
369
370
}
370
371
}
371
372
}
372
373
}