· 4 years ago · Jul 14, 2021, 10:28 PM
1AUTHORS_NOTE = [[Spawn program made by DeGariless]]
2
3require("term").clear() local args = {...}
4
5
6
7--######################
8--## GLOBAL VARIABLES ##
9--######################
10print("Initializing Global Variables")
11
12local TIMEZONEDB_API_KEY = "YOUR_TIMEZONEDB_API_KEY_GOES_HERE"
13local VERSION = "1.1.1"
14local PAGETIME = 12 --Default: 12
15local TABWIDTH = 20 --Default: 20
16
17--Resolution
18local w = 87 --Default: 87
19local h = 25 --Default: 25
20
21if TIMEZONEDB == "YOUR_TIMEZONEDB_API_KEY_GOES_HERE" then
22 print("You needs a TimezoneDB API key")
23 print("Press any key to continue...")
24 event.pull("key_down")
25 error()
26end
27
28--###############
29--## LIBRARIES ##
30--###############
31print("Adding Custom Libraries")
32
33local component = require("component")
34local computer = require("computer")
35local inet = require("internet")
36local term = require("term")
37
38
39
40--################
41--## COMPONENTS ##
42--################
43print("Adding Components")
44
45assert(component.isAvailable("debug"), "No debug card installed")
46local db = component.debug
47local fs = component.filesystem
48local gpu = component.gpu
49
50
51
52local file = io.open("/usr/lib/json4lua.lua", "r")
53if file == nil then
54 file = io.open("/usr/lib/json4lua.lua", "w")
55 print("Downloading JSON4Lua library")
56 local result, response = pcall(inet.request, "https://raw.githubusercontent.com/craigmj/json4lua/master/json/json.lua")
57 assert(result, "Could not download JSON4Lua library")
58 print("Success")
59 for chunk in response do
60 file:write(chunk)
61 end
62 file:close()
63 print("file saved to /usr/lib/json4lua.lua")
64end
65file = nil
66print("Loading JSON4Lua library")
67local json = require("json4lua")
68
69
70--################
71--## LOAD FILES ##
72--################
73print("Loading Files.")
74
75file = io.open("/Rules.txt", "r")
76if file == nil then
77 print("Rules.txt not found. Creating default file.")
78 file = io.open("/Rules.txt", "w")
79 file:write("Add server rules in Rules.txt")
80 file:close()
81 file = io.open("/Rules.txt", "r")
82end
83local rules = file:read("*all")
84file:close()
85file = nil
86
87file = io.open("/PlayerData.json", "r")
88if file == nil then
89 print("PlayerData.json not found. Creating default file.")
90 file = io.open("/PlayerData.json", "w")
91 file:write('{"owner":[],"staff":[],"players":[]}')
92 file:close()
93 file = io.open("/PlayerData.json", "r")
94end
95local playerData = json.decode( file:read("*all") )
96file:close()
97file = nil
98
99file = io.open("/Announcements.txt", "r")
100if file == nil then
101 print("Announcements.txt not found. Creating default file.")
102 file = io.open("/Announcements.txt", "w")
103 file:write(" There are no server announcements at this time.")
104 file:close()
105 file = io.open("/Announcements.txt", "r")
106end
107local announcements = file:read("*all")
108file:close()
109file = nil
110
111file = io.open("/FAQ.txt", "r")
112if file == nil then
113 print("FAQ.txt not found. Creating default file.")
114 file = io.open("/FAQ.txt", "w")
115 file:write(" Q: How can I protect my base?\n A: Edit this answer in /FAQ.txt")
116 file:close()
117 file = io.open("/FAQ.txt", "r")
118end
119local faq = file:read("*all")
120file:close()
121file = nil
122
123
124
125--###########
126--## THEME ##
127--###########
128print("Setting theme.")
129
130local theme = {
131 bgLow = 0x004422,
132 bg = 0x006633,
133 bgHigh = 0x669966,
134 textLow = 0x999955,
135 text = 0xCC9933,
136 textHigh = 0xFFCC99,
137 online = 0x44FF44,
138 never = 0xFF8888,
139 err = 0xFF0000
140}
141
142--###############
143--## FUNCTIONS ##
144--###############
145print("Setting functions.")
146
147
148local function centerPrint(string, y)
149 local start = math.floor( (w - string:len()) / 2 )
150 term.setCursor(start, y)
151 term.write(string)
152end
153
154local function title(string)
155 gpu.setBackground(theme.bgHigh)
156 gpu.setForeground(theme.textHigh)
157 gpu.fill(1, 1, w, 4, " ")
158 centerPrint(string, 2)
159end
160
161local function clear()
162 gpu.setBackground(theme.bg)
163 gpu.setForeground(theme.text)
164 gpu.fill(1, 5, w, h-4, " ")
165 term.setCursor(1, 6)
166end
167
168local function writeFile(fileName)
169 local file = io.open(fileName, "r")
170 local text = file:read("*all")
171 file:close()
172 term.write(text)
173end
174
175local function time()
176 local req = nil
177 local data = ""
178 req = inet.request("http://api.timezonedb.com/v2.1/get-time-zone?key=" .. TIMEZONEDB_API_KEY .. "&format=json&by=zone&zone=America/Los_Angeles")
179 for line in req do
180 data = data .. line
181 end
182 return json.decode(data).timestamp
183end
184
185
186local function timeHuman(dif)
187 --dif is in seconds
188 if dif < 5 then
189 return "a moment ago"
190 elseif dif < 60 then
191 return(dif .. " seconds ago")
192 end
193 dif = math.floor(dif/6+0.5)/10 -- convert dif to minutes
194 if dif <= 1 then
195 return "a minute ago"
196 elseif dif < 60 then
197 return(dif .. " minutes ago")
198 end
199 dif = math.floor(dif/6+0.5)/10 -- convert dif to hours
200 if dif == 1 then
201 return "an hour ago"
202 elseif dif < 24 then
203 return(dif.." hours ago")
204 end
205 dif = math.floor(dif/24) --dif is in days
206 if dif == 1 then
207 return "yesterday"
208 elseif dif < 7 then
209 return(dif.." days ago")
210 elseif dif < 14 then
211 return "last week"
212 elseif dif < 30 then
213 return(math.floor(dif/7).." weeks ago")
214 elseif dif < 61 then
215 return "last month"
216 elseif dif < 365 then
217 return(math.floor(dif/30.5).." months ago")
218 end
219 dif = math.floor(dif/36.5+0.5)/10 -- dif is in years
220 if dif == 1 then
221 return "last year"
222 else
223 return(dif.." years ago")
224 end
225end
226
227local function orderPlayerData()
228 local orderedPlayers = {}
229
230 for _, player in pairs(playerData.players) do
231 local found = false
232 for k, oPlayer in pairs(orderedPlayers) do
233 if tonumber(player.lastseen) > tonumber(oPlayer.lastseen) then
234 found = true
235 table.insert(orderedPlayers, k, player)
236 break
237 end
238 end
239 if not found then
240 table.insert(orderedPlayers, #orderedPlayers+1, player)
241 end
242 end
243 playerData.players = orderedPlayers
244end
245
246
247local function updatePlayerData(curTime)
248 for _, onlinePlayer in ipairs(db.getPlayers()) do
249 local found = false
250 for _, v in pairs(playerData.owner) do
251 if onlinePlayer == v.name then
252 v.lastseen = curTime
253 found = true
254 break
255 end
256 end
257 if not found then
258 for _, v in pairs(playerData.staff) do
259 if onlinePlayer == v.name then
260 v.lastseen = curTime
261 found = true
262 break
263 end
264 end
265 end
266 if not found then
267 for _, v in pairs(playerData.players) do
268 if onlinePlayer == v.name then
269 v.lastseen = curTime
270 found = true
271 break
272 end
273 end
274 end
275 if not found then
276 newPlayerData = {name = onlinePlayer, lastseen = curTime, firstseen = curTime}
277 table.insert(playerData.players, newPlayerData)
278 end
279 end
280 orderPlayerData()
281 local file = io.open("PlayerData.json", "w")
282 file:write(json.encode(playerData))
283 file:close()
284end
285
286local function lastseen(player, curTime)
287 local status = db.getPlayer(player.name).getGameType()
288 if status == "spectator" or status == nil then
289 if player.lastseen == 0 then
290 return "Never"
291 end
292 return timeHuman(curTime - player.lastseen)
293 else
294 return "Online"
295 end
296end
297
298
299--
300--TAB GENERATOR
301--
302
303local function tabs(...)
304 term.setCursor(1, 4)
305 local args = {...}
306 local highTab = args[#args]
307 gpu.setBackground(theme.bgHigh)
308 gpu.setForeground(theme.textLow)
309 for i=1, #args-1 do
310 term.write(" ")
311 if i == highTab then
312 gpu.setForeground(theme.textHigh)
313 gpu.setBackground(theme.bg)
314 term.write(" ".. args[i] .." ")
315 gpu.setForeground(theme.textLow)
316 gpu.setBackground(theme.bgHigh)
317 else
318 gpu.setBackground(theme.bgLow)
319 term.write(" "..args[i].." ")
320 gpu.setBackground(theme.bgHigh)
321 end
322 end
323 gpu.setBackground(theme.bg)
324 gpu.setForeground(theme.text)
325end
326
327
328
329--
330--PAGE GENERATORS
331--
332
333local function rulesPage()
334 term.write(rules)
335end
336
337
338local function lastseenPage(curTime)
339 print(" Owner "..string.rep("_", 93))
340 gpu.setForeground(theme.textHigh)
341 term.write(" Name"..string.rep(" ", TABWIDTH - 4).."Last seen\n")
342 gpu.setForeground(theme.text)
343 for k,v in ipairs(playerData.owner) do
344 term.write(" "..v.name)
345 term.write(string.rep(".", TABWIDTH - #v.name))
346 local status = lastseen(v, curTime)
347 if status == "Online" then
348 gpu.setForeground(theme.online)
349 elseif status == "Never" then
350 gpu.setForeground(theme.never)
351 end
352 term.write(status)
353 gpu.setForeground(theme.text)
354 if k%2 == 0 then
355 print()
356 else
357 term.write(string.rep(" ", TABWIDTH - #status - 2))
358 end
359 end
360 term.write("\n\n")
361
362 print(" Staff "..string.rep("_", 93))
363 gpu.setForeground(theme.textHigh)
364 term.write(" Name"..string.rep(" ", TABWIDTH - 4).."Last seen\n")
365 gpu.setForeground(theme.text)
366 for k,v in ipairs(playerData.staff) do
367 term.write(" "..v.name)
368 term.write(string.rep(".", TABWIDTH - #v.name))
369 local status = lastseen(v, curTime)
370 if status == "Online" then
371 gpu.setForeground(theme.online)
372 elseif status == "Never" then
373 gpu.setForeground(theme.never)
374 end
375 term.write(status)
376 gpu.setForeground(theme.text)
377 if k%2 == 0 then
378 print()
379 else
380 term.write(string.rep(" ", TABWIDTH - #status - 2))
381 end
382 end
383 term.write("\n\n")
384
385 print(" Players "..string.rep("_", 91))
386 gpu.setForeground(theme.textHigh)
387 term.write(" Name"..string.rep(" ", TABWIDTH-4).."Last seen\n")
388 gpu.setForeground(theme.text)
389 for k, v in ipairs(playerData.players) do
390 term.write(" " .. v.name)
391 term.write(string.rep(".", TABWIDTH - #v.name))
392 local status = lastseen(v, curTime)
393 if status == "Online" then
394 gpu.setForeground(theme.online)
395 elseif status == "Never" then
396 gpu.setForeground(theme.never)
397 end
398 term.write(status)
399 gpu.setForeground(theme.text)
400 if k%2 == 0 then
401 print()
402 else
403 term.write(string.rep(" ", TABWIDTH - #status - 2))
404 end
405 local _, y = term.getCursor()
406 if y >= h then
407 return
408 end
409 end
410end
411
412local function announcementsPage()
413 term.write(announcements)
414end
415
416local function faqPage()
417 term.write(faq)
418end
419
420--###################
421--## MAIN FUNCTION ##
422--###################
423print("Starting Program")
424
425local function main()
426 gpu.setResolution(w, h)
427 title("Welcome to the server!")
428 while true do
429 tabs("Rules","Players","Announcements","FAQ",1)
430 clear()
431 rulesPage()
432 os.sleep(PAGETIME)
433 local curTime = time()
434 if curTime then
435 updatePlayerData(curTime)
436 tabs("Rules","Players","Announcements","FAQ",2)
437 clear()
438 lastseenPage(curTime)
439 os.sleep(PAGETIME)
440 end
441 tabs("Rules","Players","Announcements","FAQ",3)
442 clear()
443 announcementsPage()
444 os.sleep(PAGETIME)
445 tabs("Rules","Players","Announcements","FAQ",4)
446 clear()
447 faqPage()
448 os.sleep(PAGETIME)
449 end
450end
451
452
453
454--##########
455--## MAIN ##
456--##########
457
458local _, traceback, _ = xpcall(main, debug.traceback)
459
460
461
462--#################
463--## ERROR CATCH ##
464--#################
465
466gpu.setBackground(0x000000)
467gpu.setForeground(0xFFFFFF)
468gpu.fill(1, 1, w, h, " ")
469term.setCursor(1, 1)
470print()
471print(" Oh noes! The spawn program has crashed D:")
472print(" Please create an issue on github")
473print(" http://github.com/DeGariless/OC-Server-Spawn/")
474print(" make sure to include this error message...")
475print(" -----------")
476gpu.setForeground(theme.err)
477print(traceback)
478gpu.setForeground(0xFFFFFF)
479print()
480print(" Press any key to continue...")
481event.pull("key_down")