← Back to changelog
What changed
EggExtra · v1.0.0 → v1.0.1 (current)
Diff
2 added · 2 removed · 314 → 314 total lines
1
1
/*▄▄▄ ███▄ ▄███▓ ▄████ ▄▄▄██▀▀▀▓█████▄▄▄█████▓
2
2
▓█████▄ ▓██▒▀█▀ ██▒ ██▒ ▀█▒ ▒██ ▓█ ▀▓ ██▒ ▓▒
3
3
▒██▒ ▄██▓██ ▓██░▒██░▄▄▄░ ░██ ▒███ ▒ ▓██░ ▒░
4
4
▒██░█▀ ▒██ ▒██ ░▓█ ██▓▓██▄██▓ ▒▓█ ▄░ ▓██▓ ░
5
5
░▓█ ▀█▓▒██▒ ░██▒░▒▓███▀▒ ▓███▒ ░▒████▒ ▒██▒ ░
6
6
░▒▓███▀▒░ ▒░ ░ ░ ░▒ ▒ ▒▓▒▒░ ░░ ▒░ ░ ▒ ░░
7
7
▒░▒ ░ ░ ░ ░ ░ ░ ▒ ░▒░ ░ ░ ░ ░
8
8
░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░
9
9
░ ░ ░ ░ ░ ░ ░*/
10
10
using System;
11
11
using System.Collections.Generic;
12
12
using System.Linq;
13
13
using HarmonyLib;
14
14
using Newtonsoft.Json;
15
15
using Oxide.Core.Plugins;
16
16
using UnityEngine;
17
17
namespace Oxide.Plugins
18
18
{
19
-
[Info("EggExtra", "bmgjet", "1.0.0")]
19
+
[Info("EggExtra", "bmgjet", "1.0.1")]
20
20
[Description("Allows eggs to be used as bait and compost")]
21
21
class EggExtra : RustPlugin
22
22
{
23
23
public static EggExtra plugin;
24
24
private const int eggItemId = 1858828593;
25
25
private const string guntrapprefab = "assets/prefabs/deployable/single shot trap/guntrap.deployed.prefab";
26
26
private string permKFC = "eggextra.kfc";
27
27
28
28
#region Configuration
29
29
private Configuration config;
30
30
private class Configuration
31
31
{
32
32
[JsonProperty("BaitValue (Higher Value = Better Loot From Fish Traps)")]
33
33
public float BaitValue = 1;
34
34
35
35
[JsonProperty("MaxBaitStack (How Many To Use Per Fish Trap Attempt)")]
36
36
public int MaxBaitStack = 1;
37
37
38
38
[JsonProperty("TotalFertilizerProduced (How Much Fertilizer Per Egg)")]
39
39
public float TotalFertilizerProduced = 0.5f;
40
40
41
41
[JsonProperty("Try Auto Hatch Until Max Chickens")]
42
42
public bool AutoHatch = true;
43
43
44
44
[JsonProperty("Try To Auto Hatch Eggs In Chicken Coop On Chicken Death")]
45
45
public bool DeathHatch = true;
46
46
47
47
public string ToJson() => JsonConvert.SerializeObject(this);
48
48
49
49
public Dictionary<string, object> ToDictionary() => JsonConvert.DeserializeObject<Dictionary<string, object>>(ToJson());
50
50
}
51
51
52
52
protected override void LoadDefaultConfig() { config = new Configuration(); }
53
53
protected override void LoadConfig()
54
54
{
55
55
base.LoadConfig();
56
56
try
57
57
{
58
58
config = Config.ReadObject<Configuration>();
59
59
if (config == null) { throw new JsonException(); }
60
60
61
61
if (!config.ToDictionary().Keys.SequenceEqual(Config.ToDictionary(x => x.Key, x => x.Value).Keys))
62
62
{
63
63
PrintWarning("Configuration appears to be outdated; updating and saving");
64
64
SaveConfig();
65
65
}
66
66
67
67
SanitizeConfig();
68
68
}
69
69
catch
70
70
{
71
71
PrintWarning($"Configuration file {Name}.json is invalid; using defaults");
72
72
LoadDefaultConfig();
73
73
}
74
74
}
75
75
protected override void SaveConfig()
76
76
{
77
77
PrintWarning($"Configuration changes saved to {Name}.json");
78
78
Config.WriteObject(config, true);
79
79
}
80
80
81
81
private void SanitizeConfig()
82
82
{
83
83
//Prevent a bad hand-edited json from producing broken/negative bait values
84
84
if (config.BaitValue < 0f) { config.BaitValue = 0f; }
85
85
if (config.MaxBaitStack < 1) { config.MaxBaitStack = 1; }
86
86
if (config.TotalFertilizerProduced < 0f) { config.TotalFertilizerProduced = 0f; }
87
87
}
88
88
#endregion Configuration
89
89
90
90
#region OxideHooks
91
91
private void Init()
92
92
{
93
93
plugin = this;
94
94
Unsubscribe(nameof(OnEntitySpawned)); //Stop hooking on server startup
95
95
permission.RegisterPermission(permKFC, this);
96
96
}
97
97
98
98
private void OnServerInitialized()
99
99
{
100
100
PatchEggs(true); //Catch Everything
101
101
Subscribe(nameof(OnEntitySpawned)); //Catch fishtraps from now on.
102
102
}
103
103
104
104
private void OnEntitySpawned(WildlifeTrap trap) { PatchTrap(trap); }
105
105
106
106
private void Unload()
107
107
{
108
108
PatchEggs(false);
109
109
plugin = null;
110
110
}
111
111
112
112
public void HatchEgg(ChickenCoop __instance)
113
113
{
114
114
if (__instance.HasFlag(BaseEntity.Flags.Reserved3) || __instance.HasFlag(BaseEntity.Flags.Reserved1))
115
115
{
116
116
return;
117
117
}
118
118
119
119
Item slot = __instance.inventory.GetSlot(0);
120
120
if (slot != null && slot.info == ChickenCoop.EggDef)
121
121
{
122
122
slot.UseItem();
123
123
__instance.Animals.Add(new ChickenCoop.AnimalStatus
124
124
{
125
125
TimeUntilHatch = __instance.ChickenHatchTimeMinutes * 60f
126
126
});
127
127
using (ChickenCoop.FlagsUpdateScope flagsUpdateScope = __instance.StartSetFlags(BaseEntity.FlagsUpdateMode.SendNetworkUpdate))
128
128
{
129
129
flagsUpdateScope.Set(BaseEntity.Flags.Reserved1, b: true);
130
130
flagsUpdateScope.Set(BaseEntity.Flags.Reserved3, __instance.Animals.Count >= __instance.MaxChickens);
131
131
}
132
132
133
133
if (!__instance.IsInvoking(__instance.CheckEggHatchState))
134
134
{
135
135
__instance.InvokeRepeating(__instance.CheckEggHatchState, 10f, 10f);
136
136
}
137
137
138
138
__instance.SendNetworkUpdate();
139
139
}
140
140
}
141
141
142
142
[ChatCommand("KFC")] //Chat Command
143
143
private void CommandSpawnKFC(BasePlayer player, string command, string[] args)
144
144
{
145
145
if (permission.UserHasPermission(player.UserIDString, permKFC))
146
146
{
147
147
var coop = FindEntity(player.eyes.HeadRay());
148
148
if (coop == null)
149
149
{
150
150
player.ChatMessage("You Must Be Looking At A Chicken Coop!");
151
151
return;
152
152
}
153
153
foreach (var c in coop.children)
154
154
{
155
155
if (c is GunTrap)
156
156
{
157
157
player.ChatMessage("Already Has GunTrap!");
158
158
return;
159
159
}
160
160
}
161
161
if (player.inventory.Take(null, 352499047, 1) > 0)
162
162
{
163
163
SpawnPart(coop, Quaternion.Euler(90, 0, 0), new Vector3(0f, 1f, -1.2f));
164
164
return;
165
165
}
166
166
player.ChatMessage("You Must Have A Gun Trap On You!");
167
167
}
168
168
}
169
169
#endregion
170
170
171
171
#region Methods
172
172
private BaseEntity SpawnPart(BaseEntity parent, Quaternion rotoffset, Vector3 posoffset)
173
173
{
174
174
//Spawns in parts of the quarry
175
175
BaseEntity baseent = GameManager.server.CreateEntity(guntrapprefab, parent.transform.position, parent.transform.rotation);
176
176
if (baseent == null)
177
177
{
178
178
PrintWarning($"Failed to create entity from prefab '{guntrapprefab}'");
179
179
return null;
180
180
}
181
181
baseent.OwnerID = parent.OwnerID;
182
182
baseent.Spawn();
183
183
//Remove componants to stop it breaking
184
184
foreach (var mesh in baseent.GetComponentsInChildren<MeshCollider>()) { UnityEngine.Object.DestroyImmediate(mesh); }
185
185
UnityEngine.Object.DestroyImmediate(baseent.GetComponent<DestroyOnGroundMissing>());
186
186
UnityEngine.Object.DestroyImmediate(baseent.GetComponent<GroundWatch>());
187
187
//Parent it to base entity
188
188
baseent.SetParent(parent, true, true);
189
189
//Adjust offset positions
190
190
if (rotoffset != Quaternion.Euler(0, 0, 0)) { baseent.transform.rotation = baseent.transform.rotation * rotoffset; }
191
191
if (posoffset != new Vector3(0, 0, 0)) { baseent.transform.localPosition = posoffset; }
192
192
baseent.SendNetworkUpdateImmediate();
193
193
return baseent;
194
194
}
195
195
196
196
private ChickenCoop FindEntity(Ray ray)
197
197
{
198
198
//Ray cast to find BaseEntity
199
199
RaycastHit hit;
200
200
var raycast = Physics.Raycast(ray, out hit, 6, -1);
201
201
BaseEntity entity = raycast ? hit.GetEntity() : null;
202
202
if (entity is ChickenCoop)
203
203
{
204
204
return entity as ChickenCoop;
205
205
}
206
206
return null;
207
207
}
208
208
209
-
private bool CanAcceptItem(Item item, int slot)
209
+
private bool CanAcceptItem(BasePlayer basePlayer, Item item, int slot)
210
210
{
211
211
var compostable = item.info.GetComponent<ItemModCompostable>();
212
212
return compostable?.BaitValue > 0; //Has Bail Value
213
213
}
214
214
215
215
private void PatchTrap(WildlifeTrap trap, bool apply = true)
216
216
{
217
217
//Add/remove custom allow on everything that has bait value which eggs now do.
218
218
if (trap?.inventory == null) { return; }
219
219
var inv = trap.inventory;
220
220
if (apply) { inv.canAcceptItem += CanAcceptItem; }
221
221
else { inv.canAcceptItem -= CanAcceptItem; }
222
222
}
223
223
224
224
private void PatchEggs(bool apply)
225
225
{
226
226
int traps = 0;
227
227
foreach (var entity in BaseNetworkable.serverEntities)
228
228
{
229
229
if (entity is WildlifeTrap trap)
230
230
{
231
231
PatchTrap(trap, apply);
232
232
traps++;
233
233
}
234
234
}
235
235
foreach (var item in ItemManager.GetAllItems())
236
236
{
237
237
if (item.info.itemid != eggItemId) { continue; }
238
238
//Change Values Of Eggs So Can Be Bait And Compost
239
239
var compostable = item.info.GetComponent<ItemModCompostable>();
240
240
if (compostable == null) { continue; }
241
241
//Use Config values or set back to 0 default
242
242
compostable.BaitValue = apply ? config.BaitValue : 0;
243
243
compostable.MaxBaitStack = apply ? config.MaxBaitStack : 0;
244
244
compostable.TotalFertilizerProduced = apply ? config.TotalFertilizerProduced : 0;
245
245
}
246
246
Puts($"{(apply ? "Applied" : "Reverted")} custom values to eggs and {(apply ? "patched" : "unpatched")} {traps} fish traps.");
247
247
}
248
248
#endregion
249
249
250
250
#region Harmony
251
251
[AutoPatch]
252
252
[HarmonyPatch(typeof(ChickenCoop), "OnAnimalDied", typeof(FarmableAnimal))]
253
253
public static class ChickenCoop_OnAnimalDied
254
254
{
255
255
[HarmonyPostfix]
256
256
public static void Postfix(ChickenCoop __instance)
257
257
{
258
258
//Try Hatch New Chicken To Replace Dead
259
259
if (plugin.config.DeathHatch)
260
260
{
261
261
plugin.HatchEgg(__instance);
262
262
}
263
263
}
264
264
}
265
265
266
266
[AutoPatch]
267
267
[HarmonyPatch(typeof(ChickenCoop), "SpawnChicken", typeof(int))]
268
268
public static class ChickenCoop_SpawnChicken
269
269
{
270
270
[HarmonyPostfix]
271
271
public static void Postfix(ChickenCoop __instance)
272
272
{
273
273
if (plugin.config.AutoHatch)
274
274
{
275
275
plugin.NextFrame(() =>
276
276
{
277
277
//Try Maintain Max Chickens
278
278
if (__instance != null)
279
279
{
280
280
if (__instance.Animals.Count < __instance.MaxChickens)
281
281
{
282
282
plugin.HatchEgg(__instance);
283
283
}
284
284
if (__instance.Animals.Count != 0)
285
285
{
286
286
GunTrap trap = null;
287
287
foreach (var c in __instance.children)
288
288
{
289
289
if (c is GunTrap gt) { trap = gt; break; }
290
290
}
291
291
292
292
if (trap != null && plugin.permission.UserHasPermission(__instance.OwnerID.ToString(), plugin.permKFC))
293
293
{
294
294
foreach (ChickenCoop.AnimalStatus animalStatus in __instance.Animals)
295
295
{
296
296
EntityRef<FarmableAnimal> spawnedAnimal = animalStatus.SpawnedAnimal;
297
297
FarmableAnimal farmableAnimal = spawnedAnimal.Get(true);
298
298
if (farmableAnimal != null)
299
299
{
300
300
farmableAnimal.Hurt(9999);
301
301
plugin.NextFrame(() => { Effect.server.Run(trap.gun_fire_effect.resourcePath, trap, StringPool.Get(trap.muzzlePos.gameObject.name), Vector3.zero, Vector3.zero); });
302
302
return;
303
303
}
304
304
}
305
305
}
306
306
}
307
307
}
308
308
});
309
309
}
310
310
}
311
311
}
312
312
#endregion
313
313
}
314
314
}