-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSignUploadAPI.cs
270 lines (251 loc) · 11.7 KB
/
SignUploadAPI.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Plugins;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("SignUploadAPI", "Bunsen", "1.0.0")]
[Description("Upload the contents of a sign the player is looking at to Imgur. Optional DiscordCore and ServerRewards integration. https://github.com/Tyler-Lopez/SignUploadAPI")]
public class SignUploadAPI : RustPlugin
{
#region Plug-in References
[PluginReference] private Plugin ServerRewards;
[PluginReference] private Plugin ImgurApi;
[PluginReference] private Plugin DiscordCore;
#endregion
#region Global Variables and Typography
private HashSet<ulong> signUploadCooldown = new HashSet<ulong>();
private ulong imageIcon = 76561198317970917;
private string h1 = "<size=15><color=#F0A92C>";
private string h2 = "<size=12><color=green>";
private string sub = "<size=11><color=#B3B3B3>";
private string p = "<size=12><color=#E8E8E8>";
private string close = "</color></size>";
private string colorClose = "</color>";
private string highlight = "<color=yellow>";
#endregion
#region Oxide Hooks
// Initialize permission.
void Init()
{
permission.RegisterPermission("signuploadapi.use", this); // Required to use SignUploadAPI
permission.RegisterPermission("signuploadapi.free", this); // If given and Use Server Rewards is enabled, deducts no RP upon use of SignUploadAPI.
}
void OnServerInitialized()
{
if (ImgurApi == null) Puts("You are missing ImgurApi, get it here: https://umod.org/plugins/imgur-api");
if (config.useServerRewards && ServerRewards == null) Puts("You are missing Server Rewards, get it here: https://umod.org/plugins/server-rewards");
if (config.useDiscordCore && DiscordCore == null) Puts("You are missing Server Rewards, get it here: https://umod.org/plugins/discord-core");
cmd.AddChatCommand(config.command, this, "uploadSignFromRaycast");
lang.RegisterMessages(messages, this);
}
#endregion
#region Handle Sign-Uploading
void uploadSignFromRaycast(BasePlayer player, string command, string[] args)
{
// The following are various causes of error the player may encounter.
if (!permission.UserHasPermission(player.UserIDString, "signuploadapi.use"))
{
SendErrorPlayer(player, $"{p}{lang.GetMessage("noPermission", this, player.UserIDString)}{close}");
return;
}
if (config.cooldown > 0 && signUploadCooldown.Contains(player.userID))
{
SendErrorPlayer(player, $"{p}{lang.GetMessage("cooldownError", this, player.UserIDString)}{close}");
return;
}
if ((config.useServerRewards && getPoints(player) < config.cost) && !permission.UserHasPermission(player.UserIDString, "signuploadapi.free"))
{
SendErrorPlayer(player, $"{p}{lang.GetMessage("currencyError", this, player.UserIDString)} {highlight}{lang.GetMessage("currency", this, player.UserIDString)}{colorClose}!{close}");
return;
}
// Using Raycast, find the entity in front of the player.
BaseEntity sign = entityRaycast(player);
// If there was no entity detected handle the error.
if (sign == null)
{
SendErrorPlayer(player, $"{p}{lang.GetMessage("notLookingAtValid", this, player.UserIDString)}{close}");
return;
}
// If the player specifys a first argument, make it the title of the uploaded picture. Else, set to Untitled.
string title = args.Length < 1 ? lang.GetMessage("noTitle", this, player.UserIDString) : args[0];
if (sign is PhotoFrame)
{
PhotoFrame signPF = sign as PhotoFrame;
BaseEntity photoEntity = null;
// Is the photoframe holding a photo? If so - upload the contents of the picture instead.
if(signPF.inventory.itemList.Count() > 0) photoEntity = signPF.children.First();
if (photoEntity != null && photoEntity.ShortPrefabName == "photo.entity")
{
var data = FileStorage.server.Get(((PhotoEntity)photoEntity).ImageCrc, FileStorage.Type.png, sign.net.ID);
if (data != null)
{
UploadImage(data, player, title);
return;
}
}
}
else if (sign is Signage)
{
var data = FileStorage.server.Get(((Signage)sign).textureIDs.First(), FileStorage.Type.png, sign.net.ID);
if (data != null)
{
UploadImage(data, player, title);
return;
}
}
else
{
SendErrorPlayer(player, $"{p}{lang.GetMessage("notLookingAtValid", this, player.UserIDString)}{close}");
return;
}
}
private void UploadImage(byte[] image, BasePlayer player, string info)
{
// The following callback is called by the ImgurAPI plugin containing response information. This may take a few seconds.
Action<Hash<string, object>> action = (hashSet) =>
{
bool success = (bool)hashSet["Success"];
if (!success)
{
SendErrorPlayer(player, $"{p} \n\n{JsonConvert.SerializeObject(hashSet)}{close}");
return;
}
Hash<string, object> data = hashSet["Data"] as Hash<string, object>;
if (config.useDiscordCore)
{
DiscordCore?.Call("SendMessageToUser", player.userID.ToString(), $"{data?["Link"]}");
if (config.channelName != null) DiscordCore?.Call("SendMessageToChannel", config.channelName, $"\n\n**{lang.GetMessage("discordMessage", this, player.UserIDString)} {player.displayName}**\n{data?["Link"]}");
}
if (config.useServerRewards && !permission.UserHasPermission(player.UserIDString, "signuploadapi.free"))
{
takePoints(player, config.cost);
}
SendReplyWithIcon(player, $"{h1}{lang.GetMessage("success", this, player.UserIDString)}{close}\n" +
$"{p}{lang.GetMessage("fileAccessedAt", this, player.UserIDString)} {highlight}{data?["Link"]}{close}" + (config.useServerRewards ? $"{sub}\n{config.cost} {lang.GetMessage("rpWithdrawl", this, player.UserIDString)}{close}" : ""));
Interface.CallHook("OnSignUploaded", info, player.userID);
};
// Inform the player their sign is uploading.
SendReplyWithIcon(player, $"{h2}{lang.GetMessage("uploading", this, player.UserIDString)}{close}");
// If the cooldown configuration setting is set to greater than 0 seconds, add them to a HashSet of users then remove them from it after the specificed time.
if (config.cooldown > 0)
{
signUploadCooldown.Add(player.userID);
timer.Once(config.cooldown, () =>
{
signUploadCooldown.Remove(player.userID);
});
}
ImgurApi?.Call("UploadImage", image, action, info);
}
#endregion
#region Helper Functions
private BaseEntity entityRaycast(BasePlayer player)
{
RaycastHit RayHit;
var flag1 = Physics.Raycast(player.eyes.HeadRay(), out RayHit, 20f);
var baseEntity = flag1 ? RayHit.GetEntity() : null;
return baseEntity;
}
private void SendErrorPlayer(BasePlayer player, string message)
{
Effect.server.Run("assets/prefabs/locks/keypad/effects/lock.code.denied.prefab",
player.transform.position);
SendReplyWithIcon(player, $"<size=15><color=red>{lang.GetMessage("error", this, player.UserIDString)}</color></size> " + message);
}
private void SendReplyWithIcon(BasePlayer player, string message)
{
Player.Message(player, message, imageIcon);
}
#endregion
#region Handle Server Rewards
private int getPoints(BasePlayer player)
{
if (config.useServerRewards)
{
object answer = ServerRewards?.Call<int>("CheckPoints", player.userID);
if (answer != null) return (int)answer;
}
return 0;
}
private bool takePoints(BasePlayer player, int amount)
{
if (config.useServerRewards)
{
object answer = ServerRewards?.Call<int>("TakePoints", player.userID, amount);
if (answer == null) return false;
else return true;
}
return false;
}
#endregion
#region Plug-in Configuration
private static ConfigData config;
private class ConfigData
{
[JsonProperty(PropertyName = "Chat Command")]
public string command;
[JsonProperty(PropertyName = "Use Discord Core")]
public bool useDiscordCore;
[JsonProperty(PropertyName = "Discord Channel to Upload to")]
public string channelName;
[JsonProperty(PropertyName = "Use Server Rewards")]
public bool useServerRewards;
[JsonProperty(PropertyName = "Cost to Upload")]
public int cost;
[JsonProperty(PropertyName = "Cooldown Between Uploads (seconds)")]
public float cooldown;
}
private ConfigData getDefaultConfig()
{
ConfigData output = new ConfigData
{
command = "uploadsign",
useDiscordCore = false,
channelName = "",
useServerRewards = false,
cost = 20,
cooldown = 30
};
return output;
}
protected override void LoadConfig()
{
base.LoadConfig();
try
{
config = Config.ReadObject<ConfigData>();
}
catch
{
Puts("Config data is corrupted, replacing with default");
config = new ConfigData();
}
SaveConfig();
}
protected override void SaveConfig() => Config.WriteObject(config);
protected override void LoadDefaultConfig() => config = getDefaultConfig();
#endregion
#region Localization
Dictionary<string, string> messages = new Dictionary<string, string>()
{
{"noPermission", "You don't have the appropriate permission to use this."},
{"notLookingAtValid", "You weren't looking at a sign or photoframe." },
{"uploadError", "An error occured uploading the image" },
{"error", "Error. " },
{"uploading", "Uploading..." },
{"rpWithdrawl", "RP deducted" },
{"noTitle", "Untitled" },
{"fileAccessedAt", "The file may be accessed at" },
{"success", "Successful Upload." },
{"currencyError", "You don't have enough" },
{"currency", "RP" },
{"cooldownError", "You're trying to use this command again too soon." },
{"discordMessage", "NEW IMAGE UPLOADED BY" }
};
#endregion
}
}