· 11 years ago · Jul 04, 2015, 12:52 AM
1--[[
2
3 NotAshley's loadstring fix.
4
5 Credit to einsteinK, as well as the creators of LuLu for the parser. This parser now supports local variables.
6
7 Credit to Reinitialized and NecroBumpist for the VM and RBX.lua sandboxing scripts.
8
9]]
10
11local luaZ = {}
12
13------------------------------------------------------------------------
14-- * reader() should return a string, or nil if nothing else to parse.
15-- Additional data can be set only during stream initialization
16-- * Readers are handled in lauxlib.c, see luaL_load(file|buffer|string)
17-- * LUAL_BUFFERSIZE=BUFSIZ=512 in make_getF() (located in luaconf.h)
18-- * Original Reader typedef:
19-- const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz);
20-- * This Lua chunk reader implementation:
21-- returns string or nil, no arguments to function
22------------------------------------------------------------------------
23
24------------------------------------------------------------------------
25-- create a chunk reader from a source string
26------------------------------------------------------------------------
27function luaZ:make_getS(buff)
28 local b = buff
29 return function() -- chunk reader anonymous function here
30 if not b then return nil end
31 local data = b
32 b = nil
33 return data
34 end
35end
36
37------------------------------------------------------------------------
38-- create a chunk reader from a source file
39------------------------------------------------------------------------
40function luaZ:make_getF(filename)
41 local LUAL_BUFFERSIZE = 512
42 local h = io.open(filename, "r")
43 if not h then return nil end
44 return function() -- chunk reader anonymous function here
45 if not h or io.type(h) == "closed file" then return nil end
46 local buff = h:read(LUAL_BUFFERSIZE)
47 if not buff then h:close(); h = nil end
48 return buff
49 end
50end
51
52------------------------------------------------------------------------
53-- creates a zio input stream
54-- returns the ZIO structure, z
55------------------------------------------------------------------------
56function luaZ:init(reader, data)
57 if not reader then return end
58 local z = {}
59 z.reader = reader
60 z.data = data or ""
61 z.name = name
62 -- set up additional data for reading
63 if not data or data == "" then z.n = 0 else z.n = #data end
64 z.p = 0
65 return z
66end
67
68------------------------------------------------------------------------
69-- fill up input buffer
70------------------------------------------------------------------------
71function luaZ:fill(z)
72 local buff = z.reader()
73 z.data = buff
74 if not buff or buff == "" then return "EOZ" end
75 z.n, z.p = #buff - 1, 1
76 return string.sub(buff, 1, 1)
77end
78
79------------------------------------------------------------------------
80-- get next character from the input stream
81-- * local n, p are used to optimize code generation
82------------------------------------------------------------------------
83function luaZ:zgetc(z)
84 local n, p = z.n, z.p + 1
85 if n > 0 then
86 z.n, z.p = n - 1, p
87 return string.sub(z.data, p, p)
88 else
89 return self:fill(z)
90 end
91end
92
93local luaZfunc = luaZ
94
95--[[--------------------------------------------------------------------
96
97 llex.lua
98 Lua lexical analyzer in Lua
99 This file is part of Yueliang.
100
101 Copyright (c) 2005-2006 Kein-Hong Man <khman@users.sf.net>
102 The COPYRIGHT file describes the conditions
103 under which this software may be distributed.
104
105 See the ChangeLog for more information.
106
107----------------------------------------------------------------------]]
108
109--[[--------------------------------------------------------------------
110-- Notes:
111-- * intended to 'imitate' llex.c code; performance is not a concern
112-- * tokens are strings; code structure largely retained
113-- * deleted stuff (compared to llex.c) are noted, comments retained
114-- * nextc() returns the currently read character to simplify coding
115-- here; next() in llex.c does not return anything
116-- * compatibility code is marked with "--Unknown command """, use #help to get a list
117--
118-- Added:
119-- * luaX:chunkid (function luaO_chunkid from lobject.c)
120-- * luaX:str2d (function luaO_str2d from lobject.c)
121-- * luaX.LUA_QS used in luaX:lexerror (from luaconf.h)
122-- * luaX.LUA_COMPAT_LSTR in luaX:read_long_string (from luaconf.h)
123-- * luaX.MAX_INT used in luaX:inclinenumber (from llimits.h)
124--
125-- To use the lexer:
126-- (1) luaX:init() to initialize the lexer
127-- (2) luaX:setinput() to set the input stream to lex
128-- (3) call luaX:next() or luaX:luaX:lookahead() to get tokens,
129-- until "TK_EOS": luaX:next()
130-- * since EOZ is returned as a string, be careful when regexp testing
131--
132-- Not implemented:
133-- * luaX_newstring: not required by this Lua implementation
134-- * buffer MAX_SIZET size limit (from llimits.h) test not implemented
135-- in the interest of performance
136-- * locale-aware number handling is largely redundant as Lua's
137-- tonumber() function is already capable of this
138--
139-- Changed in 5.1.x:
140-- * TK_NAME token order moved down
141-- * string representation for TK_NAME, TK_NUMBER, TK_STRING changed
142-- * token struct renamed to lower case (LS -> ls)
143-- * LexState struct: removed nestlevel, added decpoint
144-- * error message functions have been greatly simplified
145-- * token2string renamed to luaX_tokens, exposed in llex.h
146-- * lexer now handles all kinds of newlines, including CRLF
147-- * shbang first line handling removed from luaX:setinput;
148-- it is now done in lauxlib.c (luaL_loadfile)
149-- * next(ls) macro renamed to nextc(ls) due to new luaX_next function
150-- * EXTRABUFF and MAXNOCHECK removed due to lexer changes
151-- * checkbuffer(ls, len) macro deleted
152-- * luaX:read_numeral now has 3 support functions: luaX:trydecpoint,
153-- luaX:buffreplace and (luaO_str2d from lobject.c) luaX:str2d
154-- * luaX:read_numeral is now more promiscuous in slurping characters;
155-- hexadecimal numbers was added, locale-aware decimal points too
156-- * luaX:skip_sep is new; used by luaX:read_long_string
157-- * luaX:read_long_string handles new-style long blocks, with some
158-- optional compatibility code
159-- * luaX:llex: parts changed to support new-style long blocks
160-- * luaX:llex: readname functionality has been folded in
161-- * luaX:llex: removed test for control characters
162--
163--------------------------------------------------------------------]]
164
165local luaZ = luaZfunc
166
167local luaX = {}
168
169-- FIRST_RESERVED is not required as tokens are manipulated as strings
170-- TOKEN_LEN deleted; maximum length of a reserved word not needed
171
172------------------------------------------------------------------------
173-- "ORDER RESERVED" deleted; enumeration in one place: luaX.RESERVED
174------------------------------------------------------------------------
175
176-- terminal symbols denoted by reserved words: TK_AND to TK_WHILE
177-- other terminal symbols: TK_NAME to TK_EOS
178luaX.RESERVED = [[
179TK_AND and
180TK_BREAK break
181TK_DO do
182TK_ELSE else
183TK_ELSEIF elseif
184TK_END end
185TK_FALSE false
186TK_FOR for
187TK_FUNCTION function
188TK_IF if
189TK_IN in
190TK_LOCAL local
191TK_NIL nil
192TK_NOT not
193TK_OR or
194TK_REPEAT repeat
195TK_RETURN return
196TK_THEN then
197TK_TRUE true
198TK_UNTIL until
199TK_WHILE while
200TK_CONCAT ..
201TK_DOTS ...
202TK_EQ ==
203TK_GE >=
204TK_LE <=
205TK_NE ~=
206TK_NAME <name>
207TK_NUMBER <number>
208TK_STRING <string>
209TK_EOS <eof>]]
210
211-- NUM_RESERVED is not required; number of reserved words
212
213--[[--------------------------------------------------------------------
214-- Instead of passing seminfo, the Token struct (e.g. ls.t) is passed
215-- so that lexer functions can use its table element, ls.t.seminfo
216--
217-- SemInfo (struct no longer needed, a mixed-type value is used)
218--
219-- Token (struct of ls.t and ls.lookahead):
220-- token -- token symbol
221-- seminfo -- semantics information
222--
223-- LexState (struct of ls; ls is initialized by luaX:setinput):
224-- current -- current character (charint)
225-- linenumber -- input line counter
226-- lastline -- line of last token 'consumed'
227-- t -- current token (table: struct Token)
228-- lookahead -- look ahead token (table: struct Token)
229-- fs -- 'FuncState' is private to the parser
230-- L -- LuaState
231-- z -- input stream
232-- buff -- buffer for tokens
233-- source -- current source name
234-- decpoint -- locale decimal point
235-- nestlevel -- level of nested non-terminals
236----------------------------------------------------------------------]]
237
238-- luaX.tokens (was luaX_tokens) is now a hash; see luaX:init
239
240luaX.MAXSRC = 80
241luaX.MAX_INT = 2147483645 -- constants from elsewhere (see above)
242luaX.LUA_QS = "'%s'"
243luaX.LUA_COMPAT_LSTR = 1
244--luaX.MAX_SIZET = 4294967293
245
246------------------------------------------------------------------------
247-- initialize lexer
248-- * original luaX_init has code to create and register token strings
249-- * luaX.tokens: TK_* -> token
250-- * luaX.enums: token -> TK_* (used in luaX:llex)
251------------------------------------------------------------------------
252function luaX:init()
253 local tokens, enums = {}, {}
254 for v in string.gmatch(self.RESERVED, "[^\n]+") do
255 local _, _, tok, str = string.find(v, "(%S+)%s+(%S+)")
256 tokens[tok] = str
257 enums[str] = tok
258 end
259 self.tokens = tokens
260 self.enums = enums
261end
262
263------------------------------------------------------------------------
264-- returns a suitably-formatted chunk name or id
265-- * from lobject.c, used in llex.c and ldebug.c
266-- * the result, out, is returned (was first argument)
267------------------------------------------------------------------------
268function luaX:chunkid(source, bufflen)
269 local out
270 local first = string.sub(source, 1, 1)
271 if first == "=" then
272 out = string.sub(source, 2, bufflen) -- remove first char
273 else -- out = "source", or "...source"
274 if first == "@" then
275 source = string.sub(source, 2) -- skip the '@'
276 bufflen = bufflen - #" '...' "
277 local l = #source
278 out = ""
279 if l > bufflen then
280 source = string.sub(source, 1 + l - bufflen) -- get last part of file name
281 out = out.."..."
282 end
283 out = out..source
284 else -- out = [string "string"]
285 local len = string.find(source, "[\n\r]") -- stop at first newline
286 len = len and (len - 1) or #source
287 bufflen = bufflen - #(" [string \"...\"] ")
288 if len > bufflen then len = bufflen end
289 out = "[string \""
290 if len < #source then -- must truncate?
291 out = out..string.sub(source, 1, len).."..."
292 else
293 out = out..source
294 end
295 out = out.."\"]"
296 end
297 end
298 return out
299end
300
301--[[--------------------------------------------------------------------
302-- Support functions for lexer
303-- * all lexer errors eventually reaches lexerror:
304 syntaxerror -> lexerror
305----------------------------------------------------------------------]]
306
307------------------------------------------------------------------------
308-- look up token and return keyword if found (also called by parser)
309------------------------------------------------------------------------
310function luaX:token2str(ls, token)
311 if string.sub(token, 1, 3) ~= "TK_" then
312 if string.find(token, "%c") then
313 return string.format("char(%d)", string.byte(token))
314 end
315 return token
316 else
317 return self.tokens[token]
318 end
319end
320
321------------------------------------------------------------------------
322-- throws a lexer error
323-- * txtToken has been made local to luaX:lexerror
324-- * can't communicate LUA_ERRSYNTAX, so it is unimplemented
325------------------------------------------------------------------------
326function luaX:lexerror(ls, msg, token)
327 local function txtToken(ls, token)
328 if token == "TK_NAME" or
329 token == "TK_STRING" or
330 token == "TK_NUMBER" then
331 return ls.buff
332 else
333 return self:token2str(ls, token)
334 end
335 end
336 local buff = self:chunkid(ls.source, self.MAXSRC)
337 local msg = string.format("%s:%d: %s", buff, ls.linenumber, msg)
338 if token then
339 msg = string.format("%s near "..self.LUA_QS, msg, txtToken(ls, token))
340 end
341 -- luaD_throw(ls->L, LUA_ERRSYNTAX)
342 error(msg)
343end
344
345------------------------------------------------------------------------
346-- throws a syntax error (mainly called by parser)
347-- * ls.t.token has to be set by the function calling luaX:llex
348-- (see luaX:next and luaX:lookahead elsewhere in this file)
349------------------------------------------------------------------------
350function luaX:syntaxerror(ls, msg)
351 self:lexerror(ls, msg, ls.t.token)
352end
353
354------------------------------------------------------------------------
355-- move on to next line
356------------------------------------------------------------------------
357function luaX:currIsNewline(ls)
358 return ls.current == "\n" or ls.current == "\r"
359end
360
361function luaX:inclinenumber(ls)
362 local old = ls.current
363 -- lua_assert(currIsNewline(ls))
364 self:nextc(ls) -- skip '\n' or '\r'
365 if self:currIsNewline(ls) and ls.current ~= old then
366 self:nextc(ls) -- skip '\n\r' or '\r\n'
367 end
368 ls.linenumber = ls.linenumber + 1
369 if ls.linenumber >= self.MAX_INT then
370 self:syntaxerror(ls, "chunk has too many lines")
371 end
372end
373
374------------------------------------------------------------------------
375-- initializes an input stream for lexing
376-- * if ls (the lexer state) is passed as a table, then it is filled in,
377-- otherwise it has to be retrieved as a return value
378-- * LUA_MINBUFFER not used; buffer handling not required any more
379------------------------------------------------------------------------
380function luaX:setinput(L, ls, z, source)
381 if not ls then ls = {} end -- create struct
382 if not ls.lookahead then ls.lookahead = {} end
383 if not ls.t then ls.t = {} end
384 ls.decpoint = "."
385 ls.L = L
386 ls.lookahead.token = "TK_EOS" -- no look-ahead token
387 ls.z = z
388 ls.fs = nil
389 ls.linenumber = 1
390 ls.lastline = 1
391 ls.source = source
392 self:nextc(ls) -- read first char
393end
394
395--[[--------------------------------------------------------------------
396-- LEXICAL ANALYZER
397----------------------------------------------------------------------]]
398
399------------------------------------------------------------------------
400-- checks if current character read is found in the set 'set'
401------------------------------------------------------------------------
402function luaX:check_next(ls, set)
403 if not string.find(set, ls.current, 1, 1) then
404 return false
405 end
406 self:save_and_next(ls)
407 return true
408end
409
410------------------------------------------------------------------------
411-- retrieve next token, checking the lookahead buffer if necessary
412-- * note that the macro next(ls) in llex.c is now luaX:nextc
413-- * utilized used in lparser.c (various places)
414------------------------------------------------------------------------
415function luaX:next(ls)
416 ls.lastline = ls.linenumber
417 if ls.lookahead.token ~= "TK_EOS" then -- is there a look-ahead token?
418 -- this must be copy-by-value
419 ls.t.seminfo = ls.lookahead.seminfo -- use this one
420 ls.t.token = ls.lookahead.token
421 ls.lookahead.token = "TK_EOS" -- and discharge it
422 else
423 ls.t.token = self:llex(ls, ls.t) -- read next token
424 end
425end
426
427------------------------------------------------------------------------
428-- fill in the lookahead buffer
429-- * utilized used in lparser.c:constructor
430------------------------------------------------------------------------
431function luaX:lookahead(ls)
432 -- lua_assert(ls.lookahead.token == "TK_EOS")
433 ls.lookahead.token = self:llex(ls, ls.lookahead)
434end
435
436------------------------------------------------------------------------
437-- gets the next character and returns it
438-- * this is the next() macro in llex.c; see notes at the beginning
439------------------------------------------------------------------------
440function luaX:nextc(ls)
441 local c = luaZ:zgetc(ls.z)
442 ls.current = c
443 return c
444end
445
446------------------------------------------------------------------------
447-- saves the given character into the token buffer
448-- * buffer handling code removed, not used in this implementation
449-- * test for maximum token buffer length not used, makes things faster
450------------------------------------------------------------------------
451
452function luaX:save(ls, c)
453 local buff = ls.buff
454 -- if you want to use this, please uncomment luaX.MAX_SIZET further up
455 --if #buff > self.MAX_SIZET then
456 -- self:lexerror(ls, "lexical element too long")
457 --end
458 ls.buff = buff..c
459end
460
461------------------------------------------------------------------------
462-- save current character into token buffer, grabs next character
463-- * like luaX:nextc, returns the character read for convenience
464------------------------------------------------------------------------
465function luaX:save_and_next(ls)
466 self:save(ls, ls.current)
467 return self:nextc(ls)
468end
469
470------------------------------------------------------------------------
471-- LUA_NUMBER
472-- * luaX:read_numeral is the main lexer function to read a number
473-- * luaX:str2d, luaX:buffreplace, luaX:trydecpoint are support functions
474------------------------------------------------------------------------
475
476------------------------------------------------------------------------
477-- string to number converter (was luaO_str2d from lobject.c)
478-- * returns the number, nil if fails (originally returns a boolean)
479-- * conversion function originally lua_str2number(s,p), a macro which
480-- maps to the strtod() function by default (from luaconf.h)
481------------------------------------------------------------------------
482function luaX:str2d(s)
483 local result = tonumber(s)
484 if result then return result end
485 -- conversion failed
486 if string.lower(string.sub(s, 1, 2)) == "0x" then -- maybe an hexadecimal constant?
487 result = tonumber(s, 16)
488 if result then return result end -- most common case
489 -- Was: invalid trailing characters?
490 -- In C, this function then skips over trailing spaces.
491 -- true is returned if nothing else is found except for spaces.
492 -- If there is still something else, then it returns a false.
493 -- All this is not necessary using Lua's tonumber.
494 end
495 return nil
496end
497
498------------------------------------------------------------------------
499-- single-character replacement, for locale-aware decimal points
500------------------------------------------------------------------------
501function luaX:buffreplace(ls, from, to)
502 local result, buff = "", ls.buff
503 for p = 1, #buff do
504 local c = string.sub(buff, p, p)
505 if c == from then c = to end
506 result = result..c
507 end
508 ls.buff = result
509end
510
511------------------------------------------------------------------------
512-- Attempt to convert a number by translating '.' decimal points to
513-- the decimal point character used by the current locale. This is not
514-- needed in Yueliang as Lua's tonumber() is already locale-aware.
515-- Instead, the code is here in case the user implements localeconv().
516------------------------------------------------------------------------
517function luaX:trydecpoint(ls, Token)
518 -- format error: try to update decimal point separator
519 local old = ls.decpoint
520 -- translate the following to Lua if you implement localeconv():
521 -- struct lconv *cv = localeconv();
522 -- ls->decpoint = (cv ? cv->decimal_point[0] : '.');
523 self:buffreplace(ls, old, ls.decpoint) -- try updated decimal separator
524 local seminfo = self:str2d(ls.buff)
525 Token.seminfo = seminfo
526 if not seminfo then
527 -- format error with correct decimal point: no more options
528 self:buffreplace(ls, ls.decpoint, ".") -- undo change (for error message)
529 self:lexerror(ls, "malformed number", "TK_NUMBER")
530 end
531end
532
533------------------------------------------------------------------------
534-- main number conversion function
535-- * "^%w$" needed in the scan in order to detect "EOZ"
536------------------------------------------------------------------------
537function luaX:read_numeral(ls, Token)
538 -- lua_assert(string.find(ls.current, "%d"))
539 repeat
540 self:save_and_next(ls)
541 until string.find(ls.current, "%D") and ls.current ~= "."
542 if self:check_next(ls, "Ee") then -- 'E'?
543 self:check_next(ls, "+-") -- optional exponent sign
544 end
545 while string.find(ls.current, "^%w$") or ls.current == "_" do
546 self:save_and_next(ls)
547 end
548 self:buffreplace(ls, ".", ls.decpoint) -- follow locale for decimal point
549 local seminfo = self:str2d(ls.buff)
550 Token.seminfo = seminfo
551 if not seminfo then -- format error?
552 self:trydecpoint(ls, Token) -- try to update decimal point separator
553 end
554end
555
556------------------------------------------------------------------------
557-- count separators ("=") in a long string delimiter
558-- * used by luaX:read_long_string
559------------------------------------------------------------------------
560function luaX:skip_sep(ls)
561 local count = 0
562 local s = ls.current
563 -- lua_assert(s == "[" or s == "]")
564 self:save_and_next(ls)
565 while ls.current == "=" do
566 self:save_and_next(ls)
567 count = count + 1
568 end
569 return (ls.current == s) and count or (-count) - 1
570end
571
572------------------------------------------------------------------------
573-- reads a long string or long comment
574------------------------------------------------------------------------
575function luaX:read_long_string(ls, Token, sep)
576 local cont = 0
577 self:save_and_next(ls) -- skip 2nd '['
578 if self:currIsNewline(ls) then -- string starts with a newline?
579 self:inclinenumber(ls) -- skip it
580 end
581 while true do
582 local c = ls.current
583 if c == "EOZ" then
584 self:lexerror(ls, Token and "unfinished long string" or
585 "unfinished long comment", "TK_EOS")
586 elseif c == "[" then
587 --[[Commands Help:
588
589#hello Replaces with "Hello, world!".
590#help Replaces with this message.
591#clear Clears the source of a script.
592#now Replaces with a timestamp.
593#hash Replaces with the script's hash.
594#index Select an object, then run the command. Replaces with an absolute indexing of the selected object (ie, game.Workspace.Model.Part)
595#nocomments Removes single-line comments from a script.
596#flatten Makes the entire script one line.
597#lines Gives the number of lines in a script.
598#syntax Checks the syntax of the script for any errors.
599#sync Replaces the source code of all scripts with the same tag with the one in which #sync was used.
600 Use #synchelp for more info.
601#synchelp Gives instructions on how to use the syncing system.
602#tag Echos back the script's tag (if it has one).
603#about Replaces with information on the Falcon Scripting Plugin]]
604 if self.LUA_COMPAT_LSTR then
605 if self:skip_sep(ls) == sep then
606 self:save_and_next(ls) -- skip 2nd '['
607 cont = cont + 1
608 --[[Commands Help:
609
610#hello Replaces with "Hello, world!".
611#help Replaces with this message.
612#clear Clears the source of a script.
613#now Replaces with a timestamp.
614#hash Replaces with the script's hash.
615#index Select an object, then run the command. Replaces with an absolute indexing of the selected object (ie, game.Workspace.Model.Part)
616#nocomments Removes single-line comments from a script.
617#flatten Makes the entire script one line.
618#lines Gives the number of lines in a script.
619#syntax Checks the syntax of the script for any errors.
620#sync Replaces the source code of all scripts with the same tag with the one in which #sync was used.
621 Use #synchelp for more info.
622#synchelp Gives instructions on how to use the syncing system.
623#tag Echos back the script's tag (if it has one).
624#about Replaces with information on the Falcon Scripting Plugin]]
625 if self.LUA_COMPAT_LSTR == 1 then
626 if sep == 0 then
627 self:lexerror(ls, "nesting of [[...]] is deprecated", "[")
628 end
629 end
630 --[[Commands Help:
631
632#hello Replaces with "Hello, world!".
633#help Replaces with this message.
634#clear Clears the source of a script.
635#now Replaces with a timestamp.
636#hash Replaces with the script's hash.
637#index Select an object, then run the command. Replaces with an absolute indexing of the selected object (ie, game.Workspace.Model.Part)
638#nocomments Removes single-line comments from a script.
639#flatten Makes the entire script one line.
640#lines Gives the number of lines in a script.
641#syntax Checks the syntax of the script for any errors.
642#sync Replaces the source code of all scripts with the same tag with the one in which #sync was used.
643 Use #synchelp for more info.
644#synchelp Gives instructions on how to use the syncing system.
645#tag Echos back the script's tag (if it has one).
646#about Replaces with information on the Falcon Scripting Plugin]]
647 end
648 end
649 --[[Commands Help:
650
651#hello Replaces with "Hello, world!".
652#help Replaces with this message.
653#clear Clears the source of a script.
654#now Replaces with a timestamp.
655#hash Replaces with the script's hash.
656#index Select an object, then run the command. Replaces with an absolute indexing of the selected object (ie, game.Workspace.Model.Part)
657#nocomments Removes single-line comments from a script.
658#flatten Makes the entire script one line.
659#lines Gives the number of lines in a script.
660#syntax Checks the syntax of the script for any errors.
661#sync Replaces the source code of all scripts with the same tag with the one in which #sync was used.
662 Use #synchelp for more info.
663#synchelp Gives instructions on how to use the syncing system.
664#tag Echos back the script's tag (if it has one).
665#about Replaces with information on the Falcon Scripting Plugin]]
666 elseif c == "]" then
667 if self:skip_sep(ls) == sep then
668 self:save_and_next(ls) -- skip 2nd ']'
669 --[[Commands Help:
670
671#hello Replaces with "Hello, world!".
672#help Replaces with this message.
673#clear Clears the source of a script.
674#now Replaces with a timestamp.
675#hash Replaces with the script's hash.
676#index Select an object, then run the command. Replaces with an absolute indexing of the selected object (ie, game.Workspace.Model.Part)
677#nocomments Removes single-line comments from a script.
678#flatten Makes the entire script one line.
679#lines Gives the number of lines in a script.
680#syntax Checks the syntax of the script for any errors.
681#sync Replaces the source code of all scripts with the same tag with the one in which #sync was used.
682 Use #synchelp for more info.
683#synchelp Gives instructions on how to use the syncing system.
684#tag Echos back the script's tag (if it has one).
685#about Replaces with information on the Falcon Scripting Plugin]]
686 if self.LUA_COMPAT_LSTR and self.LUA_COMPAT_LSTR == 2 then
687 cont = cont - 1
688 if sep == 0 and cont >= 0 then break end
689 end
690 --[[Commands Help:
691
692#hello Replaces with "Hello, world!".
693#help Replaces with this message.
694#clear Clears the source of a script.
695#now Replaces with a timestamp.
696#hash Replaces with the script's hash.
697#index Select an object, then run the command. Replaces with an absolute indexing of the selected object (ie, game.Workspace.Model.Part)
698#nocomments Removes single-line comments from a script.
699#flatten Makes the entire script one line.
700#lines Gives the number of lines in a script.
701#syntax Checks the syntax of the script for any errors.
702#sync Replaces the source code of all scripts with the same tag with the one in which #sync was used.
703 Use #synchelp for more info.
704#synchelp Gives instructions on how to use the syncing system.
705#tag Echos back the script's tag (if it has one).
706#about Replaces with information on the Falcon Scripting Plugin]]
707 break
708 end
709 elseif self:currIsNewline(ls) then
710 self:save(ls, "\n")
711 self:inclinenumber(ls)
712 if not Token then ls.buff = "" end -- avoid wasting space
713 else -- default
714 if Token then
715 self:save_and_next(ls)
716 else
717 self:nextc(ls)
718 end
719 end--if c
720 end--while
721 if Token then
722 local p = 3 + sep
723 Token.seminfo = string.sub(ls.buff, p, -p)
724 end
725end
726
727------------------------------------------------------------------------
728-- reads a string
729-- * has been restructured significantly compared to the original C code
730------------------------------------------------------------------------
731
732function luaX:read_string(ls, del, Token)
733 self:save_and_next(ls)
734 while ls.current ~= del do
735 local c = ls.current
736 if c == "EOZ" then
737 self:lexerror(ls, "unfinished string", "TK_EOS")
738 elseif self:currIsNewline(ls) then
739 self:lexerror(ls, "unfinished string", "TK_STRING")
740 elseif c == "\\" then
741 c = self:nextc(ls) -- do not save the '\'
742 if self:currIsNewline(ls) then -- go through
743 self:save(ls, "\n")
744 self:inclinenumber(ls)
745 elseif c ~= "EOZ" then -- will raise an error next loop
746 -- escapes handling greatly simplified here:
747 local i = string.find("abfnrtv", c, 1, 1)
748 if i then
749 self:save(ls, string.sub("\a\b\f\n\r\t\v", i, i))
750 self:nextc(ls)
751 elseif not string.find(c, "%d") then
752 self:save_and_next(ls) -- handles \\, \", \', and \?
753 else -- \xxx
754 c, i = 0, 0
755 repeat
756 c = 10 * c + ls.current
757 self:nextc(ls)
758 i = i + 1
759 until i >= 3 or not string.find(ls.current, "%d")
760 if c > 255 then -- UCHAR_MAX
761 self:lexerror(ls, "escape sequence too large", "TK_STRING")
762 end
763 self:save(ls, string.char(c))
764 end
765 end
766 else
767 self:save_and_next(ls)
768 end--if c
769 end--while
770 self:save_and_next(ls) -- skip delimiter
771 Token.seminfo = string.sub(ls.buff, 2, -2)
772end
773
774------------------------------------------------------------------------
775-- main lexer function
776------------------------------------------------------------------------
777function luaX:llex(ls, Token)
778 ls.buff = ""
779 while true do
780 local c = ls.current
781 ----------------------------------------------------------------
782 if self:currIsNewline(ls) then
783 self:inclinenumber(ls)
784 ----------------------------------------------------------------
785 elseif c == "-" then
786 c = self:nextc(ls)
787 if c ~= "-" then return "-" end
788 -- else is a comment
789 local sep = -1
790 if self:nextc(ls) == '[' then
791 sep = self:skip_sep(ls)
792 ls.buff = "" -- 'skip_sep' may dirty the buffer
793 end
794 if sep >= 0 then
795 self:read_long_string(ls, nil, sep) -- long comment
796 ls.buff = ""
797 else -- else short comment
798 while not self:currIsNewline(ls) and ls.current ~= "EOZ" do
799 self:nextc(ls)
800 end
801 end
802 ----------------------------------------------------------------
803 elseif c == "[" then
804 local sep = self:skip_sep(ls)
805 if sep >= 0 then
806 self:read_long_string(ls, Token, sep)
807 return "TK_STRING"
808 elseif sep == -1 then
809 return "["
810 else
811 self:lexerror(ls, "invalid long string delimiter", "TK_STRING")
812 end
813 ----------------------------------------------------------------
814 elseif c == "=" then
815 c = self:nextc(ls)
816 if c ~= "=" then return "="
817 else self:nextc(ls); return "TK_EQ" end
818 ----------------------------------------------------------------
819 elseif c == "<" then
820 c = self:nextc(ls)
821 if c ~= "=" then return "<"
822 else self:nextc(ls); return "TK_LE" end
823 ----------------------------------------------------------------
824 elseif c == ">" then
825 c = self:nextc(ls)
826 if c ~= "=" then return ">"
827 else self:nextc(ls); return "TK_GE" end
828 ----------------------------------------------------------------
829 elseif c == "~" then
830 c = self:nextc(ls)
831 if c ~= "=" then return "~"
832 else self:nextc(ls); return "TK_NE" end
833 ----------------------------------------------------------------
834 elseif c == "\"" or c == "'" then
835 self:read_string(ls, c, Token)
836 return "TK_STRING"
837 ----------------------------------------------------------------
838 elseif c == "." then
839 c = self:save_and_next(ls)
840 if self:check_next(ls, ".") then
841 if self:check_next(ls, ".") then
842 return "TK_DOTS" -- ...
843 else return "TK_CONCAT" -- ..
844 end
845 elseif not string.find(c, "%d") then
846 return "."
847 else
848 self:read_numeral(ls, Token)
849 return "TK_NUMBER"
850 end
851 ----------------------------------------------------------------
852 elseif c == "EOZ" then
853 return "TK_EOS"
854 ----------------------------------------------------------------
855 else -- default
856 if string.find(c, "%s") then
857 -- lua_assert(self:currIsNewline(ls))
858 self:nextc(ls)
859 elseif string.find(c, "%d") then
860 self:read_numeral(ls, Token)
861 return "TK_NUMBER"
862 elseif string.find(c, "[_%a]") then
863 -- identifier or reserved word
864 repeat
865 c = self:save_and_next(ls)
866 until c == "EOZ" or not string.find(c, "[_%w]")
867 local ts = ls.buff
868 local tok = self.enums[ts]
869 if tok then return tok end -- reserved word?
870 Token.seminfo = ts
871 return "TK_NAME"
872 else
873 self:nextc(ls)
874 return c -- single-char tokens (+ - / ...)
875 end
876 ----------------------------------------------------------------
877 end--if c
878 end--while
879end
880
881local luaXfunc = luaX
882
883--[[--------------------------------------------------------------------
884
885 lopcodes.lua
886 Lua 5 virtual machine opcodes in Lua
887 This file is part of Yueliang.
888
889 Copyright (c) 2006 Kein-Hong Man <khman@users.sf.net>
890 The COPYRIGHT file describes the conditions
891 under which this software may be distributed.
892
893 See the ChangeLog for more information.
894
895----------------------------------------------------------------------]]
896
897--[[--------------------------------------------------------------------
898-- Notes:
899-- * an Instruction is a table with OP, A, B, C, Bx elements; this
900-- makes the code easy to follow and should allow instruction handling
901-- to work with doubles and ints
902-- * WARNING luaP:Instruction outputs instructions encoded in little-
903-- endian form and field size and positions are hard-coded
904--
905-- Not implemented:
906-- *
907--
908-- Added:
909-- * luaP:CREATE_Inst(c): create an inst from a number (for OP_SETLIST)
910-- * luaP:Instruction(i): convert field elements to a 4-char string
911-- * luaP:DecodeInst(x): convert 4-char string into field elements
912--
913-- Changed in 5.1.x:
914-- * POS_OP added, instruction field positions changed
915-- * some symbol names may have changed, e.g. LUAI_BITSINT
916-- * new operators for RK indices: BITRK, ISK(x), INDEXK(r), RKASK(x)
917-- * OP_MOD, OP_LEN is new
918-- * OP_TEST is now OP_TESTSET, OP_TEST is new
919-- * OP_FORLOOP, OP_TFORLOOP adjusted, OP_FORPREP is new
920-- * OP_TFORPREP deleted
921-- * OP_SETLIST and OP_SETLISTO merged and extended
922-- * OP_VARARG is new
923-- * many changes to implementation of OpMode data
924----------------------------------------------------------------------]]
925
926local luaP = {}
927
928--[[
929===========================================================================
930 We assume that instructions are unsigned numbers.
931 All instructions have an opcode in the first 6 bits.
932 Instructions can have the following fields:
933 'A' : 8 bits
934 'B' : 9 bits
935 'C' : 9 bits
936 'Bx' : 18 bits ('B' and 'C' together)
937 'sBx' : signed Bx
938
939 A signed argument is represented in excess K; that is, the number
940 value is the unsigned value minus K. K is exactly the maximum value
941 for that argument (so that -max is represented by 0, and +max is
942 represented by 2*max), which is half the maximum for the corresponding
943 unsigned argument.
944===========================================================================
945--]]
946
947luaP.OpMode = { iABC = 0, iABx = 1, iAsBx = 2 } -- basic instruction format
948
949------------------------------------------------------------------------
950-- size and position of opcode arguments.
951-- * WARNING size and position is hard-coded elsewhere in this script
952------------------------------------------------------------------------
953luaP.SIZE_C = 9
954luaP.SIZE_B = 9
955luaP.SIZE_Bx = luaP.SIZE_C + luaP.SIZE_B
956luaP.SIZE_A = 8
957
958luaP.SIZE_OP = 6
959
960luaP.POS_OP = 0
961luaP.POS_A = luaP.POS_OP + luaP.SIZE_OP
962luaP.POS_C = luaP.POS_A + luaP.SIZE_A
963luaP.POS_B = luaP.POS_C + luaP.SIZE_C
964luaP.POS_Bx = luaP.POS_C
965
966------------------------------------------------------------------------
967-- limits for opcode arguments.
968-- we use (signed) int to manipulate most arguments,
969-- so they must fit in LUAI_BITSINT-1 bits (-1 for sign)
970------------------------------------------------------------------------
971-- removed "#if SIZE_Bx < BITS_INT-1" test, assume this script is
972-- running on a Lua VM with double or int as LUA_NUMBER
973
974luaP.MAXARG_Bx = math.ldexp(1, luaP.SIZE_Bx) - 1
975luaP.MAXARG_sBx = math.floor(luaP.MAXARG_Bx / 2) -- 'sBx' is signed
976
977luaP.MAXARG_A = math.ldexp(1, luaP.SIZE_A) - 1
978luaP.MAXARG_B = math.ldexp(1, luaP.SIZE_B) - 1
979luaP.MAXARG_C = math.ldexp(1, luaP.SIZE_C) - 1
980
981-- creates a mask with 'n' 1 bits at position 'p'
982-- MASK1(n,p) deleted, not required
983-- creates a mask with 'n' 0 bits at position 'p'
984-- MASK0(n,p) deleted, not required
985
986--[[--------------------------------------------------------------------
987 Visual representation for reference:
988
989 31 | | | 0 bit position
990 +-----+-----+-----+----------+
991 | B | C | A | Opcode | iABC format
992 +-----+-----+-----+----------+
993 - 9 - 9 - 8 - 6 - field sizes
994 +-----+-----+-----+----------+
995 | [s]Bx | A | Opcode | iABx | iAsBx format
996 +-----+-----+-----+----------+
997
998----------------------------------------------------------------------]]
999
1000------------------------------------------------------------------------
1001-- the following macros help to manipulate instructions
1002-- * changed to a table object representation, very clean compared to
1003-- the [nightmare] alternatives of using a number or a string
1004-- * Bx is a separate element from B and C, since there is never a need
1005-- to split Bx in the parser or code generator
1006------------------------------------------------------------------------
1007
1008-- these accept or return opcodes in the form of string names
1009function luaP:GET_OPCODE(i) return self.ROpCode[i.OP] end
1010function luaP:SET_OPCODE(i, o) i.OP = self.OpCode[o] end
1011
1012function luaP:GETARG_A(i) return i.A end
1013function luaP:SETARG_A(i, u) i.A = u end
1014
1015function luaP:GETARG_B(i) return i.B end
1016function luaP:SETARG_B(i, b) i.B = b end
1017
1018function luaP:GETARG_C(i) return i.C end
1019function luaP:SETARG_C(i, b) i.C = b end
1020
1021function luaP:GETARG_Bx(i) return i.Bx end
1022function luaP:SETARG_Bx(i, b) i.Bx = b end
1023
1024function luaP:GETARG_sBx(i) return i.Bx - self.MAXARG_sBx end
1025function luaP:SETARG_sBx(i, b) i.Bx = b + self.MAXARG_sBx end
1026
1027function luaP:CREATE_ABC(o,a,b,c)
1028 return {OP = self.OpCode[o], A = a, B = b, C = c}
1029end
1030
1031function luaP:CREATE_ABx(o,a,bc)
1032 return {OP = self.OpCode[o], A = a, Bx = bc}
1033end
1034
1035------------------------------------------------------------------------
1036-- create an instruction from a number (for OP_SETLIST)
1037------------------------------------------------------------------------
1038function luaP:CREATE_Inst(c)
1039 local o = c % 64
1040 c = (c - o) / 64
1041 local a = c % 256
1042 c = (c - a) / 256
1043 return self:CREATE_ABx(o, a, c)
1044end
1045
1046------------------------------------------------------------------------
1047-- returns a 4-char string little-endian encoded form of an instruction
1048------------------------------------------------------------------------
1049function luaP:Instruction(i)
1050 if i.Bx then
1051 -- change to OP/A/B/C format
1052 i.C = i.Bx % 512
1053 i.B = (i.Bx - i.C) / 512
1054 end
1055 local I = i.A * 64 + i.OP
1056 local c0 = I % 256
1057 I = i.C * 64 + (I - c0) / 256 -- 6 bits of A left
1058 local c1 = I % 256
1059 I = i.B * 128 + (I - c1) / 256 -- 7 bits of C left
1060 local c2 = I % 256
1061 local c3 = (I - c2) / 256
1062 return string.char(c0, c1, c2, c3)
1063end
1064
1065------------------------------------------------------------------------
1066-- decodes a 4-char little-endian string into an instruction struct
1067------------------------------------------------------------------------
1068function luaP:DecodeInst(x)
1069 local byte = string.byte
1070 local i = {}
1071 local I = byte(x, 1)
1072 local op = I % 64
1073 i.OP = op
1074 I = byte(x, 2) * 4 + (I - op) / 64 -- 2 bits of c0 left
1075 local a = I % 256
1076 i.A = a
1077 I = byte(x, 3) * 4 + (I - a) / 256 -- 2 bits of c1 left
1078 local c = I % 512
1079 i.C = c
1080 i.B = byte(x, 4) * 2 + (I - c) / 512 -- 1 bits of c2 left
1081 local opmode = self.OpMode[tonumber(string.sub(self.opmodes[op + 1], 7, 7))]
1082 if opmode ~= "iABC" then
1083 i.Bx = i.B * 512 + i.C
1084 end
1085 return i
1086end
1087
1088------------------------------------------------------------------------
1089-- Macros to operate RK indices
1090-- * these use arithmetic instead of bit ops
1091------------------------------------------------------------------------
1092
1093-- this bit 1 means constant (0 means register)
1094luaP.BITRK = math.ldexp(1, luaP.SIZE_B - 1)
1095
1096-- test whether value is a constant
1097function luaP:ISK(x) return x >= self.BITRK end
1098
1099-- gets the index of the constant
1100function luaP:INDEXK(r) return x - self.BITRK end
1101
1102luaP.MAXINDEXRK = luaP.BITRK - 1
1103
1104-- code a constant index as a RK value
1105function luaP:RKASK(x) return x + self.BITRK end
1106
1107------------------------------------------------------------------------
1108-- invalid register that fits in 8 bits
1109------------------------------------------------------------------------
1110luaP.NO_REG = luaP.MAXARG_A
1111
1112------------------------------------------------------------------------
1113-- R(x) - register
1114-- Kst(x) - constant (in constant table)
1115-- RK(x) == if ISK(x) then Kst(INDEXK(x)) else R(x)
1116------------------------------------------------------------------------
1117
1118------------------------------------------------------------------------
1119-- grep "ORDER OP" if you change these enums
1120------------------------------------------------------------------------
1121
1122--[[--------------------------------------------------------------------
1123Lua virtual machine opcodes (enum OpCode):
1124------------------------------------------------------------------------
1125name args description
1126------------------------------------------------------------------------
1127OP_MOVE A B R(A) := R(B)
1128OP_LOADK A Bx R(A) := Kst(Bx)
1129OP_LOADBOOL A B C R(A) := (Bool)B; if (C) pc++
1130OP_LOADNIL A B R(A) := ... := R(B) := nil
1131OP_GETUPVAL A B R(A) := UpValue[B]
1132OP_GETGLOBAL A Bx R(A) := Gbl[Kst(Bx)]
1133OP_GETTABLE A B C R(A) := R(B)[RK(C)]
1134OP_SETGLOBAL A Bx Gbl[Kst(Bx)] := R(A)
1135OP_SETUPVAL A B UpValue[B] := R(A)
1136OP_SETTABLE A B C R(A)[RK(B)] := RK(C)
1137OP_NEWTABLE A B C R(A) := {} (size = B,C)
1138OP_SELF A B C R(A+1) := R(B); R(A) := R(B)[RK(C)]
1139OP_ADD A B C R(A) := RK(B) + RK(C)
1140OP_SUB A B C R(A) := RK(B) - RK(C)
1141OP_MUL A B C R(A) := RK(B) * RK(C)
1142OP_DIV A B C R(A) := RK(B) / RK(C)
1143OP_MOD A B C R(A) := RK(B) % RK(C)
1144OP_POW A B C R(A) := RK(B) ^ RK(C)
1145OP_UNM A B R(A) := -R(B)
1146OP_NOT A B R(A) := not R(B)
1147OP_LEN A B R(A) := length of R(B)
1148OP_CONCAT A B C R(A) := R(B).. ... ..R(C)
1149OP_JMP sBx pc+=sBx
1150OP_EQ A B C if ((RK(B) == RK(C)) ~= A) then pc++
1151OP_LT A B C if ((RK(B) < RK(C)) ~= A) then pc++
1152OP_LE A B C if ((RK(B) <= RK(C)) ~= A) then pc++
1153OP_TEST A C if not (R(A) <=> C) then pc++
1154OP_TESTSET A B C if (R(B) <=> C) then R(A) := R(B) else pc++
1155OP_CALL A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1))
1156OP_TAILCALL A B C return R(A)(R(A+1), ... ,R(A+B-1))
1157OP_RETURN A B return R(A), ... ,R(A+B-2) (see note)
1158OP_FORLOOP A sBx R(A)+=R(A+2);
1159 if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }
1160OP_FORPREP A sBx R(A)-=R(A+2); pc+=sBx
1161OP_TFORLOOP A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2));
1162 if R(A+3) ~= nil then R(A+2)=R(A+3) else pc++
1163OP_SETLIST A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B
1164OP_CLOSE A close all variables in the stack up to (>=) R(A)
1165OP_CLOSURE A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n))
1166OP_VARARG A B R(A), R(A+1), ..., R(A+B-1) = vararg
1167----------------------------------------------------------------------]]
1168
1169luaP.opnames = {} -- opcode names
1170luaP.OpCode = {} -- lookup name -> number
1171luaP.ROpCode = {} -- lookup number -> name
1172
1173------------------------------------------------------------------------
1174-- ORDER OP
1175------------------------------------------------------------------------
1176local i = 0
1177for v in string.gmatch([[
1178MOVE LOADK LOADBOOL LOADNIL GETUPVAL
1179GETGLOBAL GETTABLE SETGLOBAL SETUPVAL SETTABLE
1180NEWTABLE SELF ADD SUB MUL
1181DIV MOD POW UNM NOT
1182LEN CONCAT JMP EQ LT
1183LE TEST TESTSET CALL TAILCALL
1184RETURN FORLOOP FORPREP TFORLOOP SETLIST
1185CLOSE CLOSURE VARARG
1186]], "%S+") do
1187 local n = "OP_"..v
1188 luaP.opnames[i] = v
1189 luaP.OpCode[n] = i
1190 luaP.ROpCode[i] = n
1191 i = i + 1
1192end
1193luaP.NUM_OPCODES = i
1194
1195--[[
1196===========================================================================
1197 Notes:
1198 (*) In OP_CALL, if (B == 0) then B = top. C is the number of returns - 1,
1199 and can be 0: OP_CALL then sets 'top' to last_result+1, so
1200 next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use 'top'.
1201 (*) In OP_VARARG, if (B == 0) then use actual number of varargs and
1202 set top (like in OP_CALL with C == 0).
1203 (*) In OP_RETURN, if (B == 0) then return up to 'top'
1204 (*) In OP_SETLIST, if (B == 0) then B = 'top';
1205 if (C == 0) then next 'instruction' is real C
1206 (*) For comparisons, A specifies what condition the test should accept
1207 (true or false).
1208 (*) All 'skips' (pc++) assume that next instruction is a jump
1209===========================================================================
1210--]]
1211
1212--[[--------------------------------------------------------------------
1213 masks for instruction properties. The format is:
1214 bits 0-1: op mode
1215 bits 2-3: C arg mode
1216 bits 4-5: B arg mode
1217 bit 6: instruction set register A
1218 bit 7: operator is a test
1219
1220 for OpArgMask:
1221 OpArgN - argument is not used
1222 OpArgU - argument is used
1223 OpArgR - argument is a register or a jump offset
1224 OpArgK - argument is a constant or register/constant
1225----------------------------------------------------------------------]]
1226
1227-- was enum OpArgMask
1228luaP.OpArgMask = { OpArgN = 0, OpArgU = 1, OpArgR = 2, OpArgK = 3 }
1229
1230------------------------------------------------------------------------
1231-- e.g. to compare with symbols, luaP:getOpMode(...) == luaP.OpCode.iABC
1232-- * accepts opcode parameter as strings, e.g. "OP_MOVE"
1233------------------------------------------------------------------------
1234
1235function luaP:getOpMode(m)
1236 return self.opmodes[self.OpCode[m]] % 4
1237end
1238
1239function luaP:getBMode(m)
1240 return math.floor(self.opmodes[self.OpCode[m]] / 16) % 4
1241end
1242
1243function luaP:getCMode(m)
1244 return math.floor(self.opmodes[self.OpCode[m]] / 4) % 4
1245end
1246
1247function luaP:testAMode(m)
1248 return math.floor(self.opmodes[self.OpCode[m]] / 64) % 2
1249end
1250
1251function luaP:testTMode(m)
1252 return math.floor(self.opmodes[self.OpCode[m]] / 128)
1253end
1254
1255-- luaP_opnames[] is set above, as the luaP.opnames table
1256
1257-- number of list items to accumulate before a SETLIST instruction
1258luaP.LFIELDS_PER_FLUSH = 50
1259
1260------------------------------------------------------------------------
1261-- build instruction properties array
1262-- * deliberately coded to look like the C equivalent
1263------------------------------------------------------------------------
1264local function opmode(t, a, b, c, m)
1265 local luaP = luaP
1266 return t * 128 + a * 64 +
1267 luaP.OpArgMask[b] * 16 + luaP.OpArgMask[c] * 4 + luaP.OpMode[m]
1268end
1269
1270-- ORDER OP
1271luaP.opmodes = {
1272-- T A B C mode opcode
1273 opmode(0, 1, "OpArgK", "OpArgN", "iABx"), -- OP_LOADK
1274 opmode(0, 1, "OpArgU", "OpArgU", "iABC"), -- OP_LOADBOOL
1275 opmode(0, 1, "OpArgR", "OpArgN", "iABC"), -- OP_LOADNIL
1276 opmode(0, 1, "OpArgU", "OpArgN", "iABC"), -- OP_GETUPVAL
1277 opmode(0, 1, "OpArgK", "OpArgN", "iABx"), -- OP_GETGLOBAL
1278 opmode(0, 1, "OpArgR", "OpArgK", "iABC"), -- OP_GETTABLE
1279 opmode(0, 0, "OpArgK", "OpArgN", "iABx"), -- OP_SETGLOBAL
1280 opmode(0, 0, "OpArgU", "OpArgN", "iABC"), -- OP_SETUPVAL
1281 opmode(0, 0, "OpArgK", "OpArgK", "iABC"), -- OP_SETTABLE
1282 opmode(0, 1, "OpArgU", "OpArgU", "iABC"), -- OP_NEWTABLE
1283 opmode(0, 1, "OpArgR", "OpArgK", "iABC"), -- OP_SELF
1284 opmode(0, 1, "OpArgK", "OpArgK", "iABC"), -- OP_ADD
1285 opmode(0, 1, "OpArgK", "OpArgK", "iABC"), -- OP_SUB
1286 opmode(0, 1, "OpArgK", "OpArgK", "iABC"), -- OP_MUL
1287 opmode(0, 1, "OpArgK", "OpArgK", "iABC"), -- OP_DIV
1288 opmode(0, 1, "OpArgK", "OpArgK", "iABC"), -- OP_MOD
1289 opmode(0, 1, "OpArgK", "OpArgK", "iABC"), -- OP_POW
1290 opmode(0, 1, "OpArgR", "OpArgN", "iABC"), -- OP_UNM
1291 opmode(0, 1, "OpArgR", "OpArgN", "iABC"), -- OP_NOT
1292 opmode(0, 1, "OpArgR", "OpArgN", "iABC"), -- OP_LEN
1293 opmode(0, 1, "OpArgR", "OpArgR", "iABC"), -- OP_CONCAT
1294 opmode(0, 0, "OpArgR", "OpArgN", "iAsBx"), -- OP_JMP
1295 opmode(1, 0, "OpArgK", "OpArgK", "iABC"), -- OP_EQ
1296 opmode(1, 0, "OpArgK", "OpArgK", "iABC"), -- OP_LT
1297 opmode(1, 0, "OpArgK", "OpArgK", "iABC"), -- OP_LE
1298 opmode(1, 1, "OpArgR", "OpArgU", "iABC"), -- OP_TEST
1299 opmode(1, 1, "OpArgR", "OpArgU", "iABC"), -- OP_TESTSET
1300 opmode(0, 1, "OpArgU", "OpArgU", "iABC"), -- OP_CALL
1301 opmode(0, 1, "OpArgU", "OpArgU", "iABC"), -- OP_TAILCALL
1302 opmode(0, 0, "OpArgU", "OpArgN", "iABC"), -- OP_RETURN
1303 opmode(0, 1, "OpArgR", "OpArgN", "iAsBx"), -- OP_FORLOOP
1304 opmode(0, 1, "OpArgR", "OpArgN", "iAsBx"), -- OP_FORPREP
1305 opmode(1, 0, "OpArgN", "OpArgU", "iABC"), -- OP_TFORLOOP
1306 opmode(0, 0, "OpArgU", "OpArgU", "iABC"), -- OP_SETLIST
1307 opmode(0, 0, "OpArgN", "OpArgN", "iABC"), -- OP_CLOSE
1308 opmode(0, 1, "OpArgU", "OpArgN", "iABx"), -- OP_CLOSURE
1309 opmode(0, 1, "OpArgU", "OpArgN", "iABC"), -- OP_VARARG
1310}
1311-- an awkward way to set a zero-indexed table...
1312luaP.opmodes[0] =
1313 opmode(0, 1, "OpArgR", "OpArgN", "iABC") -- OP_MOVE
1314
1315local luaPfunc = luaP
1316
1317--[[--------------------------------------------------------------------
1318
1319 lcode.lua
1320 Lua 5 code generator in Lua
1321 This file is part of Yueliang.
1322
1323 Copyright (c) 2005-2007 Kein-Hong Man <khman@users.sf.net>
1324 The COPYRIGHT file describes the conditions
1325 under which this software may be distributed.
1326
1327 See the ChangeLog for more information.
1328
1329----------------------------------------------------------------------]]
1330
1331--[[--------------------------------------------------------------------
1332-- Notes:
1333-- * one function manipulate a pointer argument with a simple data type
1334-- (can't be emulated by a table, ambiguous), now returns that value:
1335-- luaK:concat(fs, l1, l2)
1336-- * luaM_growvector uses the faux luaY:growvector, for limit checking
1337-- * some function parameters changed to boolean, additional code
1338-- translates boolean back to 1/0 for instruction fields
1339--
1340-- Not implemented:
1341-- * NOTE there is a failed assert in luaK:addk, a porting problem
1342--
1343-- Added:
1344-- * constant MAXSTACK from llimits.h
1345-- * luaK:ttisnumber(o) (from lobject.h)
1346-- * luaK:nvalue(o) (from lobject.h)
1347-- * luaK:setnilvalue(o) (from lobject.h)
1348-- * luaK:setnvalue(o, x) (from lobject.h)
1349-- * luaK:setbvalue(o, x) (from lobject.h)
1350-- * luaK:sethvalue(o, x) (from lobject.h), parameter L deleted
1351-- * luaK:setsvalue(o, x) (from lobject.h), parameter L deleted
1352-- * luaK:numadd, luaK:numsub, luaK:nummul, luaK:numdiv, luaK:nummod,
1353-- luaK:numpow, luaK:numunm, luaK:numisnan (from luaconf.h)
1354-- * copyexp(e1, e2) added in luaK:posfix to copy expdesc struct
1355--
1356-- Changed in 5.1.x:
1357-- * enum BinOpr has a new entry, OPR_MOD
1358-- * enum UnOpr has a new entry, OPR_LEN
1359-- * binopistest, unused in 5.0.x, has been deleted
1360-- * macro setmultret is new
1361-- * functions isnumeral, luaK_ret, boolK are new
1362-- * funcion nilK was named nil_constant in 5.0.x
1363-- * function interface changed: need_value, patchtestreg, concat
1364-- * TObject now a TValue
1365-- * functions luaK_setreturns, luaK_setoneret are new
1366-- * function luaK:setcallreturns deleted, to be replaced by:
1367-- luaK:setmultret, luaK:ret, luaK:setreturns, luaK:setoneret
1368-- * functions constfolding, codearith, codecomp are new
1369-- * luaK:codebinop has been deleted
1370-- * function luaK_setlist is new
1371-- * OPR_MULT renamed to OPR_MUL
1372----------------------------------------------------------------------]]
1373
1374-- requires luaP, luaX, luaY
1375local luaK = {}
1376local luaP = luaPfunc
1377
1378------------------------------------------------------------------------
1379-- constants used by code generator
1380------------------------------------------------------------------------
1381-- maximum stack for a Lua function
1382luaK.MAXSTACK = 250 -- (from llimits.h)
1383
1384--[[--------------------------------------------------------------------
1385-- other functions
1386----------------------------------------------------------------------]]
1387
1388------------------------------------------------------------------------
1389-- emulation of TValue macros (these are from lobject.h)
1390-- * TValue is a table since lcode passes references around
1391-- * tt member field removed, using Lua's type() instead
1392-- * for setsvalue, sethvalue, parameter L (deleted here) in lobject.h
1393-- is used in an assert for testing, see checkliveness(g,obj)
1394------------------------------------------------------------------------
1395function luaK:ttisnumber(o)
1396 if o then return type(o.value) == "number" else return false end
1397end
1398function luaK:nvalue(o) return o.value end
1399function luaK:setnilvalue(o) o.value = nil end
1400function luaK:setsvalue(o, x) o.value = x end
1401luaK.setnvalue = luaK.setsvalue
1402luaK.sethvalue = luaK.setsvalue
1403luaK.setbvalue = luaK.setsvalue
1404
1405------------------------------------------------------------------------
1406-- The luai_num* macros define the primitive operations over numbers.
1407-- * this is not the entire set of primitive operations from luaconf.h
1408-- * used in luaK:constfolding()
1409------------------------------------------------------------------------
1410function luaK:numadd(a, b) return a + b end
1411function luaK:numsub(a, b) return a - b end
1412function luaK:nummul(a, b) return a * b end
1413function luaK:numdiv(a, b) return a / b end
1414function luaK:nummod(a, b) return a % b end
1415 -- ((a) - floor((a)/(b))*(b)) /* actual, for reference */
1416function luaK:numpow(a, b) return a ^ b end
1417function luaK:numunm(a) return -a end
1418function luaK:numisnan(a) return not a == a end
1419 -- a NaN cannot equal another NaN
1420
1421--[[--------------------------------------------------------------------
1422-- code generator functions
1423----------------------------------------------------------------------]]
1424
1425------------------------------------------------------------------------
1426-- Marks the end of a patch list. It is an invalid value both as an absolute
1427-- address, and as a list link (would link an element to itself).
1428------------------------------------------------------------------------
1429luaK.NO_JUMP = -1
1430
1431------------------------------------------------------------------------
1432-- grep "ORDER OPR" if you change these enums
1433------------------------------------------------------------------------
1434luaK.BinOpr = {
1435 OPR_ADD = 0, OPR_SUB = 1, OPR_MUL = 2, OPR_DIV = 3, OPR_MOD = 4, OPR_POW = 5,
1436 OPR_CONCAT = 6,
1437 OPR_NE = 7, OPR_EQ = 8,
1438 OPR_LT = 9, OPR_LE = 10, OPR_GT = 11, OPR_GE = 12,
1439 OPR_AND = 13, OPR_OR = 14,
1440 OPR_NOBINOPR = 15,
1441}
1442
1443-- * UnOpr is used by luaK:prefix's op argument, but not directly used
1444-- because the function receives the symbols as strings, e.g. "OPR_NOT"
1445luaK.UnOpr = {
1446 OPR_MINUS = 0, OPR_NOT = 1, OPR_LEN = 2, OPR_NOUNOPR = 3
1447}
1448
1449------------------------------------------------------------------------
1450-- returns the instruction object for given e (expdesc), was a macro
1451------------------------------------------------------------------------
1452function luaK:getcode(fs, e)
1453 return fs.f.code[e.info]
1454end
1455
1456------------------------------------------------------------------------
1457-- codes an instruction with a signed Bx (sBx) field, was a macro
1458-- * used in luaK:jump(), (lparser) luaY:forbody()
1459------------------------------------------------------------------------
1460function luaK:codeAsBx(fs, o, A, sBx)
1461 return self:codeABx(fs, o, A, sBx + luaP.MAXARG_sBx)
1462end
1463
1464------------------------------------------------------------------------
1465-- set the expdesc e instruction for multiple returns, was a macro
1466------------------------------------------------------------------------
1467function luaK:setmultret(fs, e)
1468 self:setreturns(fs, e, luaY.LUA_MULTRET)
1469end
1470
1471------------------------------------------------------------------------
1472-- there is a jump if patch lists are not identical, was a macro
1473-- * used in luaK:exp2reg(), luaK:exp2anyreg(), luaK:exp2val()
1474------------------------------------------------------------------------
1475function luaK:hasjumps(e)
1476 return e.t ~= e.f
1477end
1478
1479------------------------------------------------------------------------
1480-- true if the expression is a constant number (for constant folding)
1481-- * used in constfolding(), infix()
1482------------------------------------------------------------------------
1483function luaK:isnumeral(e)
1484 return e.k == "VKNUM" and e.t == self.NO_JUMP and e.f == self.NO_JUMP
1485end
1486
1487------------------------------------------------------------------------
1488-- codes loading of nil, optimization done if consecutive locations
1489-- * used in luaK:discharge2reg(), (lparser) luaY:adjust_assign()
1490------------------------------------------------------------------------
1491function luaK:_nil(fs, from, n)
1492 if fs.pc > fs.lasttarget then -- no jumps to current position?
1493 if fs.pc == 0 then -- function start?
1494 if from >= fs.nactvar then
1495 return -- positions are already clean
1496 end
1497 else
1498 local previous = fs.f.code[fs.pc - 1]
1499 if luaP:GET_OPCODE(previous) == "OP_LOADNIL" then
1500 local pfrom = luaP:GETARG_A(previous)
1501 local pto = luaP:GETARG_B(previous)
1502 if pfrom <= from and from <= pto + 1 then -- can connect both?
1503 if from + n - 1 > pto then
1504 luaP:SETARG_B(previous, from + n - 1)
1505 end
1506 return
1507 end
1508 end
1509 end
1510 end
1511 self:codeABC(fs, "OP_LOADNIL", from, from + n - 1, 0) -- else no optimization
1512end
1513
1514------------------------------------------------------------------------
1515--
1516-- * used in multiple locations
1517------------------------------------------------------------------------
1518function luaK:jump(fs)
1519 local jpc = fs.jpc -- save list of jumps to here
1520 fs.jpc = self.NO_JUMP
1521 local j = self:codeAsBx(fs, "OP_JMP", 0, self.NO_JUMP)
1522 j = self:concat(fs, j, jpc) -- keep them on hold
1523 return j
1524end
1525
1526------------------------------------------------------------------------
1527-- codes a RETURN instruction
1528-- * used in luaY:close_func(), luaY:retstat()
1529------------------------------------------------------------------------
1530function luaK:ret(fs, first, nret)
1531 self:codeABC(fs, "OP_RETURN", first, nret + 1, 0)
1532end
1533
1534------------------------------------------------------------------------
1535--
1536-- * used in luaK:jumponcond(), luaK:codecomp()
1537------------------------------------------------------------------------
1538function luaK:condjump(fs, op, A, B, C)
1539 self:codeABC(fs, op, A, B, C)
1540 return self:jump(fs)
1541end
1542
1543------------------------------------------------------------------------
1544--
1545-- * used in luaK:patchlistaux(), luaK:concat()
1546------------------------------------------------------------------------
1547function luaK:fixjump(fs, pc, dest)
1548 local jmp = fs.f.code[pc]
1549 local offset = dest - (pc + 1)
1550 assert(dest ~= self.NO_JUMP)
1551 if math.abs(offset) > luaP.MAXARG_sBx then
1552 luaX:syntaxerror(fs.ls, "control structure too long")
1553 end
1554 luaP:SETARG_sBx(jmp, offset)
1555end
1556
1557------------------------------------------------------------------------
1558-- returns current 'pc' and marks it as a jump target (to avoid wrong
1559-- optimizations with consecutive instructions not in the same basic block).
1560-- * used in multiple locations
1561-- * fs.lasttarget tested only by luaK:_nil() when optimizing OP_LOADNIL
1562------------------------------------------------------------------------
1563function luaK:getlabel(fs)
1564 fs.lasttarget = fs.pc
1565 return fs.pc
1566end
1567
1568------------------------------------------------------------------------
1569--
1570-- * used in luaK:need_value(), luaK:removevalues(), luaK:patchlistaux(),
1571-- luaK:concat()
1572------------------------------------------------------------------------
1573function luaK:getjump(fs, pc)
1574 local offset = luaP:GETARG_sBx(fs.f.code[pc])
1575 if offset == self.NO_JUMP then -- point to itself represents end of list
1576 return self.NO_JUMP -- end of list
1577 else
1578 return (pc + 1) + offset -- turn offset into absolute position
1579 end
1580end
1581
1582------------------------------------------------------------------------
1583--
1584-- * used in luaK:need_value(), luaK:patchtestreg(), luaK:invertjump()
1585------------------------------------------------------------------------
1586function luaK:getjumpcontrol(fs, pc)
1587 local pi = fs.f.code[pc]
1588 local ppi = fs.f.code[pc - 1]
1589 if pc >= 1 and luaP:testTMode(luaP:GET_OPCODE(ppi)) ~= 0 then
1590 return ppi
1591 else
1592 return pi
1593 end
1594end
1595
1596------------------------------------------------------------------------
1597-- check whether list has any jump that do not produce a value
1598-- (or produce an inverted value)
1599-- * return value changed to boolean
1600-- * used only in luaK:exp2reg()
1601------------------------------------------------------------------------
1602function luaK:need_value(fs, list)
1603 while list ~= self.NO_JUMP do
1604 local i = self:getjumpcontrol(fs, list)
1605 if luaP:GET_OPCODE(i) ~= "OP_TESTSET" then return true end
1606 list = self:getjump(fs, list)
1607 end
1608 return false -- not found
1609end
1610
1611------------------------------------------------------------------------
1612--
1613-- * used in luaK:removevalues(), luaK:patchlistaux()
1614------------------------------------------------------------------------
1615function luaK:patchtestreg(fs, node, reg)
1616 local i = self:getjumpcontrol(fs, node)
1617 if luaP:GET_OPCODE(i) ~= "OP_TESTSET" then
1618 return false -- cannot patch other instructions
1619 end
1620 if reg ~= luaP.NO_REG and reg ~= luaP:GETARG_B(i) then
1621 luaP:SETARG_A(i, reg)
1622 else -- no register to put value or register already has the value
1623 -- due to use of a table as i, i cannot be replaced by another table
1624 -- so the following is required; there is no change to ARG_C
1625 luaP:SET_OPCODE(i, "OP_TEST")
1626 local b = luaP:GETARG_B(i)
1627 luaP:SETARG_A(i, b)
1628 luaP:SETARG_B(i, 0)
1629 -- *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i)); /* C */
1630 end
1631 return true
1632end
1633
1634------------------------------------------------------------------------
1635--
1636-- * used only in luaK:codenot()
1637------------------------------------------------------------------------
1638function luaK:removevalues(fs, list)
1639 while list ~= self.NO_JUMP do
1640 self:patchtestreg(fs, list, luaP.NO_REG)
1641 list = self:getjump(fs, list)
1642 end
1643end
1644
1645------------------------------------------------------------------------
1646--
1647-- * used in luaK:dischargejpc(), luaK:patchlist(), luaK:exp2reg()
1648------------------------------------------------------------------------
1649function luaK:patchlistaux(fs, list, vtarget, reg, dtarget)
1650 while list ~= self.NO_JUMP do
1651 local _next = self:getjump(fs, list)
1652 if self:patchtestreg(fs, list, reg) then
1653 self:fixjump(fs, list, vtarget)
1654 else
1655 self:fixjump(fs, list, dtarget) -- jump to default target
1656 end
1657 list = _next
1658 end
1659end
1660
1661------------------------------------------------------------------------
1662--
1663-- * used only in luaK:code()
1664------------------------------------------------------------------------
1665function luaK:dischargejpc(fs)
1666 self:patchlistaux(fs, fs.jpc, fs.pc, luaP.NO_REG, fs.pc)
1667 fs.jpc = self.NO_JUMP
1668end
1669
1670------------------------------------------------------------------------
1671--
1672-- * used in (lparser) luaY:whilestat(), luaY:repeatstat(), luaY:forbody()
1673------------------------------------------------------------------------
1674function luaK:patchlist(fs, list, target)
1675 if target == fs.pc then
1676 self:patchtohere(fs, list)
1677 else
1678 assert(target < fs.pc)
1679 self:patchlistaux(fs, list, target, luaP.NO_REG, target)
1680 end
1681end
1682
1683------------------------------------------------------------------------
1684--
1685-- * used in multiple locations
1686------------------------------------------------------------------------
1687function luaK:patchtohere(fs, list)
1688 self:getlabel(fs)
1689 fs.jpc = self:concat(fs, fs.jpc, list)
1690end
1691
1692------------------------------------------------------------------------
1693-- * l1 was a pointer, now l1 is returned and callee assigns the value
1694-- * used in multiple locations
1695------------------------------------------------------------------------
1696function luaK:concat(fs, l1, l2)
1697 if l2 == self.NO_JUMP then return l1
1698 elseif l1 == self.NO_JUMP then
1699 return l2
1700 else
1701 local list = l1
1702 local _next = self:getjump(fs, list)
1703 while _next ~= self.NO_JUMP do -- find last element
1704 list = _next
1705 _next = self:getjump(fs, list)
1706 end
1707 self:fixjump(fs, list, l2)
1708 end
1709 return l1
1710end
1711
1712------------------------------------------------------------------------
1713--
1714-- * used in luaK:reserveregs(), (lparser) luaY:forlist()
1715------------------------------------------------------------------------
1716function luaK:checkstack(fs, n)
1717 local newstack = fs.freereg + n
1718 if newstack > fs.f.maxstacksize then
1719 if newstack >= self.MAXSTACK then
1720 luaX:syntaxerror(fs.ls, "function or expression too complex")
1721 end
1722 fs.f.maxstacksize = newstack
1723 end
1724end
1725
1726------------------------------------------------------------------------
1727--
1728-- * used in multiple locations
1729------------------------------------------------------------------------
1730function luaK:reserveregs(fs, n)
1731 self:checkstack(fs, n)
1732 fs.freereg = fs.freereg + n
1733end
1734
1735------------------------------------------------------------------------
1736--
1737-- * used in luaK:freeexp(), luaK:dischargevars()
1738------------------------------------------------------------------------
1739function luaK:freereg(fs, reg)
1740 if not luaP:ISK(reg) and reg >= fs.nactvar then
1741 fs.freereg = fs.freereg - 1
1742 assert(reg == fs.freereg)
1743 end
1744end
1745
1746------------------------------------------------------------------------
1747--
1748-- * used in multiple locations
1749------------------------------------------------------------------------
1750function luaK:freeexp(fs, e)
1751 if e.k == "VNONRELOC" then
1752 self:freereg(fs, e.info)
1753 end
1754end
1755
1756------------------------------------------------------------------------
1757-- * TODO NOTE implementation is not 100% correct, since the assert fails
1758-- * luaH_set, setobj deleted; direct table access used instead
1759-- * used in luaK:stringK(), luaK:numberK(), luaK:boolK(), luaK:nilK()
1760------------------------------------------------------------------------
1761function luaK:addk(fs, k, v)
1762 local L = fs.L
1763 local idx = fs.h[k.value]
1764 --TValue *idx = luaH_set(L, fs->h, k); /* C */
1765 local f = fs.f
1766 if self:ttisnumber(idx) then
1767 --TODO this assert currently FAILS (last tested for 5.0.2)
1768 --assert(fs.f.k[self:nvalue(idx)] == v)
1769 --assert(luaO_rawequalObj(&fs->f->k[cast_int(nvalue(idx))], v)); /* C */
1770 return self:nvalue(idx)
1771 else -- constant not found; create a new entry
1772 idx = {}
1773 self:setnvalue(idx, fs.nk)
1774 fs.h[k.value] = idx
1775 -- setnvalue(idx, cast_num(fs->nk)); /* C */
1776 luaY:growvector(L, f.k, fs.nk, f.sizek, nil,
1777 luaP.MAXARG_Bx, "constant table overflow")
1778 -- loop to initialize empty f.k positions not required
1779 f.k[fs.nk] = v
1780 -- setobj(L, &f->k[fs->nk], v); /* C */
1781 -- luaC_barrier(L, f, v); /* GC */
1782 local nk = fs.nk
1783 fs.nk = fs.nk + 1
1784 return nk
1785 end
1786
1787end
1788
1789------------------------------------------------------------------------
1790-- creates and sets a string object
1791-- * used in (lparser) luaY:codestring(), luaY:singlevar()
1792------------------------------------------------------------------------
1793function luaK:stringK(fs, s)
1794 local o = {} -- TValue
1795 self:setsvalue(o, s)
1796 return self:addk(fs, o, o)
1797end
1798
1799------------------------------------------------------------------------
1800-- creates and sets a number object
1801-- * used in luaK:prefix() for negative (or negation of) numbers
1802-- * used in (lparser) luaY:simpleexp(), luaY:fornum()
1803------------------------------------------------------------------------
1804function luaK:numberK(fs, r)
1805 local o = {} -- TValue
1806 self:setnvalue(o, r)
1807 return self:addk(fs, o, o)
1808end
1809
1810------------------------------------------------------------------------
1811-- creates and sets a boolean object
1812-- * used only in luaK:exp2RK()
1813------------------------------------------------------------------------
1814function luaK:boolK(fs, b)
1815 local o = {} -- TValue
1816 self:setbvalue(o, b)
1817 return self:addk(fs, o, o)
1818end
1819
1820------------------------------------------------------------------------
1821-- creates and sets a nil object
1822-- * used only in luaK:exp2RK()
1823------------------------------------------------------------------------
1824function luaK:nilK(fs)
1825 local k, v = {}, {} -- TValue
1826 self:setnilvalue(v)
1827 -- cannot use nil as key; instead use table itself to represent nil
1828 self:sethvalue(k, fs.h)
1829 return self:addk(fs, k, v)
1830end
1831
1832------------------------------------------------------------------------
1833--
1834-- * used in luaK:setmultret(), (lparser) luaY:adjust_assign()
1835------------------------------------------------------------------------
1836function luaK:setreturns(fs, e, nresults)
1837 if e.k == "VCALL" then -- expression is an open function call?
1838 luaP:SETARG_C(self:getcode(fs, e), nresults + 1)
1839 elseif e.k == "VVARARG" then
1840 luaP:SETARG_B(self:getcode(fs, e), nresults + 1);
1841 luaP:SETARG_A(self:getcode(fs, e), fs.freereg);
1842 luaK:reserveregs(fs, 1)
1843 end
1844end
1845
1846------------------------------------------------------------------------
1847--
1848-- * used in luaK:dischargevars(), (lparser) luaY:assignment()
1849------------------------------------------------------------------------
1850function luaK:setoneret(fs, e)
1851 if e.k == "VCALL" then -- expression is an open function call?
1852 e.k = "VNONRELOC"
1853 e.info = luaP:GETARG_A(self:getcode(fs, e))
1854 elseif e.k == "VVARARG" then
1855 luaP:SETARG_B(self:getcode(fs, e), 2)
1856 e.k = "VRELOCABLE" -- can relocate its simple result
1857 end
1858end
1859
1860------------------------------------------------------------------------
1861--
1862-- * used in multiple locations
1863------------------------------------------------------------------------
1864function luaK:dischargevars(fs, e)
1865 local k = e.k
1866 if k == "VLOCAL" then
1867 e.k = "VNONRELOC"
1868 elseif k == "VUPVAL" then
1869 e.info = self:codeABC(fs, "OP_GETUPVAL", 0, e.info, 0)
1870 e.k = "VRELOCABLE"
1871 elseif k == "VGLOBAL" then
1872 e.info = self:codeABx(fs, "OP_GETGLOBAL", 0, e.info)
1873 e.k = "VRELOCABLE"
1874 elseif k == "VINDEXED" then
1875 self:freereg(fs, e.aux)
1876 self:freereg(fs, e.info)
1877 e.info = self:codeABC(fs, "OP_GETTABLE", 0, e.info, e.aux)
1878 e.k = "VRELOCABLE"
1879 elseif k == "VVARARG" or k == "VCALL" then
1880 self:setoneret(fs, e)
1881 else
1882 -- there is one value available (somewhere)
1883 end
1884end
1885
1886------------------------------------------------------------------------
1887--
1888-- * used only in luaK:exp2reg()
1889------------------------------------------------------------------------
1890function luaK:code_label(fs, A, b, jump)
1891 self:getlabel(fs) -- those instructions may be jump targets
1892 return self:codeABC(fs, "OP_LOADBOOL", A, b, jump)
1893end
1894
1895------------------------------------------------------------------------
1896--
1897-- * used in luaK:discharge2anyreg(), luaK:exp2reg()
1898------------------------------------------------------------------------
1899function luaK:discharge2reg(fs, e, reg)
1900 self:dischargevars(fs, e)
1901 local k = e.k
1902 if k == "VNIL" then
1903 self:_nil(fs, reg, 1)
1904 elseif k == "VFALSE" or k == "VTRUE" then
1905 self:codeABC(fs, "OP_LOADBOOL", reg, (e.k == "VTRUE") and 1 or 0, 0)
1906 elseif k == "VK" then
1907 self:codeABx(fs, "OP_LOADK", reg, e.info)
1908 elseif k == "VKNUM" then
1909 self:codeABx(fs, "OP_LOADK", reg, self:numberK(fs, e.nval))
1910 elseif k == "VRELOCABLE" then
1911 local pc = self:getcode(fs, e)
1912 luaP:SETARG_A(pc, reg)
1913 elseif k == "VNONRELOC" then
1914 if reg ~= e.info then
1915 self:codeABC(fs, "OP_MOVE", reg, e.info, 0)
1916 end
1917 else
1918 assert(e.k == "VVOID" or e.k == "VJMP")
1919 return -- nothing to do...
1920 end
1921 e.info = reg
1922 e.k = "VNONRELOC"
1923end
1924
1925------------------------------------------------------------------------
1926--
1927-- * used in luaK:jumponcond(), luaK:codenot()
1928------------------------------------------------------------------------
1929function luaK:discharge2anyreg(fs, e)
1930 if e.k ~= "VNONRELOC" then
1931 self:reserveregs(fs, 1)
1932 self:discharge2reg(fs, e, fs.freereg - 1)
1933 end
1934end
1935
1936------------------------------------------------------------------------
1937--
1938-- * used in luaK:exp2nextreg(), luaK:exp2anyreg(), luaK:storevar()
1939------------------------------------------------------------------------
1940function luaK:exp2reg(fs, e, reg)
1941 self:discharge2reg(fs, e, reg)
1942 if e.k == "VJMP" then
1943 e.t = self:concat(fs, e.t, e.info) -- put this jump in 't' list
1944 end
1945 if self:hasjumps(e) then
1946 local final -- position after whole expression
1947 local p_f = self.NO_JUMP -- position of an eventual LOAD false
1948 local p_t = self.NO_JUMP -- position of an eventual LOAD true
1949 if self:need_value(fs, e.t) or self:need_value(fs, e.f) then
1950 local fj = (e.k == "VJMP") and self.NO_JUMP or self:jump(fs)
1951 p_f = self:code_label(fs, reg, 0, 1)
1952 p_t = self:code_label(fs, reg, 1, 0)
1953 self:patchtohere(fs, fj)
1954 end
1955 final = self:getlabel(fs)
1956 self:patchlistaux(fs, e.f, final, reg, p_f)
1957 self:patchlistaux(fs, e.t, final, reg, p_t)
1958 end
1959 e.f, e.t = self.NO_JUMP, self.NO_JUMP
1960 e.info = reg
1961 e.k = "VNONRELOC"
1962end
1963
1964------------------------------------------------------------------------
1965--
1966-- * used in multiple locations
1967------------------------------------------------------------------------
1968function luaK:exp2nextreg(fs, e)
1969 self:dischargevars(fs, e)
1970 self:freeexp(fs, e)
1971 self:reserveregs(fs, 1)
1972 self:exp2reg(fs, e, fs.freereg - 1)
1973end
1974
1975------------------------------------------------------------------------
1976--
1977-- * used in multiple locations
1978------------------------------------------------------------------------
1979function luaK:exp2anyreg(fs, e)
1980 self:dischargevars(fs, e)
1981 if e.k == "VNONRELOC" then
1982 if not self:hasjumps(e) then -- exp is already in a register
1983 return e.info
1984 end
1985 if e.info >= fs.nactvar then -- reg. is not a local?
1986 self:exp2reg(fs, e, e.info) -- put value on it
1987 return e.info
1988 end
1989 end
1990 self:exp2nextreg(fs, e) -- default
1991 return e.info
1992end
1993
1994------------------------------------------------------------------------
1995--
1996-- * used in luaK:exp2RK(), luaK:prefix(), luaK:posfix()
1997-- * used in (lparser) luaY:yindex()
1998------------------------------------------------------------------------
1999function luaK:exp2val(fs, e)
2000 if self:hasjumps(e) then
2001 self:exp2anyreg(fs, e)
2002 else
2003 self:dischargevars(fs, e)
2004 end
2005end
2006
2007------------------------------------------------------------------------
2008--
2009-- * used in multiple locations
2010------------------------------------------------------------------------
2011function luaK:exp2RK(fs, e)
2012 self:exp2val(fs, e)
2013 local k = e.k
2014 if k == "VKNUM" or k == "VTRUE" or k == "VFALSE" or k == "VNIL" then
2015 if fs.nk <= luaP.MAXINDEXRK then -- constant fit in RK operand?
2016 -- converted from a 2-deep ternary operator expression
2017 if e.k == "VNIL" then
2018 e.info = self:nilK(fs)
2019 else
2020 e.info = (e.k == "VKNUM") and self:numberK(fs, e.nval)
2021 or self:boolK(fs, e.k == "VTRUE")
2022 end
2023 e.k = "VK"
2024 return luaP:RKASK(e.info)
2025 end
2026 elseif k == "VK" then
2027 if e.info <= luaP.MAXINDEXRK then -- constant fit in argC?
2028 return luaP:RKASK(e.info)
2029 end
2030 else
2031 -- default
2032 end
2033 -- not a constant in the right range: put it in a register
2034 return self:exp2anyreg(fs, e)
2035end
2036
2037------------------------------------------------------------------------
2038--
2039-- * used in (lparser) luaY:assignment(), luaY:localfunc(), luaY:funcstat()
2040------------------------------------------------------------------------
2041function luaK:storevar(fs, var, ex)
2042 local k = var.k
2043 if k == "VLOCAL" then
2044 self:freeexp(fs, ex)
2045 self:exp2reg(fs, ex, var.info)
2046 return
2047 elseif k == "VUPVAL" then
2048 local e = self:exp2anyreg(fs, ex)
2049 self:codeABC(fs, "OP_SETUPVAL", e, var.info, 0)
2050 elseif k == "VGLOBAL" then
2051 local e = self:exp2anyreg(fs, ex)
2052 self:codeABx(fs, "OP_SETGLOBAL", e, var.info)
2053 elseif k == "VINDEXED" then
2054 local e = self:exp2RK(fs, ex)
2055 self:codeABC(fs, "OP_SETTABLE", var.info, var.aux, e)
2056 else
2057 assert(0) -- invalid var kind to store
2058 end
2059 self:freeexp(fs, ex)
2060end
2061
2062------------------------------------------------------------------------
2063--
2064-- * used only in (lparser) luaY:primaryexp()
2065------------------------------------------------------------------------
2066function luaK:_self(fs, e, key)
2067 self:exp2anyreg(fs, e)
2068 self:freeexp(fs, e)
2069 local func = fs.freereg
2070 self:reserveregs(fs, 2)
2071 self:codeABC(fs, "OP_SELF", func, e.info, self:exp2RK(fs, key))
2072 self:freeexp(fs, key)
2073 e.info = func
2074 e.k = "VNONRELOC"
2075end
2076
2077------------------------------------------------------------------------
2078--
2079-- * used in luaK:goiftrue(), luaK:codenot()
2080------------------------------------------------------------------------
2081function luaK:invertjump(fs, e)
2082 local pc = self:getjumpcontrol(fs, e.info)
2083 assert(luaP:testTMode(luaP:GET_OPCODE(pc)) ~= 0 and
2084 luaP:GET_OPCODE(pc) ~= "OP_TESTSET" and
2085 luaP:GET_OPCODE(pc) ~= "OP_TEST")
2086 luaP:SETARG_A(pc, (luaP:GETARG_A(pc) == 0) and 1 or 0)
2087end
2088
2089------------------------------------------------------------------------
2090--
2091-- * used in luaK:goiftrue(), luaK:goiffalse()
2092------------------------------------------------------------------------
2093function luaK:jumponcond(fs, e, cond)
2094 if e.k == "VRELOCABLE" then
2095 local ie = self:getcode(fs, e)
2096 if luaP:GET_OPCODE(ie) == "OP_NOT" then
2097 fs.pc = fs.pc - 1 -- remove previous OP_NOT
2098 return self:condjump(fs, "OP_TEST", luaP:GETARG_B(ie), 0, cond and 0 or 1)
2099 end
2100 -- else go through
2101 end
2102 self:discharge2anyreg(fs, e)
2103 self:freeexp(fs, e)
2104 return self:condjump(fs, "OP_TESTSET", luaP.NO_REG, e.info, cond and 1 or 0)
2105end
2106
2107------------------------------------------------------------------------
2108--
2109-- * used in luaK:infix(), (lparser) luaY:cond()
2110------------------------------------------------------------------------
2111function luaK:goiftrue(fs, e)
2112 local pc -- pc of last jump
2113 self:dischargevars(fs, e)
2114 local k = e.k
2115 if k == "VK" or k == "VKNUM" or k == "VTRUE" then
2116 pc = self.NO_JUMP -- always true; do nothing
2117 elseif k == "VFALSE" then
2118 pc = self:jump(fs) -- always jump
2119 elseif k == "VJMP" then
2120 self:invertjump(fs, e)
2121 pc = e.info
2122 else
2123 pc = self:jumponcond(fs, e, false)
2124 end
2125 e.f = self:concat(fs, e.f, pc) -- insert last jump in `f' list
2126 self:patchtohere(fs, e.t)
2127 e.t = self.NO_JUMP
2128end
2129
2130------------------------------------------------------------------------
2131--
2132-- * used in luaK:infix()
2133------------------------------------------------------------------------
2134function luaK:goiffalse(fs, e)
2135 local pc -- pc of last jump
2136 self:dischargevars(fs, e)
2137 local k = e.k
2138 if k == "VNIL" or k == "VFALSE"then
2139 pc = self.NO_JUMP -- always false; do nothing
2140 elseif k == "VTRUE" then
2141 pc = self:jump(fs) -- always jump
2142 elseif k == "VJMP" then
2143 pc = e.info
2144 else
2145 pc = self:jumponcond(fs, e, true)
2146 end
2147 e.t = self:concat(fs, e.t, pc) -- insert last jump in `t' list
2148 self:patchtohere(fs, e.f)
2149 e.f = self.NO_JUMP
2150end
2151
2152------------------------------------------------------------------------
2153--
2154-- * used only in luaK:prefix()
2155------------------------------------------------------------------------
2156function luaK:codenot(fs, e)
2157 self:dischargevars(fs, e)
2158 local k = e.k
2159 if k == "VNIL" or k == "VFALSE" then
2160 e.k = "VTRUE"
2161 elseif k == "VK" or k == "VKNUM" or k == "VTRUE" then
2162 e.k = "VFALSE"
2163 elseif k == "VJMP" then
2164 self:invertjump(fs, e)
2165 elseif k == "VRELOCABLE" or k == "VNONRELOC" then
2166 self:discharge2anyreg(fs, e)
2167 self:freeexp(fs, e)
2168 e.info = self:codeABC(fs, "OP_NOT", 0, e.info, 0)
2169 e.k = "VRELOCABLE"
2170 else
2171 assert(0) -- cannot happen
2172 end
2173 -- interchange true and false lists
2174 e.f, e.t = e.t, e.f
2175 self:removevalues(fs, e.f)
2176 self:removevalues(fs, e.t)
2177end
2178
2179------------------------------------------------------------------------
2180--
2181-- * used in (lparser) luaY:field(), luaY:primaryexp()
2182------------------------------------------------------------------------
2183function luaK:indexed(fs, t, k)
2184 t.aux = self:exp2RK(fs, k)
2185 t.k = "VINDEXED"
2186end
2187
2188------------------------------------------------------------------------
2189--
2190-- * used only in luaK:codearith()
2191------------------------------------------------------------------------
2192function luaK:constfolding(op, e1, e2)
2193 local r
2194 if not self:isnumeral(e1) or not self:isnumeral(e2) then return false end
2195 local v1 = e1.nval
2196 local v2 = e2.nval
2197 if op == "OP_ADD" then
2198 r = self:numadd(v1, v2)
2199 elseif op == "OP_SUB" then
2200 r = self:numsub(v1, v2)
2201 elseif op == "OP_MUL" then
2202 r = self:nummul(v1, v2)
2203 elseif op == "OP_DIV" then
2204 if v2 == 0 then return false end -- do not attempt to divide by 0
2205 r = self:numdiv(v1, v2)
2206 elseif op == "OP_MOD" then
2207 if v2 == 0 then return false end -- do not attempt to divide by 0
2208 r = self:nummod(v1, v2)
2209 elseif op == "OP_POW" then
2210 r = self:numpow(v1, v2)
2211 elseif op == "OP_UNM" then
2212 r = self:numunm(v1)
2213 elseif op == "OP_LEN" then
2214 return false -- no constant folding for 'len'
2215 else
2216 assert(0)
2217 r = 0
2218 end
2219 if self:numisnan(r) then return false end -- do not attempt to produce NaN
2220 e1.nval = r
2221 return true
2222end
2223
2224------------------------------------------------------------------------
2225--
2226-- * used in luaK:prefix(), luaK:posfix()
2227------------------------------------------------------------------------
2228function luaK:codearith(fs, op, e1, e2)
2229 if self:constfolding(op, e1, e2) then
2230 return
2231 else
2232 local o2 = (op ~= "OP_UNM" and op ~= "OP_LEN") and self:exp2RK(fs, e2) or 0
2233 local o1 = self:exp2RK(fs, e1)
2234 if o1 > o2 then
2235 self:freeexp(fs, e1)
2236 self:freeexp(fs, e2)
2237 else
2238 self:freeexp(fs, e2)
2239 self:freeexp(fs, e1)
2240 end
2241 e1.info = self:codeABC(fs, op, 0, o1, o2)
2242 e1.k = "VRELOCABLE"
2243 end
2244end
2245
2246------------------------------------------------------------------------
2247--
2248-- * used only in luaK:posfix()
2249------------------------------------------------------------------------
2250function luaK:codecomp(fs, op, cond, e1, e2)
2251 local o1 = self:exp2RK(fs, e1)
2252 local o2 = self:exp2RK(fs, e2)
2253 self:freeexp(fs, e2)
2254 self:freeexp(fs, e1)
2255 if cond == 0 and op ~= "OP_EQ" then
2256 -- exchange args to replace by `<' or `<='
2257 o1, o2 = o2, o1 -- o1 <==> o2
2258 cond = 1
2259 end
2260 e1.info = self:condjump(fs, op, cond, o1, o2)
2261 e1.k = "VJMP"
2262end
2263
2264------------------------------------------------------------------------
2265--
2266-- * used only in (lparser) luaY:subexpr()
2267------------------------------------------------------------------------
2268function luaK:prefix(fs, op, e)
2269 local e2 = {} -- expdesc
2270 e2.t, e2.f = self.NO_JUMP, self.NO_JUMP
2271 e2.k = "VKNUM"
2272 e2.nval = 0
2273 if op == "OPR_MINUS" then
2274 if not self:isnumeral(e) then
2275 self:exp2anyreg(fs, e) -- cannot operate on non-numeric constants
2276 end
2277 self:codearith(fs, "OP_UNM", e, e2)
2278 elseif op == "OPR_NOT" then
2279 self:codenot(fs, e)
2280 elseif op == "OPR_LEN" then
2281 self:exp2anyreg(fs, e) -- cannot operate on constants
2282 self:codearith(fs, "OP_LEN", e, e2)
2283 else
2284 assert(0)
2285 end
2286end
2287
2288------------------------------------------------------------------------
2289--
2290-- * used only in (lparser) luaY:subexpr()
2291------------------------------------------------------------------------
2292function luaK:infix(fs, op, v)
2293 if op == "OPR_AND" then
2294 self:goiftrue(fs, v)
2295 elseif op == "OPR_OR" then
2296 self:goiffalse(fs, v)
2297 elseif op == "OPR_CONCAT" then
2298 self:exp2nextreg(fs, v) -- operand must be on the 'stack'
2299 elseif op == "OPR_ADD" or op == "OPR_SUB" or
2300 op == "OPR_MUL" or op == "OPR_DIV" or
2301 op == "OPR_MOD" or op == "OPR_POW" then
2302 if not self:isnumeral(v) then self:exp2RK(fs, v) end
2303 else
2304 self:exp2RK(fs, v)
2305 end
2306end
2307
2308------------------------------------------------------------------------
2309--
2310-- * used only in (lparser) luaY:subexpr()
2311------------------------------------------------------------------------
2312-- table lookups to simplify testing
2313luaK.arith_op = {
2314 OPR_ADD = "OP_ADD", OPR_SUB = "OP_SUB", OPR_MUL = "OP_MUL",
2315 OPR_DIV = "OP_DIV", OPR_MOD = "OP_MOD", OPR_POW = "OP_POW",
2316}
2317luaK.comp_op = {
2318 OPR_EQ = "OP_EQ", OPR_NE = "OP_EQ", OPR_LT = "OP_LT",
2319 OPR_LE = "OP_LE", OPR_GT = "OP_LT", OPR_GE = "OP_LE",
2320}
2321luaK.comp_cond = {
2322 OPR_EQ = 1, OPR_NE = 0, OPR_LT = 1,
2323 OPR_LE = 1, OPR_GT = 0, OPR_GE = 0,
2324}
2325function luaK:posfix(fs, op, e1, e2)
2326 -- needed because e1 = e2 doesn't copy values...
2327 -- * in 5.0.x, only k/info/aux/t/f copied, t for AND, f for OR
2328 -- but here, all elements are copied for completeness' sake
2329 local function copyexp(e1, e2)
2330 e1.k = e2.k
2331 e1.info = e2.info; e1.aux = e2.aux
2332 e1.nval = e2.nval
2333 e1.t = e2.t; e1.f = e2.f
2334 end
2335 if op == "OPR_AND" then
2336 assert(e1.t == self.NO_JUMP) -- list must be closed
2337 self:dischargevars(fs, e2)
2338 e2.f = self:concat(fs, e2.f, e1.f)
2339 copyexp(e1, e2)
2340 elseif op == "OPR_OR" then
2341 assert(e1.f == self.NO_JUMP) -- list must be closed
2342 self:dischargevars(fs, e2)
2343 e2.t = self:concat(fs, e2.t, e1.t)
2344 copyexp(e1, e2)
2345 elseif op == "OPR_CONCAT" then
2346 self:exp2val(fs, e2)
2347 if e2.k == "VRELOCABLE" and luaP:GET_OPCODE(self:getcode(fs, e2)) == "OP_CONCAT" then
2348 assert(e1.info == luaP:GETARG_B(self:getcode(fs, e2)) - 1)
2349 self:freeexp(fs, e1)
2350 luaP:SETARG_B(self:getcode(fs, e2), e1.info)
2351 e1.k = "VRELOCABLE"
2352 e1.info = e2.info
2353 else
2354 self:exp2nextreg(fs, e2) -- operand must be on the 'stack'
2355 self:codearith(fs, "OP_CONCAT", e1, e2)
2356 end
2357 else
2358 -- the following uses a table lookup in place of conditionals
2359 local arith = self.arith_op[op]
2360 if arith then
2361 self:codearith(fs, arith, e1, e2)
2362 else
2363 local comp = self.comp_op[op]
2364 if comp then
2365 self:codecomp(fs, comp, self.comp_cond[op], e1, e2)
2366 else
2367 assert(0)
2368 end
2369 end--if arith
2370 end--if op
2371end
2372
2373------------------------------------------------------------------------
2374-- adjusts debug information for last instruction written, in order to
2375-- change the line where item comes into existence
2376-- * used in (lparser) luaY:funcargs(), luaY:forbody(), luaY:funcstat()
2377------------------------------------------------------------------------
2378function luaK:fixline(fs, line)
2379 fs.f.lineinfo[fs.pc - 1] = line
2380end
2381
2382------------------------------------------------------------------------
2383-- general function to write an instruction into the instruction buffer,
2384-- sets debug information too
2385-- * used in luaK:codeABC(), luaK:codeABx()
2386-- * called directly by (lparser) luaY:whilestat()
2387------------------------------------------------------------------------
2388function luaK:code(fs, i, line)
2389 local f = fs.f
2390 self:dischargejpc(fs) -- 'pc' will change
2391 -- put new instruction in code array
2392 luaY:growvector(fs.L, f.code, fs.pc, f.sizecode, nil,
2393 luaY.MAX_INT, "code size overflow")
2394 f.code[fs.pc] = i
2395 -- save corresponding line information
2396 luaY:growvector(fs.L, f.lineinfo, fs.pc, f.sizelineinfo, nil,
2397 luaY.MAX_INT, "code size overflow")
2398 f.lineinfo[fs.pc] = line
2399 local pc = fs.pc
2400 fs.pc = fs.pc + 1
2401 return pc
2402end
2403
2404------------------------------------------------------------------------
2405-- writes an instruction of type ABC
2406-- * calls luaK:code()
2407------------------------------------------------------------------------
2408function luaK:codeABC(fs, o, a, b, c)
2409 assert(luaP:getOpMode(o) == luaP.OpMode.iABC)
2410 assert(luaP:getBMode(o) ~= luaP.OpArgMask.OpArgN or b == 0)
2411 assert(luaP:getCMode(o) ~= luaP.OpArgMask.OpArgN or c == 0)
2412 return self:code(fs, luaP:CREATE_ABC(o, a, b, c), fs.ls.lastline)
2413end
2414
2415------------------------------------------------------------------------
2416-- writes an instruction of type ABx
2417-- * calls luaK:code(), called by luaK:codeAsBx()
2418------------------------------------------------------------------------
2419function luaK:codeABx(fs, o, a, bc)
2420 assert(luaP:getOpMode(o) == luaP.OpMode.iABx or
2421 luaP:getOpMode(o) == luaP.OpMode.iAsBx)
2422 assert(luaP:getCMode(o) == luaP.OpArgMask.OpArgN)
2423 return self:code(fs, luaP:CREATE_ABx(o, a, bc), fs.ls.lastline)
2424end
2425
2426------------------------------------------------------------------------
2427--
2428-- * used in (lparser) luaY:closelistfield(), luaY:lastlistfield()
2429------------------------------------------------------------------------
2430function luaK:setlist(fs, base, nelems, tostore)
2431 local c = math.floor((nelems - 1)/luaP.LFIELDS_PER_FLUSH) + 1
2432 local b = (tostore == luaY.LUA_MULTRET) and 0 or tostore
2433 assert(tostore ~= 0)
2434 if c <= luaP.MAXARG_C then
2435 self:codeABC(fs, "OP_SETLIST", base, b, c)
2436 else
2437 self:codeABC(fs, "OP_SETLIST", base, b, 0)
2438 self:code(fs, luaP:CREATE_Inst(c), fs.ls.lastline)
2439 end
2440 fs.freereg = base + 1 -- free registers with list values
2441end
2442
2443local luaKfunc = function(a) luaY = a return luaK end
2444
2445--[[--------------------------------------------------------------------
2446
2447 ldump.lua
2448 Save precompiled Lua chunks
2449 This file is part of Yueliang.
2450
2451 Copyright (c) 2006 Kein-Hong Man <khman@users.sf.net>
2452 The COPYRIGHT file describes the conditions
2453 under which this software may be distributed.
2454
2455 See the ChangeLog for more information.
2456
2457----------------------------------------------------------------------]]
2458
2459--[[--------------------------------------------------------------------
2460-- Notes:
2461-- * WARNING! byte order (little endian) and data type sizes for header
2462-- signature values hard-coded; see luaU:header
2463-- * chunk writer generators are included, see below
2464-- * one significant difference is that instructions are still in table
2465-- form (with OP/A/B/C/Bx fields) and luaP:Instruction() is needed to
2466-- convert them into 4-char strings
2467--
2468-- Not implemented:
2469-- * DumpVar, DumpMem has been removed
2470-- * DumpVector folded into folded into DumpDebug, DumpCode
2471--
2472-- Added:
2473-- * for convenience, the following two functions have been added:
2474-- luaU:make_setS: create a chunk writer that writes to a string
2475-- luaU:make_setF: create a chunk writer that writes to a file
2476-- (lua.h contains a typedef for lua_Writer/lua_Chunkwriter, and
2477-- a Lua-based implementation exists, writer() in lstrlib.c)
2478-- * luaU:ttype(o) (from lobject.h)
2479-- * for converting number types to its binary equivalent:
2480-- luaU:from_double(x): encode double value for writing
2481-- luaU:from_int(x): encode integer value for writing
2482-- (error checking is limited for these conversion functions)
2483-- (double conversion does not support denormals or NaNs)
2484--
2485-- Changed in 5.1.x:
2486-- * the dumper was mostly rewritten in Lua 5.1.x, so notes on the
2487-- differences between 5.0.x and 5.1.x is limited
2488-- * LUAC_VERSION bumped to 0x51, LUAC_FORMAT added
2489-- * developer is expected to adjust LUAC_FORMAT in order to identify
2490-- non-standard binary chunk formats
2491-- * header signature code is smaller, has been simplified, and is
2492-- tested as a single unit; its logic is shared with the undumper
2493-- * no more endian conversion, invalid endianness mean rejection
2494-- * opcode field sizes are no longer exposed in the header
2495-- * code moved to front of a prototype, followed by constants
2496-- * debug information moved to the end of the binary chunk, and the
2497-- relevant functions folded into a single function
2498-- * luaU:dump returns a writer status code
2499-- * chunk writer now implements status code because dumper uses it
2500-- * luaU:endianness removed
2501----------------------------------------------------------------------]]
2502
2503--requires luaP
2504local luaU = {}
2505local luaP = luaPfunc
2506
2507-- mark for precompiled code ('<esc>Lua') (from lua.h)
2508luaU.LUA_SIGNATURE = "\27Lua"
2509
2510-- constants used by dumper (from lua.h)
2511luaU.LUA_TNUMBER = 3
2512luaU.LUA_TSTRING = 4
2513luaU.LUA_TNIL = 0
2514luaU.LUA_TBOOLEAN = 1
2515luaU.LUA_TNONE = -1
2516
2517-- constants for header of binary files (from lundump.h)
2518luaU.LUAC_VERSION = 0x51 -- this is Lua 5.1
2519luaU.LUAC_FORMAT = 0 -- this is the official format
2520luaU.LUAC_HEADERSIZE = 12 -- size of header of binary files
2521
2522--[[--------------------------------------------------------------------
2523-- Additional functions to handle chunk writing
2524-- * to use make_setS and make_setF, see test_ldump.lua elsewhere
2525----------------------------------------------------------------------]]
2526
2527------------------------------------------------------------------------
2528-- create a chunk writer that writes to a string
2529-- * returns the writer function and a table containing the string
2530-- * to get the final result, look in buff.data
2531------------------------------------------------------------------------
2532function luaU:make_setS()
2533 local buff = {}
2534 buff.data = ""
2535 local writer =
2536 function(s, buff) -- chunk writer
2537 if not s then return 0 end
2538 buff.data = buff.data..s
2539 return 0
2540 end
2541 return writer, buff
2542end
2543
2544------------------------------------------------------------------------
2545-- create a chunk writer that writes to a file
2546-- * returns the writer function and a table containing the file handle
2547-- * if a nil is passed, then writer should close the open file
2548------------------------------------------------------------------------
2549function luaU:make_setF(filename)
2550 local buff = {}
2551 buff.h = io.open(filename, "wb")
2552 if not buff.h then return nil end
2553 local writer =
2554 function(s, buff) -- chunk writer
2555 if not buff.h then return 0 end
2556 if not s then
2557 if buff.h:close() then return 0 end
2558 else
2559 if buff.h:write(s) then return 0 end
2560 end
2561 return 1
2562 end
2563 return writer, buff
2564end
2565
2566------------------------------------------------------------------------
2567-- works like the lobject.h version except that TObject used in these
2568-- scripts only has a 'value' field, no 'tt' field (native types used)
2569------------------------------------------------------------------------
2570function luaU:ttype(o)
2571 local tt = type(o.value)
2572 if tt == "number" then return self.LUA_TNUMBER
2573 elseif tt == "string" then return self.LUA_TSTRING
2574 elseif tt == "nil" then return self.LUA_TNIL
2575 elseif tt == "boolean" then return self.LUA_TBOOLEAN
2576 else
2577 return self.LUA_TNONE -- the rest should not appear
2578 end
2579end
2580
2581-----------------------------------------------------------------------
2582-- converts a IEEE754 double number to an 8-byte little-endian string
2583-- * luaU:from_double() and luaU:from_int() are adapted from ChunkBake
2584-- * supports +/- Infinity, but not denormals or NaNs
2585-----------------------------------------------------------------------
2586function luaU:from_double(x)
2587 local function grab_byte(v)
2588 local c = v % 256
2589 return (v - c) / 256, string.char(c)
2590 end
2591 local sign = 0
2592 if x < 0 then sign = 1; x = -x end
2593 local mantissa, exponent = math.frexp(x)
2594 if x == 0 then -- zero
2595 mantissa, exponent = 0, 0
2596 elseif x == 1/0 then
2597 mantissa, exponent = 0, 2047
2598 else
2599 mantissa = (mantissa * 2 - 1) * math.ldexp(0.5, 53)
2600 exponent = exponent + 1022
2601 end
2602 local v, byte = "" -- convert to bytes
2603 x = math.floor(mantissa)
2604 for i = 1,6 do
2605 x, byte = grab_byte(x); v = v..byte -- 47:0
2606 end
2607 x, byte = grab_byte(exponent * 16 + x); v = v..byte -- 55:48
2608 x, byte = grab_byte(sign * 128 + x); v = v..byte -- 63:56
2609 return v
2610end
2611
2612-----------------------------------------------------------------------
2613-- converts a number to a little-endian 32-bit integer string
2614-- * input value assumed to not overflow, can be signed/unsigned
2615-----------------------------------------------------------------------
2616function luaU:from_int(x)
2617 local v = ""
2618 x = math.floor(x)
2619 if x < 0 then x = 4294967296 + x end -- ULONG_MAX+1
2620 for i = 1, 4 do
2621 local c = x % 256
2622 v = v..string.char(c); x = math.floor(x / 256)
2623 end
2624 return v
2625end
2626
2627--[[--------------------------------------------------------------------
2628-- Functions to make a binary chunk
2629-- * many functions have the size parameter removed, since output is
2630-- in the form of a string and some sizes are implicit or hard-coded
2631----------------------------------------------------------------------]]
2632
2633--[[--------------------------------------------------------------------
2634-- struct DumpState:
2635-- L -- lua_State (not used in this script)
2636-- writer -- lua_Writer (chunk writer function)
2637-- data -- void* (chunk writer context or data already written)
2638-- strip -- if true, don't write any debug information
2639-- status -- if non-zero, an error has occured
2640----------------------------------------------------------------------]]
2641
2642------------------------------------------------------------------------
2643-- dumps a block of bytes
2644-- * lua_unlock(D.L), lua_lock(D.L) unused
2645------------------------------------------------------------------------
2646function luaU:DumpBlock(b, D)
2647 if D.status == 0 then
2648 -- lua_unlock(D->L);
2649 D.status = D.write(b, D.data)
2650 -- lua_lock(D->L);
2651 end
2652end
2653
2654------------------------------------------------------------------------
2655-- dumps a char
2656------------------------------------------------------------------------
2657function luaU:DumpChar(y, D)
2658 self:DumpBlock(string.char(y), D)
2659end
2660
2661------------------------------------------------------------------------
2662-- dumps a 32-bit signed or unsigned integer (for int) (hard-coded)
2663------------------------------------------------------------------------
2664function luaU:DumpInt(x, D)
2665 self:DumpBlock(self:from_int(x), D)
2666end
2667
2668------------------------------------------------------------------------
2669-- dumps a lua_Number (hard-coded as a double)
2670------------------------------------------------------------------------
2671function luaU:DumpNumber(x, D)
2672 self:DumpBlock(self:from_double(x), D)
2673end
2674
2675------------------------------------------------------------------------
2676-- dumps a Lua string (size type is hard-coded)
2677------------------------------------------------------------------------
2678function luaU:DumpString(s, D)
2679 if s == nil then
2680 self:DumpInt(0, D)
2681 else
2682 s = s.."\0" -- include trailing '\0'
2683 self:DumpInt(#s, D)
2684 self:DumpBlock(s, D)
2685 end
2686end
2687
2688------------------------------------------------------------------------
2689-- dumps instruction block from function prototype
2690------------------------------------------------------------------------
2691function luaU:DumpCode(f, D)
2692 local n = f.sizecode
2693 --was DumpVector
2694 self:DumpInt(n, D)
2695 for i = 0, n - 1 do
2696 self:DumpBlock(luaP:Instruction(f.code[i]), D)
2697 end
2698end
2699
2700------------------------------------------------------------------------
2701-- dump constant pool from function prototype
2702-- * bvalue(o), nvalue(o) and rawtsvalue(o) macros removed
2703------------------------------------------------------------------------
2704function luaU:DumpConstants(f, D)
2705 local n = f.sizek
2706 self:DumpInt(n, D)
2707 for i = 0, n - 1 do
2708 local o = f.k[i] -- TValue
2709 local tt = self:ttype(o)
2710 self:DumpChar(tt, D)
2711 if tt == self.LUA_TNIL then
2712 elseif tt == self.LUA_TBOOLEAN then
2713 self:DumpChar(o.value and 1 or 0, D)
2714 elseif tt == self.LUA_TNUMBER then
2715 self:DumpNumber(o.value, D)
2716 elseif tt == self.LUA_TSTRING then
2717 self:DumpString(o.value, D)
2718 else
2719 --lua_assert(0) -- cannot happen
2720 end
2721 end
2722 n = f.sizep
2723 self:DumpInt(n, D)
2724 for i = 0, n - 1 do
2725 self:DumpFunction(f.p[i], f.source, D)
2726 end
2727end
2728
2729------------------------------------------------------------------------
2730-- dump debug information
2731------------------------------------------------------------------------
2732function luaU:DumpDebug(f, D)
2733 local n
2734 n = D.strip and 0 or f.sizelineinfo -- dump line information
2735 --was DumpVector
2736 self:DumpInt(n, D)
2737 for i = 0, n - 1 do
2738 self:DumpInt(f.lineinfo[i], D)
2739 end
2740 n = D.strip and 0 or f.sizelocvars -- dump local information
2741 self:DumpInt(n, D)
2742 for i = 0, n - 1 do
2743 self:DumpString(f.locvars[i].varname, D)
2744 self:DumpInt(f.locvars[i].startpc, D)
2745 self:DumpInt(f.locvars[i].endpc, D)
2746 end
2747 n = D.strip and 0 or f.sizeupvalues -- dump upvalue information
2748 self:DumpInt(n, D)
2749 for i = 0, n - 1 do
2750 self:DumpString(f.upvalues[i], D)
2751 end
2752end
2753
2754------------------------------------------------------------------------
2755-- dump child function prototypes from function prototype
2756------------------------------------------------------------------------
2757function luaU:DumpFunction(f, p, D)
2758 local source = f.source
2759 if source == p or D.strip then source = nil end
2760 self:DumpString(source, D)
2761 self:DumpInt(f.lineDefined, D)
2762 self:DumpInt(f.lastlinedefined, D)
2763 self:DumpChar(f.nups, D)
2764 self:DumpChar(f.numparams, D)
2765 self:DumpChar(f.is_vararg, D)
2766 self:DumpChar(f.maxstacksize, D)
2767 self:DumpCode(f, D)
2768 self:DumpConstants(f, D)
2769 self:DumpDebug(f, D)
2770end
2771
2772------------------------------------------------------------------------
2773-- dump Lua header section (some sizes hard-coded)
2774------------------------------------------------------------------------
2775function luaU:DumpHeader(D)
2776 local h = self:header()
2777 assert(#h == self.LUAC_HEADERSIZE) -- fixed buffer now an assert
2778 self:DumpBlock(h, D)
2779end
2780
2781------------------------------------------------------------------------
2782-- make header (from lundump.c)
2783-- returns the header string
2784------------------------------------------------------------------------
2785function luaU:header()
2786 local x = 1
2787 return self.LUA_SIGNATURE..
2788 string.char(
2789 self.LUAC_VERSION,
2790 self.LUAC_FORMAT,
2791 x, -- endianness (1=little)
2792 4, -- sizeof(int)
2793 4, -- sizeof(size_t)
2794 4, -- sizeof(Instruction)
2795 8, -- sizeof(lua_Number)
2796 0) -- is lua_Number integral?
2797end
2798
2799------------------------------------------------------------------------
2800-- dump Lua function as precompiled chunk
2801-- (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip)
2802-- * w, data are created from make_setS, make_setF
2803------------------------------------------------------------------------
2804function luaU:dump(L, f, w, data, strip)
2805 local D = {} -- DumpState
2806 D.L = L
2807 D.write = w
2808 D.data = data
2809 D.strip = strip
2810 D.status = 0
2811 self:DumpHeader(D)
2812 self:DumpFunction(f, nil, D)
2813 -- added: for a chunk writer writing to a file, this final call with
2814 -- nil data is to indicate to the writer to close the file
2815 D.write(nil, D.data)
2816 return D.status
2817end
2818
2819local luaUfunc = luaU
2820
2821--[[--------------------------------------------------------------------
2822
2823 lparser.lua
2824 Lua 5 parser in Lua
2825 This file is part of Yueliang.
2826
2827 Copyright (c) 2005-2007 Kein-Hong Man <khman@users.sf.net>
2828 The COPYRIGHT file describes the conditions
2829 under which this software may be distributed.
2830
2831 See the ChangeLog for more information.
2832
2833----------------------------------------------------------------------]]
2834
2835--[[--------------------------------------------------------------------
2836-- Notes:
2837-- * some unused C code that were not converted are kept as comments
2838-- * LUA_COMPAT_VARARG option changed into a comment block
2839-- * for value/size specific code added, look for 'NOTE: '
2840--
2841-- Not implemented:
2842-- * luaX_newstring not needed by this Lua implementation
2843-- * luaG_checkcode() in assert is not currently implemented
2844--
2845-- Added:
2846-- * some constants added from various header files
2847-- * luaY.LUA_QS used in error_expected, check_match (from luaconf.h)
2848-- * luaY:LUA_QL needed for error messages (from luaconf.h)
2849-- * luaY:growvector (from lmem.h) -- skeleton only, limit checking
2850-- * luaY.SHRT_MAX (from <limits.h>) for registerlocalvar
2851-- * luaY:newproto (from lfunc.c)
2852-- * luaY:int2fb (from lobject.c)
2853-- * NOTE: HASARG_MASK, for implementing a VARARG_HASARG bit operation
2854-- * NOTE: value-specific code for VARARG_NEEDSARG to replace a bitop
2855--
2856-- Changed in 5.1.x:
2857-- * various code changes are not detailed...
2858-- * names of constants may have changed, e.g. added a LUAI_ prefix
2859-- * struct expkind: added VKNUM, VVARARG; VCALL's info changed?
2860-- * struct expdesc: added nval
2861-- * struct FuncState: upvalues data type changed to upvaldesc
2862-- * macro hasmultret is new
2863-- * function checklimit moved to parser from lexer
2864-- * functions anchor_token, errorlimit, checknext are new
2865-- * checknext is new, equivalent to 5.0.x's check, see check too
2866-- * luaY:next and luaY:lookahead moved to lexer
2867-- * break keyword no longer skipped in luaY:breakstat
2868-- * function new_localvarstr replaced by new_localvarliteral
2869-- * registerlocalvar limits local variables to SHRT_MAX
2870-- * create_local deleted, new_localvarliteral used instead
2871-- * constant LUAI_MAXUPVALUES increased to 60
2872-- * constants MAXPARAMS, LUA_MAXPARSERLEVEL, MAXSTACK removed
2873-- * function interface changed: singlevaraux, singlevar
2874-- * enterlevel and leavelevel uses nCcalls to track call depth
2875-- * added a name argument to main entry function, luaY:parser
2876-- * function luaY_index changed to yindex
2877-- * luaY:int2fb()'s table size encoding format has been changed
2878-- * luaY:log2() no longer needed for table constructors
2879-- * function code_params deleted, functionality folded in parlist
2880-- * vararg flags handling (is_vararg) changes; also see VARARG_*
2881-- * LUA_COMPATUPSYNTAX section for old-style upvalues removed
2882-- * repeatstat() calls chunk() instead of block()
2883-- * function interface changed: cond, test_then_block
2884-- * while statement implementation considerably simplified; MAXEXPWHILE
2885-- and EXTRAEXP no longer required, no limits to the complexity of a
2886-- while condition
2887-- * repeat, forbody statement implementation has major changes,
2888-- mostly due to new scoping behaviour of local variables
2889-- * OPR_MULT renamed to OPR_MUL
2890----------------------------------------------------------------------]]
2891
2892--requires luaP, luaX, luaK
2893local luaY = {}
2894local luaX = luaXfunc
2895local luaK = luaKfunc(luaY)
2896local luaP = luaPfunc
2897
2898--[[--------------------------------------------------------------------
2899-- Expression descriptor
2900-- * expkind changed to string constants; luaY:assignment was the only
2901-- function to use a relational operator with this enumeration
2902-- VVOID -- no value
2903-- VNIL -- no value
2904-- VTRUE -- no value
2905-- VFALSE -- no value
2906-- VK -- info = index of constant in 'k'
2907-- VKNUM -- nval = numerical value
2908-- VLOCAL -- info = local register
2909-- VUPVAL, -- info = index of upvalue in 'upvalues'
2910-- VGLOBAL -- info = index of table; aux = index of global name in 'k'
2911-- VINDEXED -- info = table register; aux = index register (or 'k')
2912-- VJMP -- info = instruction pc
2913-- VRELOCABLE -- info = instruction pc
2914-- VNONRELOC -- info = result register
2915-- VCALL -- info = instruction pc
2916-- VVARARG -- info = instruction pc
2917} ----------------------------------------------------------------------]]
2918
2919--[[--------------------------------------------------------------------
2920-- * expdesc in Lua 5.1.x has a union u and another struct s; this Lua
2921-- implementation ignores all instances of u and s usage
2922-- struct expdesc:
2923-- k -- (enum: expkind)
2924-- info, aux -- (int, int)
2925-- nval -- (lua_Number)
2926-- t -- patch list of 'exit when true'
2927-- f -- patch list of 'exit when false'
2928----------------------------------------------------------------------]]
2929
2930--[[--------------------------------------------------------------------
2931-- struct upvaldesc:
2932-- k -- (lu_byte)
2933-- info -- (lu_byte)
2934----------------------------------------------------------------------]]
2935
2936--[[--------------------------------------------------------------------
2937-- state needed to generate code for a given function
2938-- struct FuncState:
2939-- f -- current function header (table: Proto)
2940-- h -- table to find (and reuse) elements in 'k' (table: Table)
2941-- prev -- enclosing function (table: FuncState)
2942-- ls -- lexical state (table: LexState)
2943-- L -- copy of the Lua state (table: lua_State)
2944-- bl -- chain of current blocks (table: BlockCnt)
2945-- pc -- next position to code (equivalent to 'ncode')
2946-- lasttarget -- 'pc' of last 'jump target'
2947-- jpc -- list of pending jumps to 'pc'
2948-- freereg -- first free register
2949-- nk -- number of elements in 'k'
2950-- np -- number of elements in 'p'
2951-- nlocvars -- number of elements in 'locvars'
2952-- nactvar -- number of active local variables
2953-- upvalues[LUAI_MAXUPVALUES] -- upvalues (table: upvaldesc)
2954-- actvar[LUAI_MAXVARS] -- declared-variable stack
2955----------------------------------------------------------------------]]
2956
2957------------------------------------------------------------------------
2958-- constants used by parser
2959-- * picks up duplicate values from luaX if required
2960------------------------------------------------------------------------
2961
2962luaY.LUA_QS = luaX.LUA_QS or "'%s'" -- (from luaconf.h)
2963
2964luaY.SHRT_MAX = 32767 -- (from <limits.h>)
2965luaY.LUAI_MAXVARS = 200 -- (luaconf.h)
2966luaY.LUAI_MAXUPVALUES = 60 -- (luaconf.h)
2967luaY.MAX_INT = luaX.MAX_INT or 2147483645 -- (from llimits.h)
2968 -- * INT_MAX-2 for 32-bit systems
2969luaY.LUAI_MAXCCALLS = 200 -- (from luaconf.h)
2970
2971luaY.VARARG_HASARG = 1 -- (from lobject.h)
2972-- NOTE: HASARG_MASK is value-specific
2973luaY.HASARG_MASK = 2 -- this was added for a bitop in parlist()
2974luaY.VARARG_ISVARARG = 2
2975-- NOTE: there is some value-specific code that involves VARARG_NEEDSARG
2976luaY.VARARG_NEEDSARG = 4
2977
2978luaY.LUA_MULTRET = -1 -- (lua.h)
2979
2980--[[--------------------------------------------------------------------
2981-- other functions
2982----------------------------------------------------------------------]]
2983
2984------------------------------------------------------------------------
2985-- LUA_QL describes how error messages quote program elements.
2986-- CHANGE it if you want a different appearance. (from luaconf.h)
2987------------------------------------------------------------------------
2988function luaY:LUA_QL(x)
2989 return "'"..x.."'"
2990end
2991
2992------------------------------------------------------------------------
2993-- this is a stripped-down luaM_growvector (from lmem.h) which is a
2994-- macro based on luaM_growaux (in lmem.c); all the following does is
2995-- reproduce the size limit checking logic of the original function
2996-- so that error behaviour is identical; all arguments preserved for
2997-- convenience, even those which are unused
2998-- * set the t field to nil, since this originally does a sizeof(t)
2999-- * size (originally a pointer) is never updated, their final values
3000-- are set by luaY:close_func(), so overall things should still work
3001------------------------------------------------------------------------
3002function luaY:growvector(L, v, nelems, size, t, limit, e)
3003 if nelems >= limit then
3004 error(e) -- was luaG_runerror
3005 end
3006end
3007
3008------------------------------------------------------------------------
3009-- initialize a new function prototype structure (from lfunc.c)
3010-- * used only in open_func()
3011------------------------------------------------------------------------
3012function luaY:newproto(L)
3013 local f = {} -- Proto
3014 -- luaC_link(L, obj2gco(f), LUA_TPROTO); /* GC */
3015 f.k = {}
3016 f.sizek = 0
3017 f.p = {}
3018 f.sizep = 0
3019 f.code = {}
3020 f.sizecode = 0
3021 f.sizelineinfo = 0
3022 f.sizeupvalues = 0
3023 f.nups = 0
3024 f.upvalues = {}
3025 f.numparams = 0
3026 f.is_vararg = 0
3027 f.maxstacksize = 0
3028 f.lineinfo = {}
3029 f.sizelocvars = 0
3030 f.locvars = {}
3031 f.lineDefined = 0
3032 f.lastlinedefined = 0
3033 f.source = nil
3034 return f
3035end
3036
3037------------------------------------------------------------------------
3038-- converts an integer to a "floating point byte", represented as
3039-- (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if
3040-- eeeee != 0 and (xxx) otherwise.
3041------------------------------------------------------------------------
3042function luaY:int2fb(x)
3043 local e = 0 -- exponent
3044 while x >= 16 do
3045 x = math.floor((x + 1) / 2)
3046 e = e + 1
3047 end
3048 if x < 8 then
3049 return x
3050 else
3051 return ((e + 1) * 8) + (x - 8)
3052 end
3053end
3054
3055--[[--------------------------------------------------------------------
3056-- parser functions
3057----------------------------------------------------------------------]]
3058
3059------------------------------------------------------------------------
3060-- true of the kind of expression produces multiple return values
3061------------------------------------------------------------------------
3062function luaY:hasmultret(k)
3063 return k == "VCALL" or k == "VVARARG"
3064end
3065
3066------------------------------------------------------------------------
3067-- convenience function to access active local i, returns entry
3068------------------------------------------------------------------------
3069function luaY:getlocvar(fs, i)
3070 return fs.f.locvars[ fs.actvar[i] ]
3071end
3072
3073------------------------------------------------------------------------
3074-- check a limit, string m provided as an error message
3075------------------------------------------------------------------------
3076function luaY:checklimit(fs, v, l, m)
3077 if v > l then self:errorlimit(fs, l, m) end
3078end
3079
3080--[[--------------------------------------------------------------------
3081-- nodes for block list (list of active blocks)
3082-- struct BlockCnt:
3083-- previous -- chain (table: BlockCnt)
3084-- breaklist -- list of jumps out of this loop
3085-- nactvar -- # active local variables outside the breakable structure
3086-- upval -- true if some variable in the block is an upvalue (boolean)
3087-- isbreakable -- true if 'block' is a loop (boolean)
3088----------------------------------------------------------------------]]
3089
3090------------------------------------------------------------------------
3091-- prototypes for recursive non-terminal functions
3092------------------------------------------------------------------------
3093-- prototypes deleted; not required in Lua
3094
3095------------------------------------------------------------------------
3096-- reanchor if last token is has a constant string, see close_func()
3097-- * used only in close_func()
3098------------------------------------------------------------------------
3099function luaY:anchor_token(ls)
3100 if ls.t.token == "TK_NAME" or ls.t.token == "TK_STRING" then
3101 -- not relevant to Lua implementation of parser
3102 -- local ts = ls.t.seminfo
3103 -- luaX_newstring(ls, getstr(ts), ts->tsv.len); /* C */
3104 end
3105end
3106
3107------------------------------------------------------------------------
3108-- throws a syntax error if token expected is not there
3109------------------------------------------------------------------------
3110function luaY:error_expected(ls, token)
3111 luaX:syntaxerror(ls,
3112 string.format(self.LUA_QS.." expected", luaX:token2str(ls, token)))
3113end
3114
3115------------------------------------------------------------------------
3116-- prepares error message for display, for limits exceeded
3117-- * used only in checklimit()
3118------------------------------------------------------------------------
3119function luaY:errorlimit(fs, limit, what)
3120 local msg = (fs.f.linedefined == 0) and
3121 string.format("main function has more than %d %s", limit, what) or
3122 string.format("function at line %d has more than %d %s",
3123 fs.f.linedefined, limit, what)
3124 luaX:lexerror(fs.ls, msg, 0)
3125end
3126
3127------------------------------------------------------------------------
3128-- tests for a token, returns outcome
3129-- * return value changed to boolean
3130------------------------------------------------------------------------
3131function luaY:testnext(ls, c)
3132 if ls.t.token == c then
3133 luaX:next(ls)
3134 return true
3135 else
3136 return false
3137 end
3138end
3139
3140------------------------------------------------------------------------
3141-- check for existence of a token, throws error if not found
3142------------------------------------------------------------------------
3143function luaY:check(ls, c)
3144 if ls.t.token ~= c then
3145 self:error_expected(ls, c)
3146 end
3147end
3148
3149------------------------------------------------------------------------
3150-- verify existence of a token, then skip it
3151------------------------------------------------------------------------
3152function luaY:checknext(ls, c)
3153 self:check(ls, c)
3154 luaX:next(ls)
3155end
3156
3157------------------------------------------------------------------------
3158-- throws error if condition not matched
3159------------------------------------------------------------------------
3160function luaY:check_condition(ls, c, msg)
3161 if not c then luaX:syntaxerror(ls, msg) end
3162end
3163
3164------------------------------------------------------------------------
3165-- verifies token conditions are met or else throw error
3166------------------------------------------------------------------------
3167function luaY:check_match(ls, what, who, where)
3168 if not self:testnext(ls, what) then
3169 if where == ls.linenumber then
3170 self:error_expected(ls, what)
3171 else
3172 luaX:syntaxerror(ls, string.format(
3173 self.LUA_QS.." expected (to close "..self.LUA_QS.." at line %d)",
3174 luaX:token2str(ls, what), luaX:token2str(ls, who), where))
3175 end
3176 end
3177end
3178
3179------------------------------------------------------------------------
3180-- expect that token is a name, return the name
3181------------------------------------------------------------------------
3182function luaY:str_checkname(ls)
3183 self:check(ls, "TK_NAME")
3184 local ts = ls.t.seminfo
3185 luaX:next(ls)
3186 return ts
3187end
3188
3189------------------------------------------------------------------------
3190-- initialize a struct expdesc, expression description data structure
3191------------------------------------------------------------------------
3192function luaY:init_exp(e, k, i)
3193 e.f, e.t = luaK.NO_JUMP, luaK.NO_JUMP
3194 e.k = k
3195 e.info = i
3196end
3197
3198------------------------------------------------------------------------
3199-- adds given string s in string pool, sets e as VK
3200------------------------------------------------------------------------
3201function luaY:codestring(ls, e, s)
3202 self:init_exp(e, "VK", luaK:stringK(ls.fs, s))
3203end
3204
3205------------------------------------------------------------------------
3206-- consume a name token, adds it to string pool, sets e as VK
3207------------------------------------------------------------------------
3208function luaY:checkname(ls, e)
3209 self:codestring(ls, e, self:str_checkname(ls))
3210end
3211
3212------------------------------------------------------------------------
3213-- creates struct entry for a local variable
3214-- * used only in new_localvar()
3215------------------------------------------------------------------------
3216function luaY:registerlocalvar(ls, varname)
3217 local fs = ls.fs
3218 local f = fs.f
3219 self:growvector(ls.L, f.locvars, fs.nlocvars, f.sizelocvars,
3220 nil, self.SHRT_MAX, "too many local variables")
3221 -- loop to initialize empty f.locvar positions not required
3222 f.locvars[fs.nlocvars] = {} -- LocVar
3223 f.locvars[fs.nlocvars].varname = varname
3224 -- luaC_objbarrier(ls.L, f, varname) /* GC */
3225 local nlocvars = fs.nlocvars
3226 fs.nlocvars = fs.nlocvars + 1
3227 return nlocvars
3228end
3229
3230------------------------------------------------------------------------
3231-- creates a new local variable given a name and an offset from nactvar
3232-- * used in fornum(), forlist(), parlist(), body()
3233------------------------------------------------------------------------
3234function luaY:new_localvarliteral(ls, v, n)
3235 self:new_localvar(ls, v, n)
3236end
3237
3238------------------------------------------------------------------------
3239-- register a local variable, set in active variable list
3240------------------------------------------------------------------------
3241function luaY:new_localvar(ls, name, n)
3242 local fs = ls.fs
3243 self:checklimit(fs, fs.nactvar + n + 1, self.LUAI_MAXVARS, "local variables")
3244 fs.actvar[fs.nactvar + n] = self:registerlocalvar(ls, name)
3245end
3246
3247------------------------------------------------------------------------
3248-- adds nvars number of new local variables, set debug information
3249------------------------------------------------------------------------
3250function luaY:adjustlocalvars(ls, nvars)
3251 local fs = ls.fs
3252 fs.nactvar = fs.nactvar + nvars
3253 for i = nvars, 1, -1 do
3254 self:getlocvar(fs, fs.nactvar - i).startpc = fs.pc
3255 end
3256end
3257
3258------------------------------------------------------------------------
3259-- removes a number of locals, set debug information
3260------------------------------------------------------------------------
3261function luaY:removevars(ls, tolevel)
3262 local fs = ls.fs
3263 while fs.nactvar > tolevel do
3264 fs.nactvar = fs.nactvar - 1
3265 self:getlocvar(fs, fs.nactvar).endpc = fs.pc
3266 end
3267end
3268
3269------------------------------------------------------------------------
3270-- returns an existing upvalue index based on the given name, or
3271-- creates a new upvalue struct entry and returns the new index
3272-- * used only in singlevaraux()
3273------------------------------------------------------------------------
3274function luaY:indexupvalue(fs, name, v)
3275 local f = fs.f
3276 for i = 0, f.nups - 1 do
3277 if fs.upvalues[i].k == v.k and fs.upvalues[i].info == v.info then
3278 assert(f.upvalues[i] == name)
3279 return i
3280 end
3281 end
3282 -- new one
3283 self:checklimit(fs, f.nups + 1, self.LUAI_MAXUPVALUES, "upvalues")
3284 self:growvector(fs.L, f.upvalues, f.nups, f.sizeupvalues,
3285 nil, self.MAX_INT, "")
3286 -- loop to initialize empty f.upvalues positions not required
3287 f.upvalues[f.nups] = name
3288 -- luaC_objbarrier(fs->L, f, name); /* GC */
3289 assert(v.k == "VLOCAL" or v.k == "VUPVAL")
3290 -- this is a partial copy; only k & info fields used
3291 fs.upvalues[f.nups] = { k = v.k, info = v.info }
3292 local nups = f.nups
3293 f.nups = f.nups + 1
3294 return nups
3295end
3296
3297------------------------------------------------------------------------
3298-- search the local variable namespace of the given fs for a match
3299-- * used only in singlevaraux()
3300------------------------------------------------------------------------
3301function luaY:searchvar(fs, n)
3302 for i = fs.nactvar - 1, 0, -1 do
3303 if n == self:getlocvar(fs, i).varname then
3304 return i
3305 end
3306 end
3307 return -1 -- not found
3308end
3309
3310------------------------------------------------------------------------
3311-- * mark upvalue flags in function states up to a given level
3312-- * used only in singlevaraux()
3313------------------------------------------------------------------------
3314function luaY:markupval(fs, level)
3315 local bl = fs.bl
3316 while bl and bl.nactvar > level do bl = bl.previous end
3317 if bl then bl.upval = true end
3318end
3319
3320------------------------------------------------------------------------
3321-- handle locals, globals and upvalues and related processing
3322-- * search mechanism is recursive, calls itself to search parents
3323-- * used only in singlevar()
3324------------------------------------------------------------------------
3325function luaY:singlevaraux(fs, n, var, base)
3326 if fs == nil then -- no more levels?
3327 self:init_exp(var, "VGLOBAL", luaP.NO_REG) -- default is global variable
3328 return "VGLOBAL"
3329 else
3330 local v = self:searchvar(fs, n) -- look up at current level
3331 if v >= 0 then
3332 self:init_exp(var, "VLOCAL", v)
3333 if base == 0 then
3334 self:markupval(fs, v) -- local will be used as an upval
3335 end
3336 return "VLOCAL"
3337 else -- not found at current level; try upper one
3338 if self:singlevaraux(fs.prev, n, var, 0) == "VGLOBAL" then
3339 return "VGLOBAL"
3340 end
3341 var.info = self:indexupvalue(fs, n, var) -- else was LOCAL or UPVAL
3342 var.k = "VUPVAL" -- upvalue in this level
3343 return "VUPVAL"
3344 end--if v
3345 end--if fs
3346end
3347
3348------------------------------------------------------------------------
3349-- consume a name token, creates a variable (global|local|upvalue)
3350-- * used in prefixexp(), funcname()
3351------------------------------------------------------------------------
3352function luaY:singlevar(ls, var)
3353 local varname = self:str_checkname(ls)
3354 local fs = ls.fs
3355 if self:singlevaraux(fs, varname, var, 1) == "VGLOBAL" then
3356 var.info = luaK:stringK(fs, varname) -- info points to global name
3357 end
3358end
3359
3360------------------------------------------------------------------------
3361-- adjust RHS to match LHS in an assignment
3362-- * used in assignment(), forlist(), localstat()
3363------------------------------------------------------------------------
3364function luaY:adjust_assign(ls, nvars, nexps, e)
3365 local fs = ls.fs
3366 local extra = nvars - nexps
3367 if self:hasmultret(e.k) then
3368 extra = extra + 1 -- includes call itself
3369 if extra <= 0 then extra = 0 end
3370 luaK:setreturns(fs, e, extra) -- last exp. provides the difference
3371 if extra > 1 then luaK:reserveregs(fs, extra - 1) end
3372 else
3373 if e.k ~= "VVOID" then luaK:exp2nextreg(fs, e) end -- close last expression
3374 if extra > 0 then
3375 local reg = fs.freereg
3376 luaK:reserveregs(fs, extra)
3377 luaK:_nil(fs, reg, extra)
3378 end
3379 end
3380end
3381
3382------------------------------------------------------------------------
3383-- tracks and limits parsing depth, assert check at end of parsing
3384------------------------------------------------------------------------
3385function luaY:enterlevel(ls)
3386 ls.L.nCcalls = ls.L.nCcalls + 1
3387 if ls.L.nCcalls > self.LUAI_MAXCCALLS then
3388 luaX:lexerror(ls, "chunk has too many syntax levels", 0)
3389 end
3390end
3391
3392------------------------------------------------------------------------
3393-- tracks parsing depth, a pair with luaY:enterlevel()
3394------------------------------------------------------------------------
3395function luaY:leavelevel(ls)
3396 ls.L.nCcalls = ls.L.nCcalls - 1
3397end
3398
3399------------------------------------------------------------------------
3400-- enters a code unit, initializes elements
3401------------------------------------------------------------------------
3402function luaY:enterblock(fs, bl, isbreakable)
3403 bl.breaklist = luaK.NO_JUMP
3404 bl.isbreakable = isbreakable
3405 bl.nactvar = fs.nactvar
3406 bl.upval = false
3407 bl.previous = fs.bl
3408 fs.bl = bl
3409 assert(fs.freereg == fs.nactvar)
3410end
3411
3412------------------------------------------------------------------------
3413-- leaves a code unit, close any upvalues
3414------------------------------------------------------------------------
3415function luaY:leaveblock(fs)
3416 local bl = fs.bl
3417 fs.bl = bl.previous
3418 self:removevars(fs.ls, bl.nactvar)
3419 if bl.upval then
3420 luaK:codeABC(fs, "OP_CLOSE", bl.nactvar, 0, 0)
3421 end
3422 -- a block either controls scope or breaks (never both)
3423 assert(not bl.isbreakable or not bl.upval)
3424 assert(bl.nactvar == fs.nactvar)
3425 fs.freereg = fs.nactvar -- free registers
3426 luaK:patchtohere(fs, bl.breaklist)
3427end
3428
3429------------------------------------------------------------------------
3430-- implement the instantiation of a function prototype, append list of
3431-- upvalues after the instantiation instruction
3432-- * used only in body()
3433------------------------------------------------------------------------
3434function luaY:pushclosure(ls, func, v)
3435 local fs = ls.fs
3436 local f = fs.f
3437 self:growvector(ls.L, f.p, fs.np, f.sizep, nil,
3438 luaP.MAXARG_Bx, "constant table overflow")
3439 -- loop to initialize empty f.p positions not required
3440 f.p[fs.np] = func.f
3441 fs.np = fs.np + 1
3442 -- luaC_objbarrier(ls->L, f, func->f); /* C */
3443 self:init_exp(v, "VRELOCABLE", luaK:codeABx(fs, "OP_CLOSURE", 0, fs.np - 1))
3444 for i = 0, func.f.nups - 1 do
3445 local o = (func.upvalues[i].k == "VLOCAL") and "OP_MOVE" or "OP_GETUPVAL"
3446 luaK:codeABC(fs, o, 0, func.upvalues[i].info, 0)
3447 end
3448end
3449
3450------------------------------------------------------------------------
3451-- opening of a function
3452------------------------------------------------------------------------
3453function luaY:open_func(ls, fs)
3454 local L = ls.L
3455 local f = self:newproto(ls.L)
3456 fs.f = f
3457 fs.prev = ls.fs -- linked list of funcstates
3458 fs.ls = ls
3459 fs.L = L
3460 ls.fs = fs
3461 fs.pc = 0
3462 fs.lasttarget = -1
3463 fs.jpc = luaK.NO_JUMP
3464 fs.freereg = 0
3465 fs.nk = 0
3466 fs.np = 0
3467 fs.nlocvars = 0
3468 fs.nactvar = 0
3469 fs.bl = nil
3470 f.source = ls.source
3471 f.maxstacksize = 2 -- registers 0/1 are always valid
3472 fs.h = {} -- constant table; was luaH_new call
3473 -- anchor table of constants and prototype (to avoid being collected)
3474 -- sethvalue2s(L, L->top, fs->h); incr_top(L); /* C */
3475 -- setptvalue2s(L, L->top, f); incr_top(L);
3476end
3477
3478------------------------------------------------------------------------
3479-- closing of a function
3480------------------------------------------------------------------------
3481function luaY:close_func(ls)
3482 local L = ls.L
3483 local fs = ls.fs
3484 local f = fs.f
3485 self:removevars(ls, 0)
3486 luaK:ret(fs, 0, 0) -- final return
3487 -- luaM_reallocvector deleted for f->code, f->lineinfo, f->k, f->p,
3488 -- f->locvars, f->upvalues; not required for Lua table arrays
3489 f.sizecode = fs.pc
3490 f.sizelineinfo = fs.pc
3491 f.sizek = fs.nk
3492 f.sizep = fs.np
3493 f.sizelocvars = fs.nlocvars
3494 f.sizeupvalues = f.nups
3495 --assert(luaG_checkcode(f)) -- currently not implemented
3496 assert(fs.bl == nil)
3497 ls.fs = fs.prev
3498 -- the following is not required for this implementation; kept here
3499 -- for completeness
3500 -- L->top -= 2; /* remove table and prototype from the stack */
3501 -- last token read was anchored in defunct function; must reanchor it
3502 if fs then self:anchor_token(ls) end
3503end
3504
3505------------------------------------------------------------------------
3506-- parser initialization function
3507-- * note additional sub-tables needed for LexState, FuncState
3508------------------------------------------------------------------------
3509function luaY:parser(L, z, buff, name)
3510 local lexstate = {} -- LexState
3511 lexstate.t = {}
3512 lexstate.lookahead = {}
3513 local funcstate = {} -- FuncState
3514 funcstate.upvalues = {}
3515 funcstate.actvar = {}
3516 -- the following nCcalls initialization added for convenience
3517 L.nCcalls = 0
3518 lexstate.buff = buff
3519 luaX:setinput(L, lexstate, z, name)
3520 self:open_func(lexstate, funcstate)
3521 funcstate.f.is_vararg = self.VARARG_ISVARARG -- main func. is always vararg
3522 luaX:next(lexstate) -- read first token
3523 self:chunk(lexstate)
3524 self:check(lexstate, "TK_EOS")
3525 self:close_func(lexstate)
3526 assert(funcstate.prev == nil)
3527 assert(funcstate.f.nups == 0)
3528 assert(lexstate.fs == nil)
3529 return funcstate.f
3530end
3531
3532--[[--------------------------------------------------------------------
3533-- GRAMMAR RULES
3534----------------------------------------------------------------------]]
3535
3536------------------------------------------------------------------------
3537-- parse a function name suffix, for function call specifications
3538-- * used in primaryexp(), funcname()
3539------------------------------------------------------------------------
3540function luaY:field(ls, v)
3541 -- field -> ['.' | ':'] NAME
3542 local fs = ls.fs
3543 local key = {} -- expdesc
3544 luaK:exp2anyreg(fs, v)
3545 luaX:next(ls) -- skip the dot or colon
3546 self:checkname(ls, key)
3547 luaK:indexed(fs, v, key)
3548end
3549
3550------------------------------------------------------------------------
3551-- parse a table indexing suffix, for constructors, expressions
3552-- * used in recfield(), primaryexp()
3553------------------------------------------------------------------------
3554function luaY:yindex(ls, v)
3555 -- index -> '[' expr ']'
3556 luaX:next(ls) -- skip the '['
3557 self:expr(ls, v)
3558 luaK:exp2val(ls.fs, v)
3559 self:checknext(ls, "]")
3560end
3561
3562--[[--------------------------------------------------------------------
3563-- Rules for Constructors
3564----------------------------------------------------------------------]]
3565
3566--[[--------------------------------------------------------------------
3567-- struct ConsControl:
3568-- v -- last list item read (table: struct expdesc)
3569-- t -- table descriptor (table: struct expdesc)
3570-- nh -- total number of 'record' elements
3571-- na -- total number of array elements
3572-- tostore -- number of array elements pending to be stored
3573----------------------------------------------------------------------]]
3574
3575------------------------------------------------------------------------
3576-- parse a table record (hash) field
3577-- * used in constructor()
3578------------------------------------------------------------------------
3579function luaY:recfield(ls, cc)
3580 -- recfield -> (NAME | '['exp1']') = exp1
3581 local fs = ls.fs
3582 local reg = ls.fs.freereg
3583 local key, val = {}, {} -- expdesc
3584 if ls.t.token == "TK_NAME" then
3585 self:checklimit(fs, cc.nh, self.MAX_INT, "items in a constructor")
3586 self:checkname(ls, key)
3587 else -- ls->t.token == '['
3588 self:yindex(ls, key)
3589 end
3590 cc.nh = cc.nh + 1
3591 self:checknext(ls, "=")
3592 local rkkey = luaK:exp2RK(fs, key)
3593 self:expr(ls, val)
3594 luaK:codeABC(fs, "OP_SETTABLE", cc.t.info, rkkey, luaK:exp2RK(fs, val))
3595 fs.freereg = reg -- free registers
3596end
3597
3598------------------------------------------------------------------------
3599-- emit a set list instruction if enough elements (LFIELDS_PER_FLUSH)
3600-- * used in constructor()
3601------------------------------------------------------------------------
3602function luaY:closelistfield(fs, cc)
3603 if cc.v.k == "VVOID" then return end -- there is no list item
3604 luaK:exp2nextreg(fs, cc.v)
3605 cc.v.k = "VVOID"
3606 if cc.tostore == luaP.LFIELDS_PER_FLUSH then
3607 luaK:setlist(fs, cc.t.info, cc.na, cc.tostore) -- flush
3608 cc.tostore = 0 -- no more items pending
3609 end
3610end
3611
3612------------------------------------------------------------------------
3613-- emit a set list instruction at the end of parsing list constructor
3614-- * used in constructor()
3615------------------------------------------------------------------------
3616function luaY:lastlistfield(fs, cc)
3617 if cc.tostore == 0 then return end
3618 if self:hasmultret(cc.v.k) then
3619 luaK:setmultret(fs, cc.v)
3620 luaK:setlist(fs, cc.t.info, cc.na, self.LUA_MULTRET)
3621 cc.na = cc.na - 1 -- do not count last expression (unknown number of elements)
3622 else
3623 if cc.v.k ~= "VVOID" then
3624 luaK:exp2nextreg(fs, cc.v)
3625 end
3626 luaK:setlist(fs, cc.t.info, cc.na, cc.tostore)
3627 end
3628end
3629
3630------------------------------------------------------------------------
3631-- parse a table list (array) field
3632-- * used in constructor()
3633------------------------------------------------------------------------
3634function luaY:listfield(ls, cc)
3635 self:expr(ls, cc.v)
3636 self:checklimit(ls.fs, cc.na, self.MAX_INT, "items in a constructor")
3637 cc.na = cc.na + 1
3638 cc.tostore = cc.tostore + 1
3639end
3640
3641------------------------------------------------------------------------
3642-- parse a table constructor
3643-- * used in funcargs(), simpleexp()
3644------------------------------------------------------------------------
3645function luaY:constructor(ls, t)
3646 -- constructor -> '{' [ field { fieldsep field } [ fieldsep ] ] '}'
3647 -- field -> recfield | listfield
3648 -- fieldsep -> ',' | ';'
3649 local fs = ls.fs
3650 local line = ls.linenumber
3651 local pc = luaK:codeABC(fs, "OP_NEWTABLE", 0, 0, 0)
3652 local cc = {} -- ConsControl
3653 cc.v = {}
3654 cc.na, cc.nh, cc.tostore = 0, 0, 0
3655 cc.t = t
3656 self:init_exp(t, "VRELOCABLE", pc)
3657 self:init_exp(cc.v, "VVOID", 0) -- no value (yet)
3658 luaK:exp2nextreg(ls.fs, t) -- fix it at stack top (for gc)
3659 self:checknext(ls, "{")
3660 repeat
3661 assert(cc.v.k == "VVOID" or cc.tostore > 0)
3662 if ls.t.token == "}" then break end
3663 self:closelistfield(fs, cc)
3664 local c = ls.t.token
3665
3666 if c == "TK_NAME" then -- may be listfields or recfields
3667 luaX:lookahead(ls)
3668 if ls.lookahead.token ~= "=" then -- expression?
3669 self:listfield(ls, cc)
3670 else
3671 self:recfield(ls, cc)
3672 end
3673 elseif c == "[" then -- constructor_item -> recfield
3674 self:recfield(ls, cc)
3675 else -- constructor_part -> listfield
3676 self:listfield(ls, cc)
3677 end
3678 until not self:testnext(ls, ",") and not self:testnext(ls, ";")
3679 self:check_match(ls, "}", "{", line)
3680 self:lastlistfield(fs, cc)
3681 luaP:SETARG_B(fs.f.code[pc], self:int2fb(cc.na)) -- set initial array size
3682 luaP:SETARG_C(fs.f.code[pc], self:int2fb(cc.nh)) -- set initial table size
3683end
3684
3685-- }======================================================================
3686
3687------------------------------------------------------------------------
3688-- parse the arguments (parameters) of a function declaration
3689-- * used in body()
3690------------------------------------------------------------------------
3691function luaY:parlist(ls)
3692 -- parlist -> [ param { ',' param } ]
3693 local fs = ls.fs
3694 local f = fs.f
3695 local nparams = 0
3696 f.is_vararg = 0
3697 if ls.t.token ~= ")" then -- is 'parlist' not empty?
3698 repeat
3699 local c = ls.t.token
3700 if c == "TK_NAME" then -- param -> NAME
3701 self:new_localvar(ls, self:str_checkname(ls), nparams)
3702 nparams = nparams + 1
3703 elseif c == "TK_DOTS" then -- param -> `...'
3704 luaX:next(ls)
3705-- [[
3706-- #if defined(LUA_COMPAT_VARARG)
3707 -- use `arg' as default name
3708 self:new_localvarliteral(ls, "arg", nparams)
3709 nparams = nparams + 1
3710 f.is_vararg = self.VARARG_HASARG + self.VARARG_NEEDSARG
3711-- #endif
3712--]]
3713 f.is_vararg = f.is_vararg + self.VARARG_ISVARARG
3714 else
3715 luaX:syntaxerror(ls, "<name> or "..self:LUA_QL("...").." expected")
3716 end
3717 until f.is_vararg ~= 0 or not self:testnext(ls, ",")
3718 end--if
3719 self:adjustlocalvars(ls, nparams)
3720 -- NOTE: the following works only when HASARG_MASK is 2!
3721 f.numparams = fs.nactvar - (f.is_vararg % self.HASARG_MASK)
3722 luaK:reserveregs(fs, fs.nactvar) -- reserve register for parameters
3723end
3724
3725------------------------------------------------------------------------
3726-- parse function declaration body
3727-- * used in simpleexp(), localfunc(), funcstat()
3728------------------------------------------------------------------------
3729function luaY:body(ls, e, needself, line)
3730 -- body -> '(' parlist ')' chunk END
3731 local new_fs = {} -- FuncState
3732 new_fs.upvalues = {}
3733 new_fs.actvar = {}
3734 self:open_func(ls, new_fs)
3735 new_fs.f.lineDefined = line
3736 self:checknext(ls, "(")
3737 if needself then
3738 self:new_localvarliteral(ls, "self", 0)
3739 self:adjustlocalvars(ls, 1)
3740 end
3741 self:parlist(ls)
3742 self:checknext(ls, ")")
3743 self:chunk(ls)
3744 new_fs.f.lastlinedefined = ls.linenumber
3745 self:check_match(ls, "TK_END", "TK_FUNCTION", line)
3746 self:close_func(ls)
3747 self:pushclosure(ls, new_fs, e)
3748end
3749
3750------------------------------------------------------------------------
3751-- parse a list of comma-separated expressions
3752-- * used is multiple locations
3753------------------------------------------------------------------------
3754function luaY:explist1(ls, v)
3755 -- explist1 -> expr { ',' expr }
3756 local n = 1 -- at least one expression
3757 self:expr(ls, v)
3758 while self:testnext(ls, ",") do
3759 luaK:exp2nextreg(ls.fs, v)
3760 self:expr(ls, v)
3761 n = n + 1
3762 end
3763 return n
3764end
3765
3766------------------------------------------------------------------------
3767-- parse the parameters of a function call
3768-- * contrast with parlist(), used in function declarations
3769-- * used in primaryexp()
3770------------------------------------------------------------------------
3771function luaY:funcargs(ls, f)
3772 local fs = ls.fs
3773 local args = {} -- expdesc
3774 local nparams
3775 local line = ls.linenumber
3776 local c = ls.t.token
3777 if c == "(" then -- funcargs -> '(' [ explist1 ] ')'
3778 if line ~= ls.lastline then
3779 luaX:syntaxerror(ls, "ambiguous syntax (function call x new statement)")
3780 end
3781 luaX:next(ls)
3782 if ls.t.token == ")" then -- arg list is empty?
3783 args.k = "VVOID"
3784 else
3785 self:explist1(ls, args)
3786 luaK:setmultret(fs, args)
3787 end
3788 self:check_match(ls, ")", "(", line)
3789 elseif c == "{" then -- funcargs -> constructor
3790 self:constructor(ls, args)
3791 elseif c == "TK_STRING" then -- funcargs -> STRING
3792 self:codestring(ls, args, ls.t.seminfo)
3793 luaX:next(ls) -- must use 'seminfo' before 'next'
3794 else
3795 luaX:syntaxerror(ls, "function arguments expected")
3796 return
3797 end
3798 assert(f.k == "VNONRELOC")
3799 local base = f.info -- base register for call
3800 if self:hasmultret(args.k) then
3801 nparams = self.LUA_MULTRET -- open call
3802 else
3803 if args.k ~= "VVOID" then
3804 luaK:exp2nextreg(fs, args) -- close last argument
3805 end
3806 nparams = fs.freereg - (base + 1)
3807 end
3808 self:init_exp(f, "VCALL", luaK:codeABC(fs, "OP_CALL", base, nparams + 1, 2))
3809 luaK:fixline(fs, line)
3810 fs.freereg = base + 1 -- call remove function and arguments and leaves
3811 -- (unless changed) one result
3812end
3813
3814--[[--------------------------------------------------------------------
3815-- Expression parsing
3816----------------------------------------------------------------------]]
3817
3818------------------------------------------------------------------------
3819-- parses an expression in parentheses or a single variable
3820-- * used in primaryexp()
3821------------------------------------------------------------------------
3822function luaY:prefixexp(ls, v)
3823 -- prefixexp -> NAME | '(' expr ')'
3824 local c = ls.t.token
3825 if c == "(" then
3826 local line = ls.linenumber
3827 luaX:next(ls)
3828 self:expr(ls, v)
3829 self:check_match(ls, ")", "(", line)
3830 luaK:dischargevars(ls.fs, v)
3831 elseif c == "TK_NAME" then
3832 self:singlevar(ls, v)
3833 else
3834 luaX:syntaxerror(ls, "unexpected symbol")
3835 end--if c
3836 return
3837end
3838
3839------------------------------------------------------------------------
3840-- parses a prefixexp (an expression in parentheses or a single variable)
3841-- or a function call specification
3842-- * used in simpleexp(), assignment(), exprstat()
3843------------------------------------------------------------------------
3844function luaY:primaryexp(ls, v)
3845 -- primaryexp ->
3846 -- prefixexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs }
3847 local fs = ls.fs
3848 self:prefixexp(ls, v)
3849 while true do
3850 local c = ls.t.token
3851 if c == "." then -- field
3852 self:field(ls, v)
3853 elseif c == "[" then -- '[' exp1 ']'
3854 local key = {} -- expdesc
3855 luaK:exp2anyreg(fs, v)
3856 self:yindex(ls, key)
3857 luaK:indexed(fs, v, key)
3858 elseif c == ":" then -- ':' NAME funcargs
3859 local key = {} -- expdesc
3860 luaX:next(ls)
3861 self:checkname(ls, key)
3862 luaK:_self(fs, v, key)
3863 self:funcargs(ls, v)
3864 elseif c == "(" or c == "TK_STRING" or c == "{" then -- funcargs
3865 luaK:exp2nextreg(fs, v)
3866 self:funcargs(ls, v)
3867 else
3868 return
3869 end--if c
3870 end--while
3871end
3872
3873------------------------------------------------------------------------
3874-- parses general expression types, constants handled here
3875-- * used in subexpr()
3876------------------------------------------------------------------------
3877function luaY:simpleexp(ls, v)
3878 -- simpleexp -> NUMBER | STRING | NIL | TRUE | FALSE | ... |
3879 -- constructor | FUNCTION body | primaryexp
3880 local c = ls.t.token
3881 if c == "TK_NUMBER" then
3882 self:init_exp(v, "VKNUM", 0)
3883 v.nval = ls.t.seminfo
3884 elseif c == "TK_STRING" then
3885 self:codestring(ls, v, ls.t.seminfo)
3886 elseif c == "TK_NIL" then
3887 self:init_exp(v, "VNIL", 0)
3888 elseif c == "TK_TRUE" then
3889 self:init_exp(v, "VTRUE", 0)
3890 elseif c == "TK_FALSE" then
3891 self:init_exp(v, "VFALSE", 0)
3892 elseif c == "TK_DOTS" then -- vararg
3893 local fs = ls.fs
3894 self:check_condition(ls, fs.f.is_vararg ~= 0,
3895 "cannot use "..self:LUA_QL("...").." outside a vararg function");
3896 -- NOTE: the following substitutes for a bitop, but is value-specific
3897 local is_vararg = fs.f.is_vararg
3898 if is_vararg >= self.VARARG_NEEDSARG then
3899 fs.f.is_vararg = is_vararg - self.VARARG_NEEDSARG -- don't need 'arg'
3900 end
3901 self:init_exp(v, "VVARARG", luaK:codeABC(fs, "OP_VARARG", 0, 1, 0))
3902 elseif c == "{" then -- constructor
3903 self:constructor(ls, v)
3904 return
3905 elseif c == "TK_FUNCTION" then
3906 luaX:next(ls)
3907 self:body(ls, v, false, ls.linenumber)
3908 return
3909 else
3910 self:primaryexp(ls, v)
3911 return
3912 end--if c
3913 luaX:next(ls)
3914end
3915
3916------------------------------------------------------------------------
3917-- Translates unary operators tokens if found, otherwise returns
3918-- OPR_NOUNOPR. getunopr() and getbinopr() are used in subexpr().
3919-- * used in subexpr()
3920------------------------------------------------------------------------
3921function luaY:getunopr(op)
3922 if op == "TK_NOT" then
3923 return "OPR_NOT"
3924 elseif op == "-" then
3925 return "OPR_MINUS"
3926 elseif op == "#" then
3927 return "OPR_LEN"
3928 else
3929 return "OPR_NOUNOPR"
3930 end
3931end
3932
3933------------------------------------------------------------------------
3934-- Translates binary operator tokens if found, otherwise returns
3935-- OPR_NOBINOPR. Code generation uses OPR_* style tokens.
3936-- * used in subexpr()
3937------------------------------------------------------------------------
3938luaY.getbinopr_table = {
3939 ["+"] = "OPR_ADD",
3940 ["-"] = "OPR_SUB",
3941 ["*"] = "OPR_MUL",
3942 ["/"] = "OPR_DIV",
3943 ["%"] = "OPR_MOD",
3944 ["^"] = "OPR_POW",
3945 ["TK_CONCAT"] = "OPR_CONCAT",
3946 ["TK_NE"] = "OPR_NE",
3947 ["TK_EQ"] = "OPR_EQ",
3948 ["<"] = "OPR_LT",
3949 ["TK_LE"] = "OPR_LE",
3950 [">"] = "OPR_GT",
3951 ["TK_GE"] = "OPR_GE",
3952 ["TK_AND"] = "OPR_AND",
3953 ["TK_OR"] = "OPR_OR",
3954}
3955function luaY:getbinopr(op)
3956 local opr = self.getbinopr_table[op]
3957 if opr then return opr else return "OPR_NOBINOPR" end
3958end
3959
3960------------------------------------------------------------------------
3961-- the following priority table consists of pairs of left/right values
3962-- for binary operators (was a static const struct); grep for ORDER OPR
3963-- * the following struct is replaced:
3964-- static const struct {
3965-- lu_byte left; /* left priority for each binary operator */
3966-- lu_byte right; /* right priority */
3967-- } priority[] = { /* ORDER OPR */
3968------------------------------------------------------------------------
3969luaY.priority = {
3970 {6, 6}, {6, 6}, {7, 7}, {7, 7}, {7, 7}, -- `+' `-' `/' `%'
3971 {10, 9}, {5, 4}, -- power and concat (right associative)
3972 {3, 3}, {3, 3}, -- equality
3973 {3, 3}, {3, 3}, {3, 3}, {3, 3}, -- order
3974 {2, 2}, {1, 1} -- logical (and/or)
3975}
3976
3977luaY.UNARY_PRIORITY = 8 -- priority for unary operators
3978
3979------------------------------------------------------------------------
3980-- Parse subexpressions. Includes handling of unary operators and binary
3981-- operators. A subexpr is given the rhs priority level of the operator
3982-- immediately left of it, if any (limit is -1 if none,) and if a binop
3983-- is found, limit is compared with the lhs priority level of the binop
3984-- in order to determine which executes first.
3985------------------------------------------------------------------------
3986
3987------------------------------------------------------------------------
3988-- subexpr -> (simpleexp | unop subexpr) { binop subexpr }
3989-- where 'binop' is any binary operator with a priority higher than 'limit'
3990-- * for priority lookups with self.priority[], 1=left and 2=right
3991-- * recursively called
3992-- * used in expr()
3993------------------------------------------------------------------------
3994function luaY:subexpr(ls, v, limit)
3995 self:enterlevel(ls)
3996 local uop = self:getunopr(ls.t.token)
3997 if uop ~= "OPR_NOUNOPR" then
3998 luaX:next(ls)
3999 self:subexpr(ls, v, self.UNARY_PRIORITY)
4000 luaK:prefix(ls.fs, uop, v)
4001 else
4002 self:simpleexp(ls, v)
4003 end
4004 -- expand while operators have priorities higher than 'limit'
4005 local op = self:getbinopr(ls.t.token)
4006 while op ~= "OPR_NOBINOPR" and self.priority[luaK.BinOpr[op] + 1][1] > limit do
4007 local v2 = {} -- expdesc
4008 luaX:next(ls)
4009 luaK:infix(ls.fs, op, v)
4010 -- read sub-expression with higher priority
4011 local nextop = self:subexpr(ls, v2, self.priority[luaK.BinOpr[op] + 1][2])
4012 luaK:posfix(ls.fs, op, v, v2)
4013 op = nextop
4014 end
4015 self:leavelevel(ls)
4016 return op -- return first untreated operator
4017end
4018
4019------------------------------------------------------------------------
4020-- Expression parsing starts here. Function subexpr is entered with the
4021-- left operator (which is non-existent) priority of -1, which is lower
4022-- than all actual operators. Expr information is returned in parm v.
4023-- * used in multiple locations
4024------------------------------------------------------------------------
4025function luaY:expr(ls, v)
4026 self:subexpr(ls, v, 0)
4027end
4028
4029-- }====================================================================
4030
4031--[[--------------------------------------------------------------------
4032-- Rules for Statements
4033----------------------------------------------------------------------]]
4034
4035------------------------------------------------------------------------
4036-- checks next token, used as a look-ahead
4037-- * returns boolean instead of 0|1
4038-- * used in retstat(), chunk()
4039------------------------------------------------------------------------
4040function luaY:block_follow(token)
4041 if token == "TK_ELSE" or token == "TK_ELSEIF" or token == "TK_END"
4042 or token == "TK_UNTIL" or token == "TK_EOS" then
4043 return true
4044 else
4045 return false
4046 end
4047end
4048
4049------------------------------------------------------------------------
4050-- parse a code block or unit
4051-- * used in multiple functions
4052------------------------------------------------------------------------
4053function luaY:block(ls)
4054 -- block -> chunk
4055 local fs = ls.fs
4056 local bl = {} -- BlockCnt
4057 self:enterblock(fs, bl, false)
4058 self:chunk(ls)
4059 assert(bl.breaklist == luaK.NO_JUMP)
4060 self:leaveblock(fs)
4061end
4062
4063------------------------------------------------------------------------
4064-- structure to chain all variables in the left-hand side of an
4065-- assignment
4066-- struct LHS_assign:
4067-- prev -- (table: struct LHS_assign)
4068-- v -- variable (global, local, upvalue, or indexed) (table: expdesc)
4069------------------------------------------------------------------------
4070
4071------------------------------------------------------------------------
4072-- check whether, in an assignment to a local variable, the local variable
4073-- is needed in a previous assignment (to a table). If so, save original
4074-- local value in a safe place and use this safe copy in the previous
4075-- assignment.
4076-- * used in assignment()
4077------------------------------------------------------------------------
4078function luaY:check_conflict(ls, lh, v)
4079 local fs = ls.fs
4080 local extra = fs.freereg -- eventual position to save local variable
4081 local conflict = false
4082 while lh do
4083 if lh.v.k == "VINDEXED" then
4084 if lh.v.info == v.info then -- conflict?
4085 conflict = true
4086 lh.v.info = extra -- previous assignment will use safe copy
4087 end
4088 if lh.v.aux == v.info then -- conflict?
4089 conflict = true
4090 lh.v.aux = extra -- previous assignment will use safe copy
4091 end
4092 end
4093 lh = lh.prev
4094 end
4095 if conflict then
4096 luaK:codeABC(fs, "OP_MOVE", fs.freereg, v.info, 0) -- make copy
4097 luaK:reserveregs(fs, 1)
4098 end
4099end
4100
4101------------------------------------------------------------------------
4102-- parse a variable assignment sequence
4103-- * recursively called
4104-- * used in exprstat()
4105------------------------------------------------------------------------
4106function luaY:assignment(ls, lh, nvars)
4107 local e = {} -- expdesc
4108 -- test was: VLOCAL <= lh->v.k && lh->v.k <= VINDEXED
4109 local c = lh.v.k
4110 self:check_condition(ls, c == "VLOCAL" or c == "VUPVAL" or c == "VGLOBAL"
4111 or c == "VINDEXED", "syntax error")
4112 if self:testnext(ls, ",") then -- assignment -> ',' primaryexp assignment
4113 local nv = {} -- LHS_assign
4114 nv.v = {}
4115 nv.prev = lh
4116 self:primaryexp(ls, nv.v)
4117 if nv.v.k == "VLOCAL" then
4118 self:check_conflict(ls, lh, nv.v)
4119 end
4120 self:checklimit(ls.fs, nvars, self.LUAI_MAXCCALLS - ls.L.nCcalls,
4121 "variables in assignment")
4122 self:assignment(ls, nv, nvars + 1)
4123 else -- assignment -> '=' explist1
4124 self:checknext(ls, "=")
4125 local nexps = self:explist1(ls, e)
4126 if nexps ~= nvars then
4127 self:adjust_assign(ls, nvars, nexps, e)
4128 if nexps > nvars then
4129 ls.fs.freereg = ls.fs.freereg - (nexps - nvars) -- remove extra values
4130 end
4131 else
4132 luaK:setoneret(ls.fs, e) -- close last expression
4133 luaK:storevar(ls.fs, lh.v, e)
4134 return -- avoid default
4135 end
4136 end
4137 self:init_exp(e, "VNONRELOC", ls.fs.freereg - 1) -- default assignment
4138 luaK:storevar(ls.fs, lh.v, e)
4139end
4140
4141------------------------------------------------------------------------
4142-- parse condition in a repeat statement or an if control structure
4143-- * used in repeatstat(), test_then_block()
4144------------------------------------------------------------------------
4145function luaY:cond(ls)
4146 -- cond -> exp
4147 local v = {} -- expdesc
4148 self:expr(ls, v) -- read condition
4149 if v.k == "VNIL" then v.k = "VFALSE" end -- 'falses' are all equal here
4150 luaK:goiftrue(ls.fs, v)
4151 return v.f
4152end
4153
4154------------------------------------------------------------------------
4155-- parse a break statement
4156-- * used in statements()
4157------------------------------------------------------------------------
4158function luaY:breakstat(ls)
4159 -- stat -> BREAK
4160 local fs = ls.fs
4161 local bl = fs.bl
4162 local upval = false
4163 while bl and not bl.isbreakable do
4164 if bl.upval then upval = true end
4165 bl = bl.previous
4166 end
4167 if not bl then
4168 luaX:syntaxerror(ls, "no loop to break")
4169 end
4170 if upval then
4171 luaK:codeABC(fs, "OP_CLOSE", bl.nactvar, 0, 0)
4172 end
4173 bl.breaklist = luaK:concat(fs, bl.breaklist, luaK:jump(fs))
4174end
4175
4176------------------------------------------------------------------------
4177-- parse a while-do control structure, body processed by block()
4178-- * with dynamic array sizes, MAXEXPWHILE + EXTRAEXP limits imposed by
4179-- the function's implementation can be removed
4180-- * used in statements()
4181------------------------------------------------------------------------
4182function luaY:whilestat(ls, line)
4183 -- whilestat -> WHILE cond DO block END
4184 local fs = ls.fs
4185 local bl = {} -- BlockCnt
4186 luaX:next(ls) -- skip WHILE
4187 local whileinit = luaK:getlabel(fs)
4188 local condexit = self:cond(ls)
4189 self:enterblock(fs, bl, true)
4190 self:checknext(ls, "TK_DO")
4191 self:block(ls)
4192 luaK:patchlist(fs, luaK:jump(fs), whileinit)
4193 self:check_match(ls, "TK_END", "TK_WHILE", line)
4194 self:leaveblock(fs)
4195 luaK:patchtohere(fs, condexit) -- false conditions finish the loop
4196end
4197
4198------------------------------------------------------------------------
4199-- parse a repeat-until control structure, body parsed by chunk()
4200-- * used in statements()
4201------------------------------------------------------------------------
4202function luaY:repeatstat(ls, line)
4203 -- repeatstat -> REPEAT block UNTIL cond
4204 local fs = ls.fs
4205 local repeat_init = luaK:getlabel(fs)
4206 local bl1, bl2 = {}, {} -- BlockCnt
4207 self:enterblock(fs, bl1, true) -- loop block
4208 self:enterblock(fs, bl2, false) -- scope block
4209 luaX:next(ls) -- skip REPEAT
4210 self:chunk(ls)
4211 self:check_match(ls, "TK_UNTIL", "TK_REPEAT", line)
4212 local condexit = self:cond(ls) -- read condition (inside scope block)
4213 if not bl2.upval then -- no upvalues?
4214 self:leaveblock(fs) -- finish scope
4215 luaK:patchlist(ls.fs, condexit, repeat_init) -- close the loop
4216 else -- complete semantics when there are upvalues
4217 self:breakstat(ls) -- if condition then break
4218 luaK:patchtohere(ls.fs, condexit) -- else...
4219 self:leaveblock(fs) -- finish scope...
4220 luaK:patchlist(ls.fs, luaK:jump(fs), repeat_init) -- and repeat
4221 end
4222 self:leaveblock(fs) -- finish loop
4223end
4224
4225------------------------------------------------------------------------
4226-- parse the single expressions needed in numerical for loops
4227-- * used in fornum()
4228------------------------------------------------------------------------
4229function luaY:exp1(ls)
4230 local e = {} -- expdesc
4231 self:expr(ls, e)
4232 local k = e.k
4233 luaK:exp2nextreg(ls.fs, e)
4234 return k
4235end
4236
4237------------------------------------------------------------------------
4238-- parse a for loop body for both versions of the for loop
4239-- * used in fornum(), forlist()
4240------------------------------------------------------------------------
4241function luaY:forbody(ls, base, line, nvars, isnum)
4242 -- forbody -> DO block
4243 local bl = {} -- BlockCnt
4244 local fs = ls.fs
4245 self:adjustlocalvars(ls, 3) -- control variables
4246 self:checknext(ls, "TK_DO")
4247 local prep = isnum and luaK:codeAsBx(fs, "OP_FORPREP", base, luaK.NO_JUMP)
4248 or luaK:jump(fs)
4249 self:enterblock(fs, bl, false) -- scope for declared variables
4250 self:adjustlocalvars(ls, nvars)
4251 luaK:reserveregs(fs, nvars)
4252 self:block(ls)
4253 self:leaveblock(fs) -- end of scope for declared variables
4254 luaK:patchtohere(fs, prep)
4255 local endfor = isnum and luaK:codeAsBx(fs, "OP_FORLOOP", base, luaK.NO_JUMP)
4256 or luaK:codeABC(fs, "OP_TFORLOOP", base, 0, nvars)
4257 luaK:fixline(fs, line) -- pretend that `OP_FOR' starts the loop
4258 luaK:patchlist(fs, isnum and endfor or luaK:jump(fs), prep + 1)
4259end
4260
4261------------------------------------------------------------------------
4262-- parse a numerical for loop, calls forbody()
4263-- * used in forstat()
4264------------------------------------------------------------------------
4265function luaY:fornum(ls, varname, line)
4266 -- fornum -> NAME = exp1,exp1[,exp1] forbody
4267 local fs = ls.fs
4268 local base = fs.freereg
4269 self:new_localvarliteral(ls, "(for index)", 0)
4270 self:new_localvarliteral(ls, "(for limit)", 1)
4271 self:new_localvarliteral(ls, "(for step)", 2)
4272 self:new_localvar(ls, varname, 3)
4273 self:checknext(ls, '=')
4274 self:exp1(ls) -- initial value
4275 self:checknext(ls, ",")
4276 self:exp1(ls) -- limit
4277 if self:testnext(ls, ",") then
4278 self:exp1(ls) -- optional step
4279 else -- default step = 1
4280 luaK:codeABx(fs, "OP_LOADK", fs.freereg, luaK:numberK(fs, 1))
4281 luaK:reserveregs(fs, 1)
4282 end
4283 self:forbody(ls, base, line, 1, true)
4284end
4285
4286------------------------------------------------------------------------
4287-- parse a generic for loop, calls forbody()
4288-- * used in forstat()
4289------------------------------------------------------------------------
4290function luaY:forlist(ls, indexname)
4291 -- forlist -> NAME {,NAME} IN explist1 forbody
4292 local fs = ls.fs
4293 local e = {} -- expdesc
4294 local nvars = 0
4295 local base = fs.freereg
4296 -- create control variables
4297 self:new_localvarliteral(ls, "(for generator)", nvars)
4298 nvars = nvars + 1
4299 self:new_localvarliteral(ls, "(for state)", nvars)
4300 nvars = nvars + 1
4301 self:new_localvarliteral(ls, "(for control)", nvars)
4302 nvars = nvars + 1
4303 -- create declared variables
4304 self:new_localvar(ls, indexname, nvars)
4305 nvars = nvars + 1
4306 while self:testnext(ls, ",") do
4307 self:new_localvar(ls, self:str_checkname(ls), nvars)
4308 nvars = nvars + 1
4309 end
4310 self:checknext(ls, "TK_IN")
4311 local line = ls.linenumber
4312 self:adjust_assign(ls, 3, self:explist1(ls, e), e)
4313 luaK:checkstack(fs, 3) -- extra space to call generator
4314 self:forbody(ls, base, line, nvars - 3, false)
4315end
4316
4317------------------------------------------------------------------------
4318-- initial parsing for a for loop, calls fornum() or forlist()
4319-- * used in statements()
4320------------------------------------------------------------------------
4321function luaY:forstat(ls, line)
4322 -- forstat -> FOR (fornum | forlist) END
4323 local fs = ls.fs
4324 local bl = {} -- BlockCnt
4325 self:enterblock(fs, bl, true) -- scope for loop and control variables
4326 luaX:next(ls) -- skip `for'
4327 local varname = self:str_checkname(ls) -- first variable name
4328 local c = ls.t.token
4329 if c == "=" then
4330 self:fornum(ls, varname, line)
4331 elseif c == "," or c == "TK_IN" then
4332 self:forlist(ls, varname)
4333 else
4334 luaX:syntaxerror(ls, self:LUA_QL("=").." or "..self:LUA_QL("in").." expected")
4335 end
4336 self:check_match(ls, "TK_END", "TK_FOR", line)
4337 self:leaveblock(fs) -- loop scope (`break' jumps to this point)
4338end
4339
4340------------------------------------------------------------------------
4341-- parse part of an if control structure, including the condition
4342-- * used in ifstat()
4343------------------------------------------------------------------------
4344function luaY:test_then_block(ls)
4345 -- test_then_block -> [IF | ELSEIF] cond THEN block
4346 luaX:next(ls) -- skip IF or ELSEIF
4347 local condexit = self:cond(ls)
4348 self:checknext(ls, "TK_THEN")
4349 self:block(ls) -- `then' part
4350 return condexit
4351end
4352
4353------------------------------------------------------------------------
4354-- parse an if control structure
4355-- * used in statements()
4356------------------------------------------------------------------------
4357function luaY:ifstat(ls, line)
4358 -- ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END
4359 local fs = ls.fs
4360 local escapelist = luaK.NO_JUMP
4361 local flist = self:test_then_block(ls) -- IF cond THEN block
4362 while ls.t.token == "TK_ELSEIF" do
4363 escapelist = luaK:concat(fs, escapelist, luaK:jump(fs))
4364 luaK:patchtohere(fs, flist)
4365 flist = self:test_then_block(ls) -- ELSEIF cond THEN block
4366 end
4367 if ls.t.token == "TK_ELSE" then
4368 escapelist = luaK:concat(fs, escapelist, luaK:jump(fs))
4369 luaK:patchtohere(fs, flist)
4370 luaX:next(ls) -- skip ELSE (after patch, for correct line info)
4371 self:block(ls) -- 'else' part
4372 else
4373 escapelist = luaK:concat(fs, escapelist, flist)
4374 end
4375 luaK:patchtohere(fs, escapelist)
4376 self:check_match(ls, "TK_END", "TK_IF", line)
4377end
4378
4379------------------------------------------------------------------------
4380-- parse a local function statement
4381-- * used in statements()
4382------------------------------------------------------------------------
4383function luaY:localfunc(ls)
4384 local v, b = {}, {} -- expdesc
4385 local fs = ls.fs
4386 self:new_localvar(ls, self:str_checkname(ls), 0)
4387 self:init_exp(v, "VLOCAL", fs.freereg)
4388 luaK:reserveregs(fs, 1)
4389 self:adjustlocalvars(ls, 1)
4390 self:body(ls, b, false, ls.linenumber)
4391 luaK:storevar(fs, v, b)
4392 -- debug information will only see the variable after this point!
4393 self:getlocvar(fs, fs.nactvar - 1).startpc = fs.pc
4394end
4395
4396------------------------------------------------------------------------
4397-- parse a local variable declaration statement
4398-- * used in statements()
4399------------------------------------------------------------------------
4400function luaY:localstat(ls)
4401 -- stat -> LOCAL NAME {',' NAME} ['=' explist1]
4402 local nvars = 0
4403 local nexps
4404 local e = {} -- expdesc
4405 repeat
4406 self:new_localvar(ls, self:str_checkname(ls), nvars)
4407 nvars = nvars + 1
4408 until not self:testnext(ls, ",")
4409 if self:testnext(ls, "=") then
4410 nexps = self:explist1(ls, e)
4411 else
4412 e.k = "VVOID"
4413 nexps = 0
4414 end
4415 self:adjust_assign(ls, nvars, nexps, e)
4416 self:adjustlocalvars(ls, nvars)
4417end
4418
4419------------------------------------------------------------------------
4420-- parse a function name specification
4421-- * used in funcstat()
4422------------------------------------------------------------------------
4423function luaY:funcname(ls, v)
4424 -- funcname -> NAME {field} [':' NAME]
4425 local needself = false
4426 self:singlevar(ls, v)
4427 while ls.t.token == "." do
4428 self:field(ls, v)
4429 end
4430 if ls.t.token == ":" then
4431 needself = true
4432 self:field(ls, v)
4433 end
4434 return needself
4435end
4436
4437------------------------------------------------------------------------
4438-- parse a function statement
4439-- * used in statements()
4440------------------------------------------------------------------------
4441function luaY:funcstat(ls, line)
4442 -- funcstat -> FUNCTION funcname body
4443 local v, b = {}, {} -- expdesc
4444 luaX:next(ls) -- skip FUNCTION
4445 local needself = self:funcname(ls, v)
4446 self:body(ls, b, needself, line)
4447 luaK:storevar(ls.fs, v, b)
4448 luaK:fixline(ls.fs, line) -- definition 'happens' in the first line
4449end
4450
4451------------------------------------------------------------------------
4452-- parse a function call with no returns or an assignment statement
4453-- * used in statements()
4454------------------------------------------------------------------------
4455function luaY:exprstat(ls)
4456 -- stat -> func | assignment
4457 local fs = ls.fs
4458 local v = {} -- LHS_assign
4459 v.v = {}
4460 self:primaryexp(ls, v.v)
4461 if v.v.k == "VCALL" then -- stat -> func
4462 luaP:SETARG_C(luaK:getcode(fs, v.v), 1) -- call statement uses no results
4463 else -- stat -> assignment
4464 v.prev = nil
4465 self:assignment(ls, v, 1)
4466 end
4467end
4468
4469------------------------------------------------------------------------
4470-- parse a return statement
4471-- * used in statements()
4472------------------------------------------------------------------------
4473function luaY:retstat(ls)
4474 -- stat -> RETURN explist
4475 local fs = ls.fs
4476 local e = {} -- expdesc
4477 local first, nret -- registers with returned values
4478 luaX:next(ls) -- skip RETURN
4479 if self:block_follow(ls.t.token) or ls.t.token == ";" then
4480 first, nret = 0, 0 -- return no values
4481 else
4482 nret = self:explist1(ls, e) -- optional return values
4483 if self:hasmultret(e.k) then
4484 luaK:setmultret(fs, e)
4485 if e.k == "VCALL" and nret == 1 then -- tail call?
4486 luaP:SET_OPCODE(luaK:getcode(fs, e), "OP_TAILCALL")
4487 assert(luaP:GETARG_A(luaK:getcode(fs, e)) == fs.nactvar)
4488 end
4489 first = fs.nactvar
4490 nret = self.LUA_MULTRET -- return all values
4491 else
4492 if nret == 1 then -- only one single value?
4493 first = luaK:exp2anyreg(fs, e)
4494 else
4495 luaK:exp2nextreg(fs, e) -- values must go to the 'stack'
4496 first = fs.nactvar -- return all 'active' values
4497 assert(nret == fs.freereg - first)
4498 end
4499 end--if
4500 end--if
4501 luaK:ret(fs, first, nret)
4502end
4503
4504------------------------------------------------------------------------
4505-- initial parsing for statements, calls a lot of functions
4506-- * returns boolean instead of 0|1
4507-- * used in chunk()
4508------------------------------------------------------------------------
4509function luaY:statement(ls)
4510 local line = ls.linenumber -- may be needed for error messages
4511 local c = ls.t.token
4512 if c == "TK_IF" then -- stat -> ifstat
4513 self:ifstat(ls, line)
4514 return false
4515 elseif c == "TK_WHILE" then -- stat -> whilestat
4516 self:whilestat(ls, line)
4517 return false
4518 elseif c == "TK_DO" then -- stat -> DO block END
4519 luaX:next(ls) -- skip DO
4520 self:block(ls)
4521 self:check_match(ls, "TK_END", "TK_DO", line)
4522 return false
4523 elseif c == "TK_FOR" then -- stat -> forstat
4524 self:forstat(ls, line)
4525 return false
4526 elseif c == "TK_REPEAT" then -- stat -> repeatstat
4527 self:repeatstat(ls, line)
4528 return false
4529 elseif c == "TK_FUNCTION" then -- stat -> funcstat
4530 self:funcstat(ls, line)
4531 return false
4532 elseif c == "TK_LOCAL" then -- stat -> localstat
4533 luaX:next(ls) -- skip LOCAL
4534 if self:testnext(ls, "TK_FUNCTION") then -- local function?
4535 self:localfunc(ls)
4536 else
4537 self:localstat(ls)
4538 end
4539 return false
4540 elseif c == "TK_RETURN" then -- stat -> retstat
4541 self:retstat(ls)
4542 return true -- must be last statement
4543 elseif c == "TK_BREAK" then -- stat -> breakstat
4544 luaX:next(ls) -- skip BREAK
4545 self:breakstat(ls)
4546 return true -- must be last statement
4547 else
4548 self:exprstat(ls)
4549 return false -- to avoid warnings
4550 end--if c
4551end
4552
4553------------------------------------------------------------------------
4554-- parse a chunk, which consists of a bunch of statements
4555-- * used in parser(), body(), block(), repeatstat()
4556------------------------------------------------------------------------
4557function luaY:chunk(ls)
4558 -- chunk -> { stat [';'] }
4559 local islast = false
4560 self:enterlevel(ls)
4561 while not islast and not self:block_follow(ls.t.token) do
4562 islast = self:statement(ls)
4563 self:testnext(ls, ";")
4564 assert(ls.fs.f.maxstacksize >= ls.fs.freereg and
4565 ls.fs.freereg >= ls.fs.nactvar)
4566 ls.fs.freereg = ls.fs.nactvar -- free registers
4567 end
4568 self:leavelevel(ls)
4569end
4570
4571-- }======================================================================
4572local luaYfunc = luaY
4573
4574local lua_opcode_types = {
4575 "ABC", "ABx", "ABC", "ABC",
4576 "ABC", "ABx", "ABC", "ABx",
4577 "ABC", "ABC", "ABC", "ABC",
4578 "ABC", "ABC", "ABC", "ABC",
4579 "ABC", "ABC", "ABC", "ABC",
4580 "ABC", "ABC", "AsBx", "ABC",
4581 "ABC", "ABC", "ABC", "ABC",
4582 "ABC", "ABC", "ABC", "AsBx",
4583 "AsBx", "ABC", "ABC", "ABC",
4584 "ABx", "ABC",
4585}
4586
4587local lua_opcode_names = {
4588 "MOVE", "LOADK", "LOADBOOL", "LOADNIL",
4589 "GETUPVAL", "GETGLOBAL", "GETTABLE", "SETGLOBAL",
4590 "SETUPVAL", "SETTABLE", "NEWTABLE", "SELF",
4591 "ADD", "SUB", "MUL", "DIV",
4592 "MOD", "POW", "UNM", "NOT",
4593 "LEN", "CONCAT", "JMP", "EQ",
4594 "LT", "LE", "TEST", "TESTSET",
4595 "CALL", "TAILCALL", "RETURN", "FORLOOP",
4596 "FORPREP", "TFORLOOP", "SETLIST", "CLOSE",
4597 "CLOSURE", "VARARG"
4598};
4599
4600--[[
4601local lua_opcode_numbers = {};
4602for number, name in next, lua_opcode_names do
4603 lua_opcode_numbers[name] = number;
4604end
4605--]]
4606
4607--- Extract bits from an integer
4608--@author: Stravant
4609local function get_bits(input, n, n2)
4610 if n2 then
4611 local total = 0
4612 local digitn = 0
4613 for i = n, n2 do
4614 total = total + 2^digitn*get_bits(input, i)
4615 digitn = digitn + 1
4616 end
4617 return total
4618 else
4619 local pn = 2^(n-1)
4620 return (input % (pn + pn) >= pn) and 1 or 0
4621 end
4622end
4623
4624local function decode_bytecode(bytecode)
4625 local index = 1
4626 local big_endian = false
4627 local int_size;
4628 local size_t;
4629
4630 -- Actual binary decoding functions. Dependant on the bytecode.
4631 local get_int, get_size_t;
4632
4633 -- Binary decoding helper functions
4634 local get_int8, get_int32, get_int64, get_float64, get_string;
4635 do
4636 function get_int8()
4637 local a = bytecode:byte(index, index);
4638 index = index + 1
4639 return a
4640 end
4641 function get_int32()
4642 local a, b, c, d = bytecode:byte(index, index + 3);
4643 index = index + 4;
4644 return d*16777216 + c*65536 + b*256 + a
4645 end
4646 function get_int64()
4647 local a = get_int32();
4648 local b = get_int32();
4649 return b*4294967296 + a;
4650 end
4651 function get_float64()
4652 local a = get_int32()
4653 local b = get_int32()
4654 return (-2*get_bits(b, 32)+1)*(2^(get_bits(b, 21, 31)-1023))*
4655 ((get_bits(b, 1, 20)*(2^32) + a)/(2^52)+1)
4656 end
4657 function get_string(len)
4658 local str;
4659 if len then
4660 str = bytecode:sub(index, index + len - 1);
4661 index = index + len;
4662 else
4663 len = get_size_t();
4664 if len == 0 then return; end
4665 str = bytecode:sub(index, index + len - 1);
4666 index = index + len;
4667 end
4668 return str;
4669 end
4670 end
4671
4672 local function decode_chunk()
4673 local chunk;
4674 local instructions = {};
4675 local constants = {};
4676 local prototypes = {};
4677 local debug = {
4678 lines = {};
4679 };
4680
4681 chunk = {
4682 instructions = instructions;
4683 constants = constants;
4684 prototypes = prototypes;
4685 debug = debug;
4686 };
4687
4688 local num;
4689
4690 chunk.name = get_string();-- Function name
4691 chunk.first_line = get_int(); -- First line
4692 chunk.last_line = get_int(); -- Last line
4693
4694 if chunk.name then chunk.name = chunk.name:sub(1, -2); end
4695
4696 chunk.upvalues = get_int8();
4697 chunk.arguments = get_int8();
4698 chunk.varg = get_int8();
4699 chunk.stack = get_int8();
4700
4701 -- TODO: realign lists to 1
4702 -- Decode instructions
4703 do
4704 num = get_int();
4705 for i = 1, num do
4706 local instruction = {
4707 -- opcode = opcode number;
4708 -- type = [ABC, ABx, AsBx]
4709 -- A, B, C, Bx, or sBx depending on type
4710 };
4711
4712 local data = get_int32();
4713 local opcode = get_bits(data, 1, 6);
4714 local type = lua_opcode_types[opcode + 1];
4715
4716 instruction.opcode = opcode;
4717 instruction.type = type;
4718
4719 instruction.A = get_bits(data, 7, 14);
4720 if type == "ABC" then
4721 instruction.B = get_bits(data, 24, 32);
4722 instruction.C = get_bits(data, 15, 23);
4723 elseif type == "ABx" then
4724 instruction.Bx = get_bits(data, 15, 32);
4725 elseif type == "AsBx" then
4726 instruction.sBx = get_bits(data, 15, 32) - 131071;
4727 end
4728
4729 instructions[i] = instruction;
4730 end
4731 end
4732
4733 -- Decode constants
4734 do
4735 num = get_int();
4736 for i = 1, num do
4737 local constant = {
4738 -- type = constant type;
4739 -- data = constant data;
4740 };
4741 local type = get_int8();
4742 constant.type = type;
4743
4744 if type == 1 then
4745 constant.data = (get_int8() ~= 0);
4746 elseif type == 3 then
4747 constant.data = get_float64();
4748 elseif type == 4 then
4749 constant.data = get_string():sub(1, -2);
4750 end
4751
4752 constants[i-1] = constant;
4753 end
4754 end
4755
4756 -- Decode Prototypes
4757 do
4758 num = get_int();
4759 for i = 1, num do
4760 prototypes[i-1] = decode_chunk();
4761 end
4762 end
4763
4764 -- Decode debug info
4765 -- Not all of which is used yet.
4766 do
4767 -- line numbers
4768 local data = debug.lines
4769 num = get_int();
4770 for i = 1, num do
4771 data[i] = get_int32();
4772 end
4773
4774 -- locals
4775 num = get_int();
4776 for i = 1, num do
4777 get_string():sub(1, -2); -- local name
4778 get_int32(); -- local start PC
4779 get_int32(); -- local end PC
4780 end
4781
4782 -- upvalues
4783 num = get_int();
4784 for i = 1, num do
4785 get_string(); -- upvalue name
4786 end
4787 end
4788
4789 return chunk;
4790 end
4791
4792 -- Verify bytecode header
4793 do
4794 assert(get_string(4) == "\27Lua", "Lua bytecode expected.");
4795 assert(get_int8() == 0x51, "Only Lua 5.1 is supported.");
4796 get_int8(); -- Oficial bytecode
4797 big_endian = (get_int8() == 0);
4798 int_size = get_int8();
4799 size_t = get_int8();
4800
4801 if int_size == 4 then
4802 get_int = get_int32;
4803 elseif int_size == 8 then
4804 get_int = get_int64;
4805 else
4806 -- TODO: refactor errors into table
4807 error("Unsupported bytecode target platform");
4808 end
4809
4810 if size_t == 4 then
4811 get_size_t = get_int32;
4812 elseif size_t == 8 then
4813 get_size_t = get_int64;
4814 else
4815 error("Unsupported bytecode target platform");
4816 end
4817
4818 assert(get_string(3) == "\4\8\0",
4819 "Unsupported bytecode target platform");
4820 end
4821
4822 return decode_chunk();
4823end
4824
4825local function handle_return(...)
4826 local c = select("#", ...)
4827 local t = {...}
4828 return c, t
4829end
4830
4831local function create_wrapper(cache, upvalues)
4832 local instructions = cache.instructions;
4833 local constants = cache.constants;
4834 local prototypes = cache.prototypes;
4835
4836 local stack, top
4837 local environment
4838 local IP = 1; -- instruction pointer
4839 local vararg, vararg_size
4840
4841 local opcode_funcs = {
4842 [0] = function(instruction) -- MOVE
4843 stack[instruction.A] = stack[instruction.B];
4844 end,
4845 [1] = function(instruction) -- LOADK
4846 stack[instruction.A] = constants[instruction.Bx].data;
4847 end,
4848 [2] = function(instruction) -- LOADBOOL
4849 stack[instruction.A] = instruction.B ~= 0
4850 if instruction.C ~= 0 then
4851 IP = IP + 1
4852 end
4853 end,
4854 [3] = function(instruction) -- LOADNIL
4855 local stack = stack
4856 for i = instruction.A, instruction.B do
4857 stack[i] = nil
4858 end
4859 end,
4860 [4] = function(instruction) -- GETUPVAL
4861 stack[instruction.A] = upvalues[instruction.B]
4862 end,
4863 [5] = function(instruction) -- GETGLOBAL
4864 local key = constants[instruction.Bx].data;
4865 stack[instruction.A] = environment[key];
4866 end,
4867 [6] = function(instruction) -- GETTABLE
4868 local C = instruction.C
4869 local stack = stack
4870 C = C > 255 and constants[C-256].data or stack[C]
4871 stack[instruction.A] = stack[instruction.B][C];
4872 end,
4873 [7] = function(instruction) -- SETGLOBAL
4874 local key = constants[instruction.Bx].data;
4875 environment[key] = stack[instruction.A];
4876 end,
4877 [8] = function (instruction) -- SETUPVAL
4878 upvalues[instruction.B] = stack[instruction.A]
4879 end,
4880 [9] = function (instruction) -- SETTABLE
4881 local B = instruction.B;
4882 local C = instruction.C;
4883 local stack, constants = stack, constants;
4884
4885 B = B > 255 and constants[B-256].data or stack[B];
4886 C = C > 255 and constants[C-256].data or stack[C];
4887
4888 stack[instruction.A][B] = C
4889 end,
4890 [10] = function (instruction) -- NEWTABLE
4891 stack[instruction.A] = {}
4892 end,
4893 [11] = function (instruction) -- SELF
4894 local A = instruction.A
4895 local B = instruction.B
4896 local C = instruction.C
4897 local stack = stack
4898
4899 B = stack[B]
4900 C = C > 255 and constants[C-256].data or stack[C]
4901
4902 stack[A+1] = B
4903 stack[A] = B[C]
4904 end,
4905 [12] = function(instruction) -- ADD
4906 local B = instruction.B;
4907 local C = instruction.C;
4908 local stack, constants = stack, constants;
4909
4910 B = B > 255 and constants[B-256].data or stack[B];
4911 C = C > 255 and constants[C-256].data or stack[C];
4912
4913 stack[instruction.A] = B+C;
4914 end,
4915 [13] = function(instruction) -- SUB
4916 local B = instruction.B;
4917 local C = instruction.C;
4918 local stack, constants = stack, constants;
4919
4920 B = B > 255 and constants[B-256].data or stack[B];
4921 C = C > 255 and constants[C-256].data or stack[C];
4922
4923 stack[instruction.A] = B - C;
4924 end,
4925 [14] = function(instruction) -- MUL
4926 local B = instruction.B;
4927 local C = instruction.C;
4928 local stack, constants = stack, constants;
4929
4930 B = B > 255 and constants[B-256].data or stack[B];
4931 C = C > 255 and constants[C-256].data or stack[C];
4932
4933 stack[instruction.A] = B * C;
4934 end,
4935 [15] = function(instruction) --DIV
4936 local B = instruction.B;
4937 local C = instruction.C;
4938 local stack, constants = stack, constants;
4939
4940 B = B > 255 and constants[B-256].data or stack[B];
4941 C = C > 255 and constants[C-256].data or stack[C];
4942
4943 stack[instruction.A] = B / C;
4944 end,
4945 [16] = function(instruction) -- MOD
4946 local B = instruction.B;
4947 local C = instruction.C;
4948 local stack, constants = stack, constants;
4949
4950 B = B > 255 and constants[B-256].data or stack[B];
4951 C = C > 255 and constants[C-256].data or stack[C];
4952
4953 stack[instruction.A] = B % C;
4954 end,
4955 [17] = function(instruction) -- POW
4956 local B = instruction.B;
4957 local C = instruction.C;
4958 local stack, constants = stack, constants;
4959
4960 B = B > 255 and constants[B-256].data or stack[B];
4961 C = C > 255 and constants[C-256].data or stack[C];
4962
4963 stack[instruction.A] = B ^ C;
4964 end,
4965 [18] = function(instruction) -- UNM
4966 stack[instruction.A] = -stack[instruction.B]
4967 end,
4968 [19] = function(instruction) -- NOT
4969 stack[instruction.A] = not stack[instruction.B]
4970 end,
4971 [20] = function(instruction) -- LEN
4972 stack[instruction.A] = #stack[instruction.B]
4973 end,
4974 [21] = function(instruction) -- CONCAT
4975 local B = instruction.B
4976 local result = stack[B]
4977 for i = B+1, instruction.C do
4978 result = result .. stack[i]
4979 end
4980 stack[instruction.A] = result
4981 end,
4982 [22] = function(instruction) -- JUMP
4983 IP = IP + instruction.sBx
4984 end,
4985 [23] = function(instruction) -- EQ
4986 local A = instruction.A
4987 local B = instruction.B
4988 local C = instruction.C
4989 local stack, constants = stack, constants
4990
4991 A = A ~= 0
4992 B = B > 255 and constants[B-256].data or stack[B]
4993 C = C > 255 and constants[C-256].data or stack[C]
4994 if (B == C) ~= A then
4995 IP = IP + 1
4996 end
4997 end,
4998 [24] = function(instruction) -- LT
4999 local A = instruction.A
5000 local B = instruction.B
5001 local C = instruction.C
5002 local stack, constants = stack, constants
5003
5004 A = A ~= 0
5005 B = B > 255 and constants[B-256].data or stack[B]
5006 C = C > 255 and constants[C-256].data or stack[C]
5007 if (B < C) ~= A then
5008 IP = IP + 1
5009 end
5010 end,
5011 [25] = function(instruction) -- LT
5012 local A = instruction.A
5013 local B = instruction.B
5014 local C = instruction.C
5015 local stack, constants = stack, constants
5016
5017 A = A ~= 0
5018 B = B > 255 and constants[B-256].data or stack[B]
5019 C = C > 255 and constants[C-256].data or stack[C]
5020 if (B <= C) ~= A then
5021 IP = IP + 1
5022 end
5023 end,
5024 [26] = function(instruction) -- TEST
5025 if stack[instruction.A] == (instruction.C ~= 0) then
5026 IP = IP + 1
5027 end
5028 end,
5029 [27] = function(instruction) -- TESTSET
5030 local stack = stack
5031 local B = stack[instruction.B]
5032
5033 if B == (instruction.C ~= 0) then
5034 IP = IP + 1
5035 else
5036 stack[instruction.A] = B
5037 end
5038 end,
5039 [28] = function(instruction) -- CALL
5040 local A = instruction.A;
5041 local B = instruction.B;
5042 local C = instruction.C;
5043 local stack = stack;
5044 local args, results;
5045 local limit, loop
5046
5047 args = {};
5048 if B ~= 1 then
5049 if B ~= 0 then
5050 limit = A+B-1;
5051 else
5052 limit = top
5053 end
5054
5055 loop = 0
5056 for i = A+1, limit do
5057 loop = loop + 1
5058 args[loop] = stack[i];
5059 end
5060
5061 limit, results = handle_return(stack[A](unpack(args, 1, limit-A)))
5062 else
5063 limit, results = handle_return(stack[A]())
5064 end
5065
5066 top = A - 1
5067
5068 if C ~= 1 then
5069 if C ~= 0 then
5070 limit = A+C-2;
5071 else
5072 limit = limit+A
5073 end
5074
5075 loop = 0;
5076 for i = A, limit do
5077 loop = loop + 1;
5078 stack[i] = results[loop];
5079 end
5080 end
5081 end,
5082 [29] = function (instruction) -- TAILCALL
5083 local A = instruction.A;
5084 local B = instruction.B;
5085 local C = instruction.C;
5086 local stack = stack;
5087 local args, results;
5088 local top, limit, loop = top
5089
5090 args = {};
5091 if B ~= 1 then
5092 if B ~= 0 then
5093 limit = A+B-1;
5094 else
5095 limit = top
5096 end
5097
5098 loop = 0
5099 for i = A+1, limit do
5100 loop = loop + 1
5101 args[#args+1] = stack[i];
5102 end
5103
5104 results = {stack[A](unpack(args, 1, limit-A))};
5105 else
5106 results = {stack[A]()};
5107 end
5108
5109 return true, results
5110 end,
5111 [30] = function(instruction) -- RETURN
5112 --TODO: CLOSE
5113 local A = instruction.A;
5114 local B = instruction.B;
5115 local stack = stack;
5116 local limit;
5117 local loop, output;
5118
5119 if B == 1 then
5120 return true;
5121 end
5122 if B == 0 then
5123 limit = top
5124 else
5125 limit = A + B - 2;
5126 end
5127
5128 output = {};
5129 local loop = 0
5130 for i = A, limit do
5131 loop = loop + 1
5132 output[loop] = stack[i];
5133 end
5134 return true, output;
5135 end,
5136 [31] = function(instruction) -- FORLOOP
5137 local A = instruction.A
5138 local stack = stack
5139
5140 local step = stack[A+2]
5141 local index = stack[A] + step
5142 stack[A] = index
5143
5144 if step > 0 then
5145 if index <= stack[A+1] then
5146 IP = IP + instruction.sBx
5147 stack[A+3] = index
5148 end
5149 else
5150 if index >= stack[A+1] then
5151 IP = IP + instruction.sBx
5152 stack[A+3] = index
5153 end
5154 end
5155 end,
5156 [32] = function(instruction) -- FORPREP
5157 local A = instruction.A
5158 local stack = stack
5159
5160 stack[A] = stack[A] - stack[A+2]
5161 IP = IP + instruction.sBx
5162 end,
5163 [33] = function(instruction) -- TFORLOOP
5164 local A = instruction.A
5165 local B = instruction.B
5166 local C = instruction.C
5167 local stack = stack
5168
5169 local offset = A+2
5170 local result = {stack[A](stack[A+1], stack[A+2])}
5171 for i = 1, C do
5172 stack[offset+i] = result[i]
5173 end
5174
5175 if stack[A+3] ~= nil then
5176 stack[A+2] = stack[A+3]
5177 else
5178 IP = IP + 1
5179 end
5180 end,
5181 [34] = function(instruction) -- SETLIST
5182 local A = instruction.A
5183 local B = instruction.B
5184 local C = instruction.C
5185 local stack = stack
5186
5187 if C == 0 then
5188 error("NYI: extended SETLIST")
5189 else
5190 local offset = (C - 1) * 50
5191 local t = stack[A]
5192
5193 if B == 0 then
5194 B = top
5195 end
5196 for i = 1, B do
5197 t[offset+i] = stack[A+i]
5198 end
5199 end
5200 end,
5201 [35] = function(instruction) -- CLOSE
5202 io.stderr:write("NYI: CLOSE")
5203 io.stderr:flush()
5204 end,
5205 [36] = function(instruction) -- CLOSURE
5206 local proto = prototypes[instruction.Bx]
5207 local instructions = instructions
5208 local stack = stack
5209
5210 local indices = {}
5211 local new_upvals = setmetatable({},
5212 {
5213 __index = function(t, k)
5214 local upval = indices[k]
5215 return upval.segment[upval.offset]
5216 end,
5217 __newindex = function(t, k, v)
5218 local upval = indices[k]
5219 upval.segment[upval.offset] = v
5220 end
5221 }
5222 )
5223 for i = 1, proto.upvalues do
5224 local movement = instructions[IP]
5225 if movement.opcode == 0 then -- MOVE
5226 indices[i-1] = {segment = stack, offset = movement.B}
5227 elseif instructions[IP].opcode == 4 then -- GETUPVAL
5228 indices[i-1] = {segment = upvalues, offset = movement.B}
5229 end
5230 IP = IP + 1
5231 end
5232
5233 local _, func = create_wrapper(proto, new_upvals)
5234 stack[instruction.A] = func
5235 end,
5236 [37] = function(instruction) -- VARARG
5237 local A = instruction.A
5238 local B = instruction.B
5239 local stack, vararg = stack, vararg
5240
5241 for i = A, A + (B > 0 and B - 1 or vararg_size) do
5242 stack[i] = vararg[i - A]
5243 end
5244 end,
5245 }
5246
5247 local function loop()
5248 local instructions = instructions
5249 local instruction, a, b
5250
5251 while true do
5252 instruction = instructions[IP];
5253 IP = IP + 1
5254 a, b = opcode_funcs[instruction.opcode](instruction);
5255 if a then
5256 return b;
5257 end
5258 end
5259 end
5260
5261 local debugging = {
5262 get_stack = function()
5263 return stack;
5264 end;
5265 get_IP = function()
5266 return IP;
5267 end
5268 };
5269
5270 local function func(...)
5271 local local_stack = {};
5272 local ghost_stack = {};
5273
5274 top = -1
5275 stack = setmetatable(local_stack, {
5276 __index = ghost_stack;
5277 __newindex = function(t, k, v)
5278 if k > top and v then
5279 top = k
5280 end
5281 ghost_stack[k] = v
5282 end;
5283 })
5284 local args = {...};
5285 vararg = {}
5286 vararg_size = select("#", ...) - 1
5287 for i = 0, vararg_size do
5288 local_stack[i] = args[i+1];
5289 vararg[i] = args[i+1]
5290 end
5291
5292 environment = getfenv();
5293 IP = 1;
5294 local thread = coroutine.create(loop)
5295 local a, b = coroutine.resume(thread)
5296
5297 if a then
5298 if b then
5299 return unpack(b);
5300 end
5301 return;
5302 else
5303 if advanced_debug then
5304 --TODO advanced debugging
5305 else
5306 --TODO error converting
5307 local name = cache.name;
5308 local line = cache.debug.lines[IP];
5309 local err = b:gsub("(.-:)", "");
5310 local output = "";
5311
5312 output = output .. (name and name .. ":" or "");
5313 output = output .. (line and line .. ":" or "");
5314 output = output .. b
5315 --[[
5316 output = ("%s (Instruction=%s)"):format(output,
5317 lua_opcode_names[select(2,debug.getlocal(loop,1, 1)).opcode+1])
5318 --]]
5319 error(output, 0);
5320 end
5321 end
5322 end
5323
5324 return debugging, func;
5325end
5326
5327local VM = {
5328 load_bytecode = function(bytecode)
5329 local cache = decode_bytecode(bytecode);
5330 local _, func = create_wrapper(cache);
5331 return func;
5332 end;
5333
5334 -- Utilities (Debug, Introspection, Testing, etc)
5335 utils = {
5336 decode_bytecode = decode_bytecode;
5337 create_wrapper = create_wrapper;
5338 debug_bytecode = function(bytecode)
5339 local cache = decode_bytecode(bytecode)
5340 return create_wrapper(cache);
5341 end;
5342 };
5343}
5344
5345--[[
5346 dofile("lzio.lua")
5347 dofile("llex.lua")
5348 dofile("lopcodes.lua")
5349 dofile("ldump.lua")
5350 dofile("lcode.lua")
5351 dofile("lparser.lua")
5352]]
5353
5354luaXfunc:init()
5355local LuaState = {}
5356
5357local loadstring = function(str)
5358 if string.sub(str,1,5) == "\027LuaQ" then
5359 return VM.load_bytecode(str)
5360 else
5361 local code = str
5362 -- luaZ:make_getF returns a file chunk reader
5363 -- luaZ:init returns a zio input stream
5364 local zio = luaZfunc:init(luaZfunc:make_getS(code), nil)
5365 if not zio then return end
5366 -- luaY:parser parses the input stream
5367 -- func is the function prototype in tabular form; in C, func can
5368 -- now be used directly by the VM, this can't be done in Lua
5369 local func = luaYfunc:parser(LuaState, zio, nil, "@input")
5370 -- luaU:make_setS returns a string chunk writer
5371 local writer, buff = luaUfunc:make_setS()
5372 -- luaU:dump builds a binary chunk
5373 luaUfunc:dump(LuaState, func, writer, buff)
5374 -- a string.dump equivalent in returned
5375 return VM.load_bytecode(buff.data),buff.data
5376 end
5377end
5378
5379local session_id = math.floor(tick() * 10)
5380local local_script_template = script:Clone()
5381local source_value_name
5382local_script_template.Disabled = true
5383for _, child in ipairs(local_script_template:GetChildren()) do
5384 if child:IsA("StringValue") then
5385 if string.lower(child.Name) ~= "owner" then
5386 source_value_name = child.Name
5387 end
5388 child.Value = ""
5389 break
5390 end
5391end
5392script:ClearAllChildren()
5393script.Parent = nil
5394if not source_value_name then
5395 source_value_name = ...
5396 if source_value_name then
5397 local source_value = Instance.new("StringValue", local_script_template)
5398 source_value.Name = source_value_name
5399 else
5400 if not (NewLocalScript and NewScript) then
5401 print("Script builder is incompatible.")
5402 end
5403 source_value_name = "Source"
5404 local_script_template = nil
5405 end
5406end
5407local Module = {}
5408Module.name = "Module"
5409Module.source = string.format([[
5410local _ENV = {
5411 Axes = {
5412 new = Axes.new
5413 },
5414 BrickColor = {
5415 Black = BrickColor.Black,
5416 Blue = BrickColor.Blue,
5417 DarkGray = BrickColor.DarkGray,
5418 Gray = BrickColor.Gray,
5419 Green = BrickColor.Green,
5420 New = BrickColor.New,
5421 Random = BrickColor.Random,
5422 Red = BrickColor.Red,
5423 White = BrickColor.White,
5424 Yellow = BrickColor.Yellow,
5425 new = BrickColor.new,
5426 palette = BrickColor.palette,
5427 random = BrickColor.random
5428 },
5429 CFrame = {
5430 Angles = CFrame.Angles,
5431 fromAxisAngle = CFrame.fromAxisAngle,
5432 fromEulerAnglesXYZ = CFrame.fromEulerAnglesXYZ,
5433 new = CFrame.new
5434 },
5435 CellId = {
5436 new = CellId.new
5437 },
5438 Color3 = {
5439 new = Color3.new
5440 },
5441 Delay = Delay,
5442 Enum = Enum,
5443 Faces = {
5444 new = Faces.new
5445 },
5446 Game = Game,
5447 Instance = {
5448 Lock = Instance.Lock,
5449 Unlock = Instance.Unlock,
5450 new = Instance.new
5451 },
5452 LoadLibrary = LoadLibrary,
5453 LoadRobloxLibrary = LoadRobloxLibrary,
5454 PluginManager = PluginManager,
5455 Ray = {
5456 new = Ray.new
5457 },
5458 Region3 = {
5459 new = Region3.new
5460 },
5461 Region3int16 = {
5462 new = Region3int16.new
5463 },
5464 Spawn = Spawn,
5465 Stats = Stats,
5466 UDim = {
5467 new = UDim.new
5468 },
5469 UDim2 = {
5470 new = UDim2.new
5471 },
5472 UserSettings = UserSettings,
5473 Vector2 = {
5474 new = Vector2.new
5475 },
5476 Vector2int16 = {
5477 new = Vector2int16.new
5478 },
5479 Vector3 = {
5480 FromAxis = Vector3.FromAxis,
5481 FromNormalId = Vector3.FromNormalId,
5482 new = Vector3.new
5483 },
5484 Vector3int16 = {
5485 new = Vector3int16.new
5486 },
5487 Version = Version,
5488 Wait = Wait,
5489 Workspace = Workspace,
5490 _G = _G,
5491 _VERSION = _VERSION,
5492 assert = assert,
5493 collectgarbage = collectgarbage,
5494 coroutine = {
5495 create = coroutine.create,
5496 resume = coroutine.resume,
5497 running = coroutine.running,
5498 status = coroutine.status,
5499 wrap = coroutine.wrap,
5500 yield = coroutine.yield
5501 },
5502 crash__ = crash__,
5503 delay = delay,
5504 dofile = dofile,
5505 error = error,
5506 game = game,
5507 gcinfo = gcinfo,
5508 getfenv = getfenv,
5509 getmetatable = getmetatable,
5510 ipairs = ipairs,
5511 load = load,
5512 loadfile = loadfile,
5513 loadstring = loadstring,
5514 math = {
5515 abs = math.abs,
5516 acos = math.acos,
5517 asin = math.asin,
5518 atan = math.atan,
5519 atan2 = math.atan2,
5520 ceil = math.ceil,
5521 cos = math.cos,
5522 cosh = math.cosh,
5523 deg = math.deg,
5524 exp = math.exp,
5525 floor = math.floor,
5526 fmod = math.fmod,
5527 frexp = math.frexp,
5528 huge = math.huge,
5529 ldexp = math.ldexp,
5530 log = math.log,
5531 log10 = math.log10,
5532 max = math.max,
5533 min = math.min,
5534 modf = math.modf,
5535 phi = 1.618033988749895,
5536 pi = math.pi,
5537 pow = math.pow,
5538 rad = math.rad,
5539 random = math.random,
5540 randomseed = math.randomseed,
5541 sin = math.sin,
5542 sinh = math.sinh,
5543 sqrt = math.sqrt,
5544 tan = math.tan,
5545 tanh = math.tanh,
5546 tau = 2 * math.pi
5547 },
5548 newproxy = newproxy,
5549 next = next,
5550 pairs = pairs,
5551 pcall = pcall,
5552 print = print,
5553 printidentity = printidentity,
5554 rawequal = rawequal,
5555 rawget = rawget,
5556 rawset = rawset,
5557 select = select,
5558 setfenv = setfenv,
5559 setmetatable = setmetatable,
5560 settings = settings,
5561 shared = shared,
5562 stats = stats,
5563 string = {
5564 byte = string.byte,
5565 char = string.char,
5566 dump = string.dump,
5567 find = string.find,
5568 format = string.format,
5569 gfind = string.gfind,
5570 gmatch = string.gmatch,
5571 gsub = string.gsub,
5572 len = string.len,
5573 lower = string.lower,
5574 match = string.match,
5575 rep = string.rep,
5576 reverse = string.reverse,
5577 sub = string.sub,
5578 upper = string.upper
5579 },
5580 table = {
5581 concat = table.concat,
5582 foreach = table.foreach,
5583 foreachi = table.foreachi,
5584 getn = table.getn,
5585 insert = table.insert,
5586 maxn = table.maxn,
5587 remove = table.remove,
5588 setn = table.setn,
5589 sort = table.sort
5590 },
5591 tick = tick,
5592 time = time,
5593 tonumber = tonumber,
5594 tostring = tostring,
5595 type = type,
5596 unpack = unpack,
5597 version = version,
5598 wait = wait,
5599 workspace = workspace,
5600 xpcall = xpcall,
5601 ypcall = ypcall
5602}
5603_ENV.Environment = ...
5604_ENV.Environment._ENV = _ENV
5605local _RBX = getfenv()
5606_ENV._ENV = _ENV
5607_ENV._RBX = _RBX
5608_ENV._SessionID = %s
5609_ENV.Debris = Game:GetService("Debris")
5610_ENV.InsertService = Game:GetService("InsertService")
5611_ENV.Lighting = Game:GetService("Lighting")
5612_ENV.LogService = Game:GetService("LogService")
5613_ENV.Players = Game:GetService("Players")
5614_ENV.RunService = Game:GetService("RunService")
5615_ENV.ReplicatedStorage = Game:GetService("ReplicatedStorage")
5616_ENV.SoundService = Game:GetService("SoundService")
5617_ENV.StarterGui = Game:GetService("StarterGui")
5618_ENV.StarterPack = Game:GetService("StarterPack")
5619_ENV.TeleportService = Game:GetService("TeleportService")
5620_ENV.RbxUtility = LoadLibrary("RbxUtility")
5621if N_ENV then
5622 N_ENV(_ENV)
5623end
5624local Module = ...
5625Module.data = {
5626 listeners = {},
5627 modules = {}
5628}
5629Module.metatable = {}
5630function Module.metatable:__tostring()
5631 return tostring(self.name)
5632end
5633function Module.Create(name, source, ...)
5634 local module = Module.Store(name, source)
5635 Module.Initialize(module, ...)
5636 return module
5637end
5638function Module.Initialize(module, ...)
5639 local name = module.name
5640 local load_function, message = loadstring(module.source, name)
5641 if load_function then
5642 local success, message = ypcall(setfenv(load_function, _ENV), ...)
5643 if success then
5644 if _ENV.Logger and _ENV.Logger.printf then
5645 _ENV.Logger.printf("Output", "%%s: ready", tostring(name))
5646 end
5647 local listeners = Module.data.listeners
5648 local listener = listeners[name]
5649 if listener then
5650 listeners[name] = nil
5651 listener:fire()
5652 end
5653 return module
5654 elseif _ENV.Logger and _ENV.Logger.printf then
5655 _ENV.Logger.printf("Severe", "Runtime error in module '%%s': %%s", tostring(name), message)
5656 else
5657 print(string.format("runtime error in module '%%s': %%s", tostring(name), message))
5658 end
5659 elseif _ENV.Logger and _ENV.Logger.printf then
5660 _ENV.Logger.printf("Severe", "Syntax error in module '%%s': %%s", tostring(name), message)
5661 else
5662 print(string.format("syntax error in module '%%s': %%s", tostring(name), message))
5663 end
5664end
5665function Module.Load(name)
5666 return Module.data.modules[name]
5667end
5668function Module.Register(module)
5669 local name = tostring(module)
5670 _ENV[name] = module
5671 Module.data.modules[name] = module
5672end
5673function Module.Reload(name, source, ...)
5674 local module = Module.Load(name)
5675 for key in pairs(module) do
5676 module[key] = nil
5677 end
5678 module.name = name
5679 module.source = source
5680 Module.Initialize(module, ...)
5681 return module
5682end
5683function Module.Store(name, source)
5684 local module = {}
5685 module.name = name
5686 module.source = source
5687 setmetatable(module, Module.metatable)
5688 Module.Register(module)
5689 return module
5690end
5691function Module.WaitForModule(name)
5692 local module = Module.Load(name)
5693 if not module then
5694 local listeners = Module.data.listeners
5695 local listener = listeners[name]
5696 if not listener then
5697 listener = _ENV.RbxUtility.CreateSignal()
5698 listeners[name] = listener
5699 end
5700 listener:wait()
5701 end
5702end
5703]], tostring(session_id))
5704assert(loadstring(Module.source))(Module)
5705setmetatable(Module, Module.metatable)
5706Module.Register(Module)
5707Module.Create("LuaEnum", [[
5708LuaEnum.enum_metatable = {
5709 __call = function(self, value)
5710 local valueType = type(value)
5711 if valueType == "table" and getmetatable(value) == LuaEnum.enum_item_metatable then
5712 return value
5713 else
5714 return self[value]
5715 end
5716 end,
5717 __index = function(self, key)
5718 local enumItem = self.ItemsByName[key] or self.ItemsByValue[key]
5719 if enumItem == nil then
5720 local default = self.Default
5721 if default then
5722 Logger.printf("Warning", "%s is not a valid EnumItem, returning default (%s)", Utility.ToString(key), tostring(default))
5723 enumItem = default
5724 else
5725 Logger.errorf(2, "%s is not a valid EnumItem", Utility.ToString(key))
5726 end
5727 end
5728 return enumItem
5729 end,
5730 __tostring = function(self)
5731 return self.Name
5732 end
5733}
5734LuaEnum.enum_item_metatable = {
5735 __tostring = function(self)
5736 return self.Enum.Name .. "." .. self.Name
5737 end
5738}
5739LuaEnum.init_metatable = {
5740 __call = function(self, items)
5741 local enumItemsByName = {}
5742 local enumItemsByValue = {}
5743 local enum = {
5744 ItemsByName = enumItemsByName,
5745 ItemsByValue = enumItemsByValue,
5746 Name = self[1]
5747 }
5748 local default = items.Default
5749 if default ~= nil then
5750 items.Default = nil
5751 end
5752 for value, name in pairs(items) do
5753 local enumItem = setmetatable({
5754 Enum = enum,
5755 Name = name,
5756 Value = value
5757 }, LuaEnum.enum_item_metatable)
5758 enumItemsByName[name] = enumItem
5759 enumItemsByValue[value] = enumItem
5760 if name == default or value == default then
5761 enum.Default = enumItem
5762 end
5763 end
5764 return setmetatable(enum, LuaEnum.enum_metatable)
5765 end
5766}
5767function LuaEnum.new(name)
5768 return setmetatable({name}, LuaEnum.init_metatable)
5769end
5770]])
5771Module.Create("Logger", [[
5772Logger.entries = {0}
5773Logger.MessageType = LuaEnum.new "MessageType" {
5774 "Output",
5775 "Info",
5776 "Warning",
5777 "Severe",
5778 "Error",
5779 Default = "Severe"
5780}
5781Logger.MESSAGE_TYPE_SETTINGS = {
5782 { -- Output
5783 Font = "Arial",
5784 TextColor3 = Color3.new(0, 0, 0)
5785 },
5786 { -- Info
5787 Font = "Arial",
5788 TextColor3 = Color3.new(0, 0, 1)
5789 },
5790 { -- Warning
5791 Font = "ArialBold",
5792 TextColor3 = Color3.new(1, 0.5, 0)
5793 },
5794 { -- Severe/Error
5795 Font = "ArialBold",
5796 TextColor3 = Color3.new(1, 0, 0)
5797 }
5798}
5799Logger.MAX_ENTRIES = 160
5800Logger.WARNING_TRACE_ITEM_COUNT = 5
5801Logger.rbxPrint = getfenv(RbxUtility.CreateSignal).print
5802function Logger.error(level, message)
5803 message = message .. "\n" .. Logger.StackTraceToString(Logger.GenerateStackTrace(level + 1))
5804 Logger.AddEntry {Logger.MessageType.Error, message}
5805 error(level + 1, message)
5806end
5807function Logger.errorf(level, messageFormat, ...)
5808 Logger.error(level + 1, string.format(messageFormat, ...))
5809end
5810function Logger.print(messageType, message, level)
5811 messageType = Logger.MessageType(messageType)
5812 local entry = {messageType, message}
5813 Logger.rbxPrint(Logger.EntryToString(entry))
5814 Logger.AddEntry(entry)
5815 if Network and Network.Print then
5816 Network.Print(messageType.Value, message)
5817 end
5818 if level ~= false and messageType.Value >= Logger.MessageType.Warning.Value then
5819 local maxItems
5820 if messageType.Value >= Logger.MessageType.Severe.Value then
5821 maxItems = math.huge
5822 else
5823 maxItems = Logger.WARNING_TRACE_ITEM_COUNT
5824 end
5825 local trace = Logger.GenerateStackTrace((level or 1) + 1, math.huge, 10, maxItems + 1)
5826 local traceLength = #trace
5827 local stackTraceMessage
5828 local suffix = ""
5829 if traceLength > maxItems then
5830 trace[traceLength] = nil
5831 suffix = "\n..."
5832 end
5833 Logger.print("Info", "Stack trace:\n" .. Logger.StackTraceToString(trace) .. suffix .. "\nStack end", false)
5834 end
5835end
5836function Logger.printf(messageType, messageFormat, ...)
5837 Logger.print(messageType, string.format(messageFormat, ...), 2)
5838end
5839function Logger.AddEntry(entry)
5840 local entries = Logger.entries
5841 if entries[1] >= Logger.MAX_ENTRIES then
5842 local first = entries[2]
5843 local nextFirst = first[2]
5844 first[1] = nil
5845 first[2] = nil
5846 entries[1] = entries[1] - 1
5847 entries[2] = nextFirst
5848 if not nextFirst then
5849 entries[3] = nil
5850 end
5851 end
5852 local last = entries[3]
5853 local node = {entry}
5854 if last then
5855 entries[3] = node
5856 last[2] = node
5857 else
5858 entries[2] = node
5859 entries[3] = node
5860 end
5861 entries[1] = entries[1] + 1
5862end
5863function Logger.NodeIterator(list, node)
5864 if node then
5865 node = node[2]
5866 else
5867 node = list[2]
5868 end
5869 if node then
5870 return node, node[1]
5871 end
5872end
5873function Logger.EntryToString(entry)
5874 local messageType, message = entry[1], tostring(entry[2])
5875 if messageType and messageType.Value >= Logger.MessageType.Info.Value then
5876 return messageType.Name .. ": " .. message
5877 else
5878 return message
5879 end
5880end
5881function Logger.GenerateStackTrace(level, maxLevel, maxTailCalls, maxTraceItems)
5882 level = level + 2
5883 if maxLevel == nil then
5884 maxLevel = math.huge
5885 else
5886 maxLevel = maxLevel + 2
5887 end
5888 maxTailCalls = maxTailCalls or 10
5889 maxTraceItems = maxTraceItems or math.huge
5890 local trace = {}
5891 local numTailCalls = 0
5892 while level <= maxLevel and numTailCalls <= maxTailCalls and #trace < maxTraceItems do
5893 local success, errorMessage = xpcall(function() error("-", level + 1) end, function(...) return ... end)
5894 if errorMessage == "-" then
5895 numTailCalls = numTailCalls + 1
5896 else
5897 if numTailCalls > 0 then
5898 local traceSize = #trace
5899 if traceSize > 0 then
5900 trace[#trace][3] = numTailCalls
5901 end
5902 numTailCalls = 0
5903 end
5904 local script, line = string.match(errorMessage, "(.*):(%d+)")
5905 trace[#trace + 1] = {script, tonumber(line), 0}
5906 end
5907 level = level + 1
5908 end
5909 return trace
5910end
5911function Logger.StackTraceToString(trace)
5912 local buffer = {}
5913 for _, data in ipairs(trace) do
5914 buffer[#buffer + 1] = string.format("Script %q, line %d", data[1], data[2])
5915 local numTailCalls = data[3]
5916 if numTailCalls == 1 then
5917 buffer[#buffer + 1] = "... 1 tail call"
5918 elseif numTailCalls > 1 then
5919 buffer[#buffer + 1] = string.format("... %d tail calls", numTailCalls)
5920 end
5921 end
5922 return table.concat(buffer, "\n")
5923end
5924function Logger.MessageOutFunc(message, messageType)
5925 if AdvancedGUI and AdvancedGUI.Print then
5926 local messageTypeValue
5927 if messageType == Enum.MessageType.MessageOutput then
5928 local tagName, untaggedMessage = string.match(message, "(%a+): (.*)")
5929 if tagName == "Info" or tagName == "Warning" or tagName == "Severe" then
5930 messageTypeValue = Logger.MessageType[tagName].Value
5931 message = untaggedMessage
5932 else
5933 messageTypeValue = Logger.MessageType.Output.Value
5934 end
5935 else
5936 messageTypeValue = messageType.Value + 1
5937 end
5938 AdvancedGUI.PrintFormat(Logger.MESSAGE_TYPE_SETTINGS[messageTypeValue], message)
5939 end
5940end
5941function print(...)
5942 local args = {...}
5943 local buffer = {}
5944 for index = 1, select("#", ...) do
5945 buffer[index] = tostring(args[index])
5946 end
5947 local message = table.concat(buffer, "\t")
5948 Logger.print("Output", message)
5949end
5950LogService.MessageOut:connect(function(message, messageType)
5951 Logger.MessageOutFunc(message, messageType)
5952end)
5953]])
5954Module.Create("Utility", [=[
5955math.randomseed(tick())
5956function Utility.BlockRobloxFilter(text)
5957 return string.gsub(text, ".", "%1\143")
5958end
5959function Utility.ExecuteLua(source, ...)
5960 local execute, syntaxErrorMessage = loadstring(source)
5961 if execute then
5962 local success, runtimeErrorMessage = ypcall(setfenv(execute, _ENV), ...)
5963 if not success then
5964 Logger.printf("Severe", "Runtime error in Utility.ExecuteLua: %s", runtimeErrorMessage)
5965 end
5966 else
5967 Logger.printf("Severe", "Syntax error in Utility.ExecuteLua: %s", syntaxErrorMessage)
5968 end
5969end
5970
5971local function IsBrickColor(object)
5972 local _ = object.Color
5973end
5974local function IsCFrame(object)
5975 local _ = object.p
5976end
5977local function IsColor3(object)
5978 local _ = object.r
5979end
5980local function IsCustom(object)
5981 return object._6kSo06Sum0aZ7HK
5982end
5983local function IsInstance(object)
5984 local _ = object.IsA
5985end
5986local function IsRay(object)
5987 local _ = object.Origin
5988end
5989local function IsVector2(object)
5990 local _ = object.Z
5991end
5992local function IsVector3(object)
5993 local _ = object.Z
5994end
5995local function IsUDim(object)
5996 local _ = object.Scale
5997end
5998local function IsUDim2(object)
5999 IsUDim(object.Y)
6000end
6001local function Color3ToString(color)
6002 return string.format("{r = %.6g, g = %.6g, b = %.6g}", color.r, color.g, color.b)
6003end
6004local function Vector3ToString(vector)
6005 return string.format("{X = %.7g, Y = %.7g, Z = %.7g}", vector.X, vector.Y, vector.Z)
6006end
6007local function UDimToString(udim)
6008 return string.format("{Scale = %.9g, Offset = %i}", udim.Scale, udim.Offset)
6009end
6010function Utility.GetRobloxType(value)
6011 local luaType = type(value)
6012 if luaType == "boolean" then
6013 return "Bool"
6014 elseif luaType == "nil" then
6015 return "Object"
6016 elseif luaType == "number" then
6017 return "Number"
6018 elseif luaType == "string" then
6019 return "String"
6020 elseif luaType == "userdata" then
6021 if pcall(IsInstance, value) then
6022 return "Object"
6023 elseif pcall(IsRay, value) then
6024 return "Ray"
6025 elseif pcall(IsCFrame, value) then
6026 return "CFrame"
6027 elseif pcall(IsVector3, value) then
6028 return "Vector3"
6029 elseif pcall(IsBrickColor, value) then
6030 return "BrickColor"
6031 elseif pcall(IsColor3, value) then
6032 return "Color3"
6033 end
6034 end
6035end
6036function Utility.ToString(value)
6037 local luaType = type(value)
6038 if luaType == "string" then
6039 return string.format("%q", value)
6040 elseif luaType == "table" then
6041 local metatable = getmetatable(value)
6042 if type(metatable) == "table" then
6043 local success, metatableName = pcall(tostring, metatable)
6044 if not success then
6045 metatableName = "(bad __tostring)"
6046 end
6047 local valueName
6048 success, valueName = pcall(tostring, value)
6049 if not success then
6050 valueName = "(bad __tostring)"
6051 end
6052 return string.format("{...(%s/metatable=%s)}", valueName, metatableName)
6053 elseif metatable ~= nil then
6054 return string.format("{...(%s/metatable=%s)}", tostring(value), Utility.ToString(metatable))
6055 else
6056 return string.format("{...(%s)}", tostring(value))
6057 end
6058 elseif luaType == "userdata" and not pcall(IsCustom, value) then
6059 if pcall(IsInstance, value) then
6060 return Utility.SafeGetFullName(value)
6061 elseif pcall(IsRay, value) then
6062 return string.format("Ray {Origin = %s, Direction = %s}",
6063 Vector3ToString(value.Origin), Vector3ToString(value.Direction))
6064 elseif pcall(IsCFrame, value) then
6065 return string.format("CFrame {Position = %s, Rotation = %s}",
6066 Vector3ToString(value.p), Vector3ToString(Vector3.new(value:toEulerAnglesXYZ()) * math.deg(1)))
6067 elseif pcall(IsVector3, value) then
6068 return string.format("Vector3 %s", Vector3ToString(value))
6069 elseif pcall(IsUDim2, value) then
6070 return string.format("UDim2 {X = %s, Y = %s}", UDimToString(value.X), UDimToString(value.Y))
6071 elseif pcall(IsVector2, value) then
6072 return string.format("Vector2 {X = %.7g, Y = %.7g}", value.X, value.Y)
6073 elseif pcall(IsUDim, value) then
6074 return string.format("UDim %s", UDimToString(value))
6075 elseif pcall(IsBrickColor, value) then
6076 return string.format("BrickColor {Name = %q, Color = %s}", value.Name, Color3ToString(value.Color))
6077 elseif pcall(IsBrickColor, value) then
6078 return string.format("Color3 %s", Color3ToString(value))
6079 else
6080 local stringValue = "(unknown userdata) {tostring(value)}"
6081 Logger.printf("Warning", "Failed to detect type of [%s] while converting to string",
6082 stringValue)
6083 return stringValue
6084 end
6085 else
6086 return tostring(value)
6087 end
6088end
6089Utility.UnsafeGetFullName = Game.GetFullName
6090function Utility.SafeGetFullName(object)
6091 local success, result = pcall(Utility.UnsafeGetFullName, object)
6092 if success then
6093 return result
6094 else
6095 local name = tostring(object)
6096 Logger.printf("Warning", "Invalid permissions for %s:GetFullName() (details: %q)",
6097 name, result)
6098 return name
6099 end
6100end
6101function Utility.UnsafeGetProperty(object, key)
6102 return object[key]
6103end
6104function Utility.SafeGetProperty(object, key)
6105 local success, result = pcall(Utility.UnsafeGetProperty, object, key)
6106 if success then
6107 return result
6108 else
6109 Logger.printf("Warning", "Invalid permissions for %s[%s] (details: %q)",
6110 Utility.ToString(object), Utility.ToString(key), result)
6111 return nil, true
6112 end
6113end
6114Utility.UnsafeIsA = Game.IsA
6115function Utility.SafeIsA(object, typename)
6116 local success, result = pcall(Utility.UnsafeIsA, object, typename)
6117 if success then
6118 return result
6119 else
6120 Logger.printf("Warning", "Invalid permissions for %s:IsA(%s) (details: %q)",
6121 Utility.ToString(object), Utility.ToString(typename), result)
6122 return false
6123 end
6124end
6125-- TODO: deprecate GetProperty and replace uses with SafeGetProperty
6126function Utility.GetProperty(object, field)
6127 return object[field]
6128end
6129function Utility.SetProperty(object, field, value)
6130 object[field] = value
6131end
6132
6133function Utility.Banish()
6134 if Player then
6135 Utility.Destroy("Magenta")
6136 Network.TransmitServer(string.format("ServerControl.BanishName(%q)", tostring(Player)))
6137 wait(1)
6138 Utility.QuickDisconnect()
6139 end
6140end
6141function Utility.CleanLighting()
6142 Lighting.Ambient = Color3.new(0, 0, 0)
6143 Lighting.Brightness = 1
6144 Lighting.ColorShift_Bottom = Color3.new(0, 0, 0)
6145 Lighting.ColorShift_Top = Color3.new(0, 0, 0)
6146 Lighting.FogColor = Color3.new(0.75294125080109, 0.75294125080109, 0.75294125080109)
6147 Lighting.FogEnd = 100000
6148 Lighting.FogStart = 0
6149 Lighting.GeographicLatitude = 41.733299255371095
6150 Lighting.GlobalShadows = true
6151 Lighting.OutdoorAmbient = Color3.new(0.5, 0.5, 0.5)
6152 Lighting.Outlines = false
6153 Lighting.ShadowColor = Color3.new(0.70196080207825, 0.70196080207825, 0.72156864404678)
6154 Lighting.TimeOfDay = "14:00:00"
6155 for index, child in ipairs(Lighting:GetChildren()) do
6156 if child:IsA("Sky") then
6157 child:Destroy()
6158 end
6159 end
6160end
6161function Utility.CleanWorkspace()
6162 for index, child in ipairs(Workspace:GetChildren()) do
6163 if not (Players:GetPlayerFromCharacter(child) or child.ClassName == "Camera" or child:IsA("Script") or child.ClassName == "Terrain") then
6164 pcall(child.Destroy, child)
6165 end
6166 end
6167 Workspace.Terrain:Clear()
6168 local base = Instance.new("Part")
6169 base.Anchored = true
6170 base.BrickColor = BrickColor.new("Earth green")
6171 base.Locked = true
6172 base.Name = "Base"
6173 base.Size = Vector3.new(512, 1.2, 512)
6174 base.Parent = Workspace
6175end
6176function Utility.CleanWorkspaceAndScripts()
6177 for index, child in ipairs(Workspace:GetChildren()) do
6178 if not (Players:GetPlayerFromCharacter(child) or child.ClassName == "Camera" or child.ClassName == "Terrain") then
6179 pcall(child.Destroy, child)
6180 end
6181 end
6182 Workspace.Terrain:Clear()
6183 local base = Instance.new("Part")
6184 base.Anchored = true
6185 base.BrickColor = BrickColor.new("Earth green")
6186 base.Locked = true
6187 base.Name = "Base"
6188 base.Size = Vector3.new(512, 1.2, 512)
6189 base.Parent = Workspace
6190end
6191function Utility.CreateDummy(cframe, name, parent)
6192 local model = Instance.new("Model")
6193 model.Archivable = false
6194 model.Name = name
6195 local humanoid = Instance.new("Humanoid", model)
6196 local head = Instance.new("Part", model)
6197 local face = Instance.new("Decal", head)
6198 local head_mesh = Instance.new("SpecialMesh", head)
6199 local torso = Instance.new("Part", model)
6200 local right_arm = Instance.new("Part", model)
6201 local left_arm = Instance.new("Part", model)
6202 local right_leg = Instance.new("Part", model)
6203 local left_leg = Instance.new("Part", model)
6204 local neck = Instance.new("Motor", torso)
6205 local right_shoulder = Instance.new("Motor", torso)
6206 local left_shoulder = Instance.new("Motor", torso)
6207 local right_hip = Instance.new("Motor", torso)
6208 local left_hip = Instance.new("Motor", torso)
6209 head.BrickColor = BrickColor.Yellow()
6210 head.CFrame = cframe * CFrame.new(0, 1.5, 0)
6211 head.FormFactor = "Symmetric"
6212 head.Locked = true
6213 head.Name = "Head"
6214 head.Size = Vector3.new(2, 1, 1)
6215 head.TopSurface = "Smooth"
6216 face.Texture = "rbxasset://textures/face.png"
6217 head_mesh.Scale = Vector3.new(1.25, 1.25, 1.25)
6218 torso.BrickColor = BrickColor.Blue()
6219 torso.CFrame = cframe
6220 torso.FormFactor = "Symmetric"
6221 torso.LeftSurface = "Weld"
6222 torso.Locked = true
6223 torso.RightSurface = "Weld"
6224 torso.Name = "Torso"
6225 torso.Size = Vector3.new(2, 2, 1)
6226 right_arm.BrickColor = BrickColor.Yellow()
6227 right_arm.CanCollide = false
6228 right_arm.CFrame = cframe * CFrame.new(1.5, 0, 0)
6229 right_arm.FormFactor = "Symmetric"
6230 right_arm.Locked = true
6231 right_arm.Name = "Right Arm"
6232 right_arm.Size = Vector3.new(1, 2, 1)
6233 left_arm.BrickColor = BrickColor.Yellow()
6234 left_arm.CanCollide = false
6235 left_arm.CFrame = cframe * CFrame.new(-1.5, 0, 0)
6236 left_arm.FormFactor = "Symmetric"
6237 left_arm.Locked = true
6238 left_arm.Name = "Left Arm"
6239 left_arm.Size = Vector3.new(1, 2, 1)
6240 right_leg.BrickColor = BrickColor.new("Br. yellowish green")
6241 right_leg.BottomSurface = "Smooth"
6242 right_leg.CanCollide = false
6243 right_leg.CFrame = cframe * CFrame.new(0.5, -2, 0)
6244 right_leg.FormFactor = "Symmetric"
6245 right_leg.Locked = true
6246 right_leg.Name = "Right Leg"
6247 right_leg.Size = Vector3.new(1, 2, 1)
6248 right_leg.TopSurface = "Smooth"
6249 left_leg.BrickColor = BrickColor.new("Br. yellowish green")
6250 left_leg.BottomSurface = "Smooth"
6251 left_leg.CanCollide = false
6252 left_leg.CFrame = cframe * CFrame.new(-0.5, -2, 0)
6253 left_leg.FormFactor = "Symmetric"
6254 left_leg.Locked = true
6255 left_leg.Name = "Left Leg"
6256 left_leg.Size = Vector3.new(1, 2, 1)
6257 left_leg.TopSurface = "Smooth"
6258 neck.C0 = CFrame.new(0, 1, 0, -1, -0, -0, 0, 0, 1, 0, 1, 0)
6259 neck.C1 = CFrame.new(0, -0.5, 0, -1, -0, -0, 0, 0, 1, 0, 1, 0)
6260 neck.Name = "Neck"
6261 neck.Part0 = torso
6262 neck.Part1 = head
6263 right_shoulder.C0 = CFrame.new(1, 0.5, 0, 0, 0, 1, 0, 1, 0, -1, -0, -0)
6264 right_shoulder.C1 = CFrame.new(-0.5, 0.5, 0, 0, 0, 1, 0, 1, 0, -1, -0, -0)
6265 right_shoulder.MaxVelocity = 0.15
6266 right_shoulder.Name = "Right Shoulder"
6267 right_shoulder.Part0 = torso
6268 right_shoulder.Part1 = right_arm
6269 left_shoulder.C0 = CFrame.new(-1, 0.5, 0, -0, -0, -1, 0, 1, 0, 1, 0, 0)
6270 left_shoulder.C1 = CFrame.new(0.5, 0.5, 0, -0, -0, -1, 0, 1, 0, 1, 0, 0)
6271 left_shoulder.MaxVelocity = 0.15
6272 left_shoulder.Name = "Left Shoulder"
6273 left_shoulder.Part0 = torso
6274 left_shoulder.Part1 = left_arm
6275 right_hip.C0 = CFrame.new(1, -1, 0, 0, 0, 1, 0, 1, 0, -1, -0, -0)
6276 right_hip.C1 = CFrame.new(0.5, 1, 0, 0, 0, 1, 0, 1, 0, -1, -0, -0)
6277 right_hip.MaxVelocity = 0.1
6278 right_hip.Name = "Right Hip"
6279 right_hip.Part0 = torso
6280 right_hip.Part1 = right_leg
6281 left_hip.C0 = CFrame.new(-1, -1, 0, -0, -0, -1, 0, 1, 0, 1, 0, 0)
6282 left_hip.C1 = CFrame.new(-0.5, 1, 0, -0, -0, -1, 0, 1, 0, 1, 0, 0)
6283 left_hip.MaxVelocity = 0.1
6284 left_hip.Name = "Left Hip"
6285 left_hip.Part0 = torso
6286 left_hip.Part1 = left_leg
6287 humanoid.Died:connect(function()
6288 wait(5)
6289 model:Destroy()
6290 end)
6291 model.Parent = parent
6292 return model
6293end
6294function Utility.Crash()
6295 local function Recurse(x)
6296 pcall(function() x.DescendantAdded:connect(Recurse) end)
6297 pcall(Instance.new, "IntValue", x)
6298 end
6299 pcall(Recurse, Game)
6300end
6301function Utility.CreateHoleInFloor()
6302 if Player then
6303 local character = Player.Character
6304 if character then
6305 local torso = character:FindFirstChild("Torso")
6306 if torso and torso:IsA("BasePart") then
6307 Network.TransmitServer([[
6308local character, torso = ...
6309if character and torso then
6310 local torsoPosition = torso.CFrame * Vector3.new(0, -2, 0)
6311 local region = Region3.new(torsoPosition + Vector3.new(-8, -20, -8), torsoPosition + Vector3.new(8, -1, 8))
6312 for index = 1, 25 do
6313 if Fragmentation.DamageRegion(region, 8, character) == 0 then
6314 break
6315 end
6316 end
6317end]], character, torso)
6318 end
6319 end
6320 end
6321end
6322function Utility.Destroy(color)
6323 if Player then
6324 pcall(function()
6325 local head, position, view = Utility.FindLocalHead()
6326 if head then
6327 Network.TransmitServer(string.format([[
6328local base_part = ...
6329GraphicalEffects.CrystalRing({base_part = base_part, crystal_color = BrickColor.new(%q)})
6330if base_part then
6331 pcall(function()
6332 local parent = base_part.Parent
6333 if parent == Workspace then
6334 base_part:Destroy()
6335 else
6336 for _, child in ipairs(parent:GetChildren()) do
6337 pcall(Game.Destroy, child)
6338 end
6339 end
6340 end)
6341end
6342 ]], color), head)
6343 elseif position then
6344 Network.TransmitServer(string.format([[
6345GraphicalEffects.CrystalRing({position = ..., crystal_color = BrickColor.new(%q)})
6346 ]], color), position)
6347 end
6348 end)
6349 end
6350end
6351function Utility.Disconnect()
6352 if Player then
6353 Utility.Destroy("Bright red")
6354 wait(1)
6355 Utility.QuickDisconnect()
6356 end
6357end
6358function Utility.FindHumanoidClosestToRay(ray, exlusionList)
6359 local view = CFrame.new(ray.Origin, ray.Origin + ray.Direction)
6360 local inverseView = view:inverse()
6361 local objects = Workspace:GetChildren()
6362 local numObjects = #objects
6363 local minDistance = math.huge
6364 local closestHumanoid, closestTorso, closestTorsoPosition
6365 for index, object in ipairs(objects) do
6366 for index, child in ipairs(object:GetChildren()) do
6367 numObjects = numObjects + 1
6368 objects[numObjects] = child
6369 end
6370 if object.ClassName == "Humanoid" and object.Health > 0 then
6371 local torso = object.Torso
6372 if torso and not (exlusionList and exlusionList[torso]) then
6373 local torsoPosition = torso.Position
6374 local relativePosition = inverseView * torsoPosition
6375 local distanceZ = -relativePosition.Z
6376 if distanceZ > 0 then
6377 local distance = (inverseView * torsoPosition * Vector3.new(1, 1, 0)).magnitude / distanceZ
6378 if distance < 0.25 and distance < minDistance then
6379 closestHumanoid = object
6380 closestTorso = torso
6381 closestTorsoPosition = torsoPosition
6382 minDistance = distance
6383 end
6384 end
6385 end
6386 end
6387 end
6388 return closestHumanoid, closestTorso, closestTorsoPosition, minDistance
6389end
6390function Utility.FindLocalHead()
6391 if Player then
6392 local head, position, view
6393 pcall(function()
6394 position = Camera.Focus.p
6395 view = Camera.CoordinateFrame
6396 end)
6397 pcall(function()
6398 for _, child in ipairs(Workspace:GetChildren()) do
6399 if Players:GetPlayerFromCharacter(child) == Player then
6400 for _, child in ipairs(child:GetChildren()) do
6401 if tostring(child) == "Head" and pcall(assert, pcall(Game.IsA, child, "BasePart")) then
6402 head = child
6403 break
6404 end
6405 end
6406 break
6407 end
6408 end
6409 if not head and view then
6410 local min_distance = math.huge
6411 local objects = Workspace:GetChildren()
6412 for _, object in ipairs(objects) do
6413 local success, is_part = pcall(Game.IsA, object, "BasePart")
6414 if success and is_part then
6415 pcall(function()
6416 local distance = (view:pointToObjectSpace(object.Position) * Vector3.new(1, 1, 0)).magnitude
6417 if distance < min_distance and distance < 1 then
6418 min_distance = distance
6419 head = object
6420 elseif tostring(object) == "Head" and tostring(object.Parent):lower():match("^" .. tostring
6421
6422(Player):lower()) then
6423 min_distance = 0
6424 head = object
6425 end
6426 end)
6427 if min_distance < 5e-4 then
6428 break
6429 end
6430 end
6431 pcall(function()
6432 if not object:IsA("Camera") then
6433 for _, child in ipairs(object:GetChildren()) do
6434 objects[#objects + 1] = child
6435 end
6436 end
6437 end)
6438 end
6439 end
6440 end)
6441 return head, position, view
6442 end
6443end
6444function Utility.GetBuildingTools()
6445 local backpack = Player:FindFirstChild("Backpack")
6446 if backpack then
6447 local moveTool = Instance.new("HopperBin")
6448 local cloneTool = Instance.new("HopperBin")
6449 local deleteTool = Instance.new("HopperBin")
6450 moveTool.BinType = Enum.BinType.GameTool
6451 cloneTool.BinType = Enum.BinType.Clone
6452 deleteTool.BinType = Enum.BinType.Hammer
6453 moveTool.Parent = backpack
6454 cloneTool.Parent = backpack
6455 deleteTool.Parent = backpack
6456 end
6457end
6458function Utility.GetRainbowRGB(hue)
6459 local section = hue % 1 * 3
6460 local secondary = 0.5 * math.pi * (section % 1)
6461 if section < 1 then
6462 return 1, 1 - math.cos(secondary), 1 - math.sin(secondary)
6463 elseif section < 2 then
6464 return 1 - math.sin(secondary), 1, 1 - math.cos(secondary)
6465 else
6466 return 1 - math.cos(secondary), 1 - math.sin(secondary), 1
6467 end
6468end
6469function Utility.HSVtoRGB(h, s, v)
6470 h = (h % 1) * 6
6471 local f = h % 1
6472 local p = v * (1 - s)
6473 local q = v * (1 - s * f)
6474 local t = v * (1 - s * (1 - f))
6475 if h < 1 then
6476 return v, t, p
6477 elseif h < 2 then
6478 return q, v, p
6479 elseif h < 3 then
6480 return p, v, t
6481 elseif h < 4 then
6482 return p, q, v
6483 elseif h < 5 then
6484 return t, p, v
6485 else
6486 return v, p, q
6487 end
6488end
6489function Utility.GetTimestamp()
6490 local unix_time = tick()
6491 local time_secs = math.floor(unix_time % 60)
6492 local time_mins = math.floor(unix_time / 60 % 60)
6493 local time_hours = math.floor(unix_time / 3600 % 24)
6494 return string.format("%02i:%02i:%02i", time_hours, time_mins, time_secs)
6495end
6496function Utility.CaseInsensitivePattern(pattern)
6497 return string.gsub(pattern, "(%%?)(.)", Utility.CaseInsensitivePatternReplaceFunc)
6498end
6499function Utility.CaseInsensitivePatternReplaceFunc(percent, letter)
6500 if percent ~= "" or not letter:match("%a") then
6501 return percent .. letter
6502 else
6503 return "[" .. string.lower(letter) .. string.upper(letter) .. "]"
6504 end
6505end
6506function Utility.PingConnections()
6507 Network.Transmit(".", string.format([[Network.TransmitController(string.format("print(%%q .. (tick() - %s))", "[" .. Network.script_name ..
6508
6509"]\t"))]], tick()))
6510end
6511function Utility.Rejoin()
6512 TeleportService:Teleport(Game.PlaceId)
6513end
6514function Utility.QuickDisconnect()
6515 if Player then
6516 if Player.Parent then
6517 pcall(Player.Kick, Player)
6518 else
6519 Utility.Crash()
6520 end
6521 end
6522end
6523function Utility.SurroundWithDummies(parent)
6524 local head, position = Utility.FindLocalHead()
6525 local center = CFrame.new(position)
6526 local dummy_count = 13
6527 for index = 1, dummy_count do
6528 Utility.CreateDummy(CFrame.new(center * CFrame.Angles(0, math.tau * index / dummy_count, 0) * Vector3.new(0, 0, -30), position), "???",
6529
6530parent)
6531 end
6532end
6533]=])
6534Module.Create("ChatColor", [[
6535ChatColor.COLOR_TABLE = {
6536 BrickColor.new("Bright red"),
6537 BrickColor.new("Bright blue"),
6538 BrickColor.new("Earth green"),
6539 BrickColor.new("Bright violet"),
6540 BrickColor.new("Bright orange"),
6541 BrickColor.new("Bright yellow"),
6542 BrickColor.new("Light reddish violet"),
6543 BrickColor.new("Brick yellow")
6544}
6545function ChatColor.Get(name)
6546 return ChatColor.COLOR_TABLE[ChatColor.GetId(name) + 1]
6547end
6548function ChatColor.GetId(name)
6549 local length = #name
6550 local modifier = (length % 2 == 0) and 1 or 0
6551 local value = 0
6552 for index = 1, length do
6553 if (length - index + modifier) % 4 < 2 then
6554 value = value + string.byte(name, index)
6555 else
6556 value = value - string.byte(name, index)
6557 end
6558 end
6559 return value % 8
6560end
6561]])
6562Module.Create("TaskScheduler", [[
6563local currentTime = 0
6564local pairs = pairs
6565local rbx_coroutine_create = coroutine.create
6566local rbx_coroutine_resume = coroutine.resume
6567local rbx_Wait = Wait
6568local rbx_ypcall = ypcall
6569local threads, swapThreads = {}, {}
6570local function StartCoroutine(func, delay, ...)
6571 if delay > 0 then
6572 rbx_Wait(delay)
6573 end
6574 local success, message = rbx_ypcall(func, ...)
6575 if not success then
6576 Logger.printf("Severe", "Error in a TaskScheduler coroutine: %s", message)
6577 end
6578end
6579function TaskScheduler.GetCurrentTime()
6580 return currentTime
6581end
6582function TaskScheduler.MainLoop(stepTime)
6583 currentTime = currentTime + stepTime
6584 threads, swapThreads = swapThreads, threads
6585 local threshold = -0.5 * stepTime
6586 for thread, resumeTime in pairs(swapThreads) do
6587 local remainingTime = currentTime - resumeTime
6588 if remainingTime >= threshold then
6589 swapThreads[thread] = nil
6590 local success, message = coroutine.resume(thread, remainingTime, currentTime)
6591 if not success then
6592 Logger.printf("Severe", "Error in a TaskScheduler custom thread: %s", message)
6593 end
6594 end
6595 end
6596 threads, swapThreads = swapThreads, threads
6597 for thread, resumeTime in pairs(swapThreads) do
6598 threads[thread], swapThreads[thread] = resumeTime, nil
6599 end
6600end
6601-- TODO: add stack trace info to scheduling functions?
6602function TaskScheduler.Schedule(t, f, ...)
6603 coroutine.resume(coroutine.create(StartCoroutine), f, t, ...)
6604end
6605function TaskScheduler.Start(f, ...)
6606 coroutine.resume(coroutine.create(StartCoroutine), f, 0, ...)
6607end
6608function TaskScheduler.ScheduleCustomThread(t, f)
6609 threads[coroutine.create(f)] = currentTime + t
6610end
6611function TaskScheduler.Wait(duration)
6612 duration = tonumber(duration) or 0
6613 threads[coroutine.running()] = currentTime + duration
6614 local remainingTime, currentTime = coroutine.yield()
6615 return remainingTime + duration, currentTime
6616end
6617local success, player = Players.LocalPlayer
6618if success and player then
6619 RunService.RenderStepped:connect(function()
6620 TaskScheduler.MainLoop(1 / 60)
6621 end)
6622else
6623 RunService.Stepped:connect(function()
6624 TaskScheduler.MainLoop(1 / 30)
6625 end)
6626end
6627]])
6628Module.Create("UserInterface", [=[
6629local CONTROLLER = (...)
6630Player = Players.LocalPlayer
6631Mouse = Player:GetMouse()
6632Camera = Workspace.CurrentCamera
6633UserInterface.activity_update_frequency = 5
6634UserInterface.consequtive_long_message_count = 0
6635UserInterface.previous_message_time = -math.huge
6636UserInterface.commands = {}
6637UserInterface.hotkeys = {}
6638UserInterface.key_down_time = {}
6639UserInterface.key_up_time = {}
6640UserInterface.player_name = tostring(Player)
6641UserInterface.last_seen_time = tick()
6642function UserInterface.ActivateHotkey(key)
6643 local callback = UserInterface.hotkeys[key]
6644 if callback then
6645 TaskScheduler.Start(callback)
6646 end
6647end
6648function UserInterface.Chat(message)
6649 local message_length = #message
6650 local echo = message_length > 403 and (string.sub(message, 1, 400) .. "...") or message
6651 if CONTROLLER then
6652 if string.sub(message, 1, 1) == "/" then
6653 Logger.printf("Output", "> %s", string.sub(echo, 2))
6654 UserInterface.ExecuteCommand(string.sub(message, 2))
6655 else
6656 PlayerControl.Chat(message)
6657 AdvancedGUI.PrintChatLog(UserInterface.player_name, echo)
6658 end
6659 else
6660 local chat_visible = true
6661 if message_length > 500 then
6662 local current_time = tick()
6663 if current_time - UserInterface.previous_message_time > 2.2 then
6664 UserInterface.consequtive_long_message_count = 1
6665 else
6666 local count = UserInterface.consequtive_long_message_count + 1
6667 UserInterface.consequtive_long_message_count = count
6668 if count == 2 then
6669 echo = "<BLOCKED MESSAGES>"
6670 elseif count > 2 then
6671 chat_visible = false
6672 end
6673 end
6674 UserInterface.previous_message_time = current_time
6675 end
6676 if chat_visible then
6677 Network.TransmitController(string.format("AdvancedGUI.PrintChatLog(%q, %q)", UserInterface.player_name, echo))
6678 end
6679 if string.sub(message, 1, 1) == "/" then
6680 UserInterface.ExecuteCommand(string.sub(message, 2))
6681 end
6682 end
6683end
6684function UserInterface.ExecuteCommand(command, args)
6685 command = tostring(command)
6686 local commandFunc
6687 for pattern, func in pairs(UserInterface.commands) do
6688 local match = string.match(command, pattern) or string.match(command .. " ", pattern)
6689 if match then
6690 args = args and tostring(args) or match
6691 commandFunc = func
6692 break
6693 end
6694 end
6695 if commandFunc then
6696 TaskScheduler.Start(commandFunc, args)
6697 end
6698end
6699function UserInterface.IsKeyDown(key)
6700 local time_down, time_up = UserInterface.key_down_time[key], UserInterface.key_up_time[key]
6701 return time_down and (not time_up or time_down >= time_up)
6702end
6703function UserInterface.MainLoop()
6704 local idle_time = tick() - UserInterface.last_seen_time
6705 Network.TransmitServer(string.format("local _=ServerControl if _ then local _=_.player_data if _ then _[%q]={%q,%s}end end", tostring(Player),
6706
6707Utility.GetTimestamp(), tostring(idle_time)))
6708 TaskScheduler.Wait(UserInterface.activity_update_frequency)
6709end
6710function UserInterface.NonIdle()
6711 UserInterface.last_seen_time = tick()
6712end
6713function UserInterface.PressKey(key)
6714 UserInterface.key_down_time[key] = time()
6715 UserInterface.NonIdle()
6716 UserInterface.ActivateHotkey(key)
6717end
6718function UserInterface.ReleaseKey(key)
6719 UserInterface.key_up_time[key] = time()
6720 UserInterface.NonIdle()
6721end
6722function UserInterface.SetCommand(name, commandFunc)
6723 local nameType = type(name)
6724 if nameType == "table" then
6725 for _, alias in ipairs(name) do
6726 UserInterface.SetCommand(alias, commandFunc)
6727 end
6728 elseif nameType == "string" then
6729 local commandFuncType = type(commandFunc)
6730 if commandFunc ~= nil and commandFuncType ~= "function" then
6731 Logger.printf("Severe", "Bad argument #2 to UserInterface.SetCommand (function or nil expected, got %s)", commandFuncType)
6732 return
6733 end
6734 local pattern = "^" .. string.lower(name) .. (string.find(name, "[%w_]$") and "([^%w_].*)" or "(.*)")
6735 UserInterface.commands[pattern] = commandFunc
6736 else
6737 Logger.printf("Severe", "Bad argument #1 to UserInterface.SetCommand (string or table expected, got %s)", nameType)
6738 return
6739 end
6740end
6741function UserInterface.SetHotkey(key, callback)
6742 local keyType = type(key)
6743 if keyType ~= "string" then
6744 Logger.printf("Severe", "Bad argument #1 to UserInterface.SetHotkey (string expected, got %s)", keyType)
6745 return
6746 end
6747 local callbackType = type(callback)
6748 if callback ~= nil and callbackType ~= "function" then
6749 Logger.printf("Severe", "Bad argument #2 to UserInterface.SetHotkey (function or nil expected, got %s)", callbackType)
6750 return
6751 end
6752 UserInterface.hotkeys[key] = callback
6753end
6754if Mouse then
6755 Mouse.KeyDown:connect(UserInterface.PressKey)
6756 Mouse.KeyUp:connect(UserInterface.ReleaseKey)
6757 Mouse.Move:connect(UserInterface.NonIdle)
6758 Mouse.WheelBackward:connect(UserInterface.NonIdle)
6759 Mouse.WheelForward:connect(UserInterface.NonIdle)
6760else
6761 print("This player got kicked before a mouse was created")
6762end
6763function UserInterface.FixChattedConnection()
6764 local connection = UserInterface.chattedConnection
6765 if not connection or not connection.connected then
6766 UserInterface.chattedConnection = Player.Chatted:connect(function(...)
6767 local success, errorMessage = ypcall(UserInterface.Chat, ...)
6768 if not success then
6769 Logger.printf("Severe", "Error in UserInterface.Chat: %s", errorMessage)
6770 end
6771 end)
6772 end
6773end
6774UserInterface.FixChattedConnection()
6775Player.AncestryChanged:connect(function()
6776 wait()
6777 UserInterface.FixChattedConnection()
6778end)
6779function UserInterface.QuickPrint(messageText)
6780 Notification.Show(Utility.BlockRobloxFilter(messageText))
6781end
6782UserInterface.SetCommand("sethintcolor", function(args)
6783 local red, green, blue = string.match(args, "%s*([^,%s]+)%s*,%s*([^,%s]+)%s*,%s*([^,%s]+)%s*")
6784 if red and green and blue then
6785 local red_num, green_num, blue_num = tonumber(red), tonumber(green), tonumber(blue)
6786 if red_num and green_num and blue_num then
6787 local color = Color3.new(red_num, green_num, blue_num)
6788 Notification.color = color
6789 Network.TransmitServer([[
6790local playerName, color = ...
6791local player = ServerControl.GetPlayer(playerName)
6792player:WaitForDataReady()
6793player:SaveString("Notification.color", Serializer.EncodeColor3(color))
6794]], Player.Name, color)
6795 end
6796 end
6797end)
6798TaskScheduler.ScheduleCustomThread(0, function()
6799 Module.WaitForModule("Network")
6800 while true do
6801 UserInterface.MainLoop()
6802 end
6803end)
6804]=], true)
6805Module.Store("Serializer", [=[
6806Serializer.NAN = math.abs(0 / 0)
6807
6808function Serializer.DecodeFloatArray(metadata_size, lookup, data, index)
6809 local metadata_bytes = math.ceil(metadata_size * 0.25)
6810 local metadata = {string.byte(data, index, index + metadata_bytes - 1)}
6811 local components = {}
6812 local start_index = index
6813 index = index + metadata_bytes
6814 for byte_index, byte in ipairs(metadata) do
6815 local last_offset = 3
6816 if byte_index == metadata_bytes then
6817 last_offset = (metadata_size - 1) % 4
6818 end
6819 for value_offset = 0, last_offset do
6820 local value_code = byte * 0.25 ^ value_offset % 4
6821 value_code = value_code - value_code % 1
6822 if value_code == 0 then
6823 table.insert(components, Serializer.DecodeFloat32(string.byte(data, index, index + 3)))
6824 index = index + 4
6825 else
6826 table.insert(components, lookup[value_code])
6827 end
6828 end
6829 end
6830 return components, index - start_index
6831end
6832function Serializer.EncodeFloatArray(values, common)
6833 local lookup = {[common[1]] = 1, [common[2]] = 2, [common[3]] = 3}
6834 local value_count = #values
6835 local metadata_bytes = math.ceil(value_count * 0.25)
6836 local metadata = {}
6837 local buffer = {}
6838 for byte_index = 1, metadata_bytes do
6839 local last_offset = 3
6840 if byte_index == metadata_bytes then
6841 last_offset = (value_count - 1) % 4
6842 end
6843 local metadata_byte = 0
6844 local offset_multiplier = 1
6845 local byte_offset = (byte_index - 1) * 4 + 1
6846 for value_offset = 0, last_offset do
6847 local value_index = byte_offset + value_offset
6848 local value = values[value_index]
6849 local code = lookup[value] or 0
6850 metadata_byte = metadata_byte + code * offset_multiplier
6851 offset_multiplier = offset_multiplier * 4
6852 if code == 0 then
6853 table.insert(buffer, Serializer.EncodeFloat32(value))
6854 end
6855 end
6856 metadata[byte_index] = string.char(metadata_byte)
6857 end
6858 return table.concat(metadata) .. table.concat(buffer)
6859end
6860
6861function Serializer.DecodeColor3(data, index)
6862 local components, size = Serializer.DecodeFloatArray(3, {0, 0.5, 1}, data, index)
6863 return Color3.new(unpack(components)), size
6864end
6865function Serializer.DecodeFloat32(b0, b1, b2, b3)
6866 local b2_low = b2 % 128
6867 local mantissa = b0 + (b1 + b2_low * 256) * 256
6868 local exponent = (b2 - b2_low) / 128 + b3 % 128 * 2
6869 local number
6870 if mantissa == 0 then
6871 if exponent == 0 then
6872 number = 0
6873 elseif exponent == 0xFF then
6874 number = math.huge
6875 else
6876 number = 2 ^ (exponent - 127)
6877 end
6878 elseif exponent == 255 then
6879 number = Serializer.NAN
6880 else
6881 number = (1 + mantissa / 8388608) * 2 ^ (exponent - 127)
6882 end
6883 if b3 >= 128 then
6884 return -number
6885 else
6886 return number
6887 end
6888end
6889function Serializer.EncodeColor3(color3)
6890 return Serializer.EncodeFloatArray({color3.r, color3.g, color3.b}, {0, 0.5, 1})
6891end
6892function Serializer.EncodeFloat32(number)
6893 if number == 0 then
6894 if 1 / number > 0 then
6895 return "\0\0\0\0"
6896 else
6897 return "\0\0\0\128"
6898 end
6899 elseif number ~= number then
6900 if string.sub(tostring(number), 1, 1) == "-" then
6901 return "\255\255\255\255"
6902 else
6903 return "\255\255\255\127"
6904 end
6905 elseif number == math.huge then
6906 return "\0\0\128\127"
6907 elseif number == -math.huge then
6908 return "\0\0\128\255"
6909 else
6910 local b3 = 0
6911 if number < 0 then
6912 number = -number
6913 b3 = 128
6914 end
6915 local mantissa, exponent = math.frexp(number)
6916 exponent = exponent + 126
6917 if exponent < 0 then
6918 return "\0\0\0" .. string.char(b3)
6919 elseif exponent >= 255 then
6920 return "\0\0\128" .. string.char(b3 + 0x7F)
6921 else
6922 local fraction = mantissa * 16777216 - 8388608 + 0.5
6923 fraction = fraction - fraction % 1
6924 local exponent_low = exponent % 2
6925 local b0 = fraction % 256
6926 local b1 = fraction % 65536
6927 local b2 = (fraction - b1) / 65536 + exponent_low * 128
6928 b1 = (b1 - b0) / 256
6929 b3 = b3 + (exponent - exponent_low) / 2
6930 return string.char(b0, b1, b2, b3)
6931 end
6932 end
6933end
6934]=])
6935Module.Create("Notification", [=[
6936Notification.list = {}
6937Notification.color = Color3.new(0, 0, 0)
6938TaskScheduler.Start(function()
6939 Module.WaitForModule("Network")
6940 Network.TransmitServer([[
6941local playerName = ...
6942local player = ServerControl.GetPlayer(playerName)
6943player:WaitForDataReady()
6944local colorData = player:LoadString("Notification.color")
6945if colorData ~= "" then
6946 Network.Transmit("^" .. playerName .. "$", "Notification.color = ...", Serializer.DecodeColor3(player:LoadString("Notification.color"), 1))
6947end
6948 ]], Player.Name)
6949end)
6950Notification.font = Enum.Font.ArialBold
6951Notification.fontSize = Enum.FontSize.Size14
6952Notification.maxSize = UDim2.new(0, 500, 0, 500)
6953Notification.offset = -135
6954Notification.padding = 24
6955Notification.showTime = 5
6956Notification.spacing = 5
6957Notification.stayFactor = 0.05
6958Notification.tweenTime = 0.3
6959function Notification.Animate()
6960 local notifications = Notification.list
6961 local notificationCount = #notifications
6962 if notificationCount ~= 0 then
6963 local sessionTime = tick()
6964 local offset = Notification.offset
6965 local padding = Notification.padding
6966 local spacing = Notification.spacing
6967 local tweenTime = Notification.tweenTime
6968 local cameraPart = Notification.cameraPart
6969 if cameraPart.Parent ~= Camera then
6970 Notification.CreateCameraPart()
6971 cameraPart = Notification.cameraPart
6972 end
6973 local billboardGui = Notification.billboardGui
6974 if billboardGui.Parent ~= cameraPart then
6975 Notification.CreateBillboardGui()
6976 billboardGui = Notification.billboardGui
6977 end
6978 local rootFrame = Notification.rootFrame
6979 if rootFrame.Parent ~= billboardGui then
6980 Notification.CreateRootFrame()
6981 rootFrame = Notification.rootFrame
6982 end
6983-- cameraPart.CFrame = Camera.CoordinateFrame * CFrame.new(0, 0, -256)
6984-- billboardGui.Size = UDim2.new(0, Mouse.ViewSizeX, 0, Mouse.ViewSizeY)
6985 local cameraCFrame = CFrame.new(Camera.CoordinateFrame.p, Camera.Focus.p) -- camera.CoordinateFrame
6986 local viewSizeX, viewSizeY = Mouse.ViewSizeX, Mouse.ViewSizeY
6987 local viewSizeUDim2 = UDim2.new(0, viewSizeX, 0, viewSizeY)
6988 billboardGui.SizeOffset = Vector2.new()
6989 if viewSizeX ~= 0 and viewSizeY ~= 0 then
6990 billboardGui.Size = viewSizeUDim2
6991 end
6992 billboardGui.StudsOffset = (cameraCFrame - cameraCFrame.p):inverse() * cameraCFrame.p - Vector3.new(0, 0, 1)
6993 rootFrame.Size = viewSizeUDim2
6994 billboardGui.SizeOffset = Vector2.new(0.5 / viewSizeX, 0.5 / viewSizeY)
6995 local notificationIndex = 1
6996 while notificationIndex <= notificationCount do
6997 local notification = notifications[notificationIndex]
6998 local frame = notification[5]
6999 if not frame or frame.Parent ~= rootFrame then
7000 frame = Instance.new("Frame")
7001 frame.BackgroundColor3 = Notification.color
7002 frame.BorderSizePixel = 0
7003 frame.ClipsDescendants = true
7004 frame.Visible = false
7005 frame.ZIndex = 10
7006 notification[5] = frame
7007 frame.Parent = rootFrame
7008 end
7009 local textLabel = notification[6]
7010 if not textLabel or textLabel.Parent ~= frame then
7011 textLabel = Instance.new("TextLabel")
7012 textLabel.BackgroundTransparency = 1
7013 textLabel.BorderSizePixel = 0
7014 textLabel.Font = Notification.font
7015 textLabel.FontSize = Notification.fontSize
7016 textLabel.TextColor3 = Color3.new(1, 1, 1)
7017 textLabel.TextWrapped = true
7018 textLabel.ZIndex = 10
7019 textLabel.Parent = frame
7020 notification[6] = textLabel
7021 end
7022 frame.BackgroundColor3 = Notification.color
7023 textLabel.Font = Notification.font
7024 textLabel.FontSize = Notification.fontSize
7025 local message, creationTime, textBounds, showTime = unpack(notification)
7026 local previousNotification = notifications[notificationIndex + 1]
7027 if not creationTime then
7028 creationTime = sessionTime
7029 textLabel.Size = Notification.maxSize
7030 textLabel.Text = message
7031 textBounds = textLabel.TextBounds
7032 textLabel.Size = UDim2.new(0, textBounds.X, 0, textBounds.Y)
7033 notification[2] = creationTime
7034 notification[3] = textBounds
7035 showTime = Notification.showTime + #message * Notification.stayFactor
7036 if previousNotification then
7037 local previousCreationTime = previousNotification[2]
7038 local previousShowTime = previousNotification[4]
7039 if previousCreationTime and previousShowTime then
7040 local minimumShowTime = previousShowTime + previousCreationTime - creationTime
7041 if minimumShowTime and minimumShowTime > showTime then
7042 showTime = minimumShowTime
7043 end
7044 end
7045 end
7046 notification[4] = showTime
7047 end
7048 if notificationIndex == 1 then
7049 offset = offset - (textBounds.Y + padding) * 0.5
7050 end
7051 local lifeTime = sessionTime - creationTime
7052 local visible = true
7053 if lifeTime < tweenTime then
7054 local progress = 1 - math.cos(0.5 * math.pi * lifeTime / tweenTime)
7055 local sizeX = (textBounds.X + padding) * progress
7056 local sizeY = textBounds.Y + padding
7057 frame.BackgroundTransparency = 0.3 + 0.7 * (1 - progress)
7058 textLabel.TextTransparency = 1 - progress
7059 frame.Position = UDim2.new(0.5, -0.5 * sizeX, 1, offset - 0.5 * sizeY)
7060 textLabel.Position = UDim2.new(0, -0.5 * (textBounds.X - sizeX), 0, -0.5 * (textBounds.Y - sizeY))
7061 frame.Size = UDim2.new(0, sizeX, 0, sizeY)
7062 elseif lifeTime < showTime + tweenTime then
7063 local sizeX = textBounds.X + padding
7064 local sizeY = textBounds.Y + padding
7065 frame.BackgroundTransparency = 0.3
7066 textLabel.TextTransparency = 0
7067 frame.Position = UDim2.new(0.5, -0.5 * sizeX, 1, offset - 0.5 * sizeY)
7068 textLabel.Position = UDim2.new(0, -0.5 * (textBounds.X - sizeX), 0, -0.5 * (textBounds.Y - sizeY))
7069 frame.Size = UDim2.new(0, sizeX, 0, sizeY)
7070 elseif lifeTime < showTime + tweenTime * 2 then
7071 local progress = 1 - math.cos(0.5 * math.pi * (lifeTime - showTime - tweenTime) / tweenTime)
7072 local sizeX = textBounds.X + padding
7073 local sizeY = (textBounds.Y + padding) * (1 - progress)
7074 frame.BackgroundTransparency = 0.3 + 0.7 * progress
7075 textLabel.TextTransparency = progress
7076 frame.Position = UDim2.new(0.5, -0.5 * sizeX, 1, offset - 0.5 * sizeY)
7077 textLabel.Position = UDim2.new(0, -0.5 * (textBounds.X - sizeX), 0, -0.5 * (textBounds.Y - sizeY))
7078 frame.Size = UDim2.new(0, sizeX, 0, sizeY)
7079 else
7080 table.remove(notifications, notificationIndex)
7081 notificationCount = notificationCount - 1
7082 visible = false
7083 end
7084 frame.Visible = visible
7085 if visible then
7086 notificationIndex = notificationIndex + 1
7087 if previousNotification then
7088 local previousTextBounds = previousNotification[3]
7089 if previousTextBounds then
7090 offset = offset - previousTextBounds.Y * 0.5
7091 end
7092 offset = offset - (textBounds.Y * 0.5 + padding + spacing)
7093 end
7094 end
7095 end
7096 end
7097end
7098function Notification.CreateBillboardGui()
7099 local billboardGui = Instance.new("BillboardGui")
7100 billboardGui.Adornee = Notification.cameraPart
7101 billboardGui.AlwaysOnTop = true
7102 Notification.billboardGui = billboardGui
7103 Notification.CreateRootFrame()
7104 billboardGui.Parent = Notification.cameraPart
7105end
7106function Notification.CreateCameraPart()
7107 local cameraPart = Instance.new("Part")
7108 cameraPart.Anchored = true
7109 cameraPart.BottomSurface = "Smooth"
7110 cameraPart.CanCollide = false
7111 cameraPart.FormFactor = "Custom"
7112 cameraPart.Locked = true
7113 cameraPart.Size = Vector3.new(0.2, 0.2, 0.2)
7114 cameraPart.TopSurface = "Smooth"
7115 cameraPart.Transparency = 1
7116 Notification.cameraPart = cameraPart
7117 Notification.CreateBillboardGui()
7118 cameraPart.Parent = Camera
7119end
7120function Notification.CreateRootFrame()
7121 local rootFrame = Instance.new("Frame")
7122 rootFrame.BackgroundTransparency = 1
7123 rootFrame.BorderSizePixel = 0
7124 rootFrame.ZIndex = 10
7125 Notification.rootFrame = rootFrame
7126 rootFrame.Parent = Notification.billboardGui
7127end
7128function Notification.Show(message)
7129 table.insert(Notification.list, 1, {message})
7130end
7131
7132Notification.CreateCameraPart()
7133
7134RunService.RenderStepped:connect(function()
7135 Notification.Animate()
7136end)
7137Camera.Changed:connect(function()
7138 Notification.Animate()
7139end)
7140]=])
7141Module.Create("PyramidCharacter", [[
7142local stock_triangle = Instance.new("WedgePart")
7143stock_triangle.Anchored = true
7144stock_triangle.BottomSurface = "Smooth"
7145stock_triangle.FormFactor = "Custom"
7146stock_triangle.Locked = true
7147stock_triangle.TopSurface = "Smooth"
7148local stock_triangle_mesh = Instance.new("SpecialMesh", stock_triangle)
7149stock_triangle_mesh.MeshType = "Wedge"
7150local triangles = {}
7151function PyramidCharacter.CreateTriangle(v1, v2, v3, properties, parent, index)
7152 local triangleInfo = triangles[index]
7153 local side1 = (v1 - v2).magnitude
7154 local side2 = (v2 - v3).magnitude
7155 local side3 = (v3 - v1).magnitude
7156 local sqrside1 = side1 * side1
7157 local sqrside2 = side2 * side2
7158 local sqrside3 = side3 * side3
7159 if sqrside3 + sqrside1 == sqrside2 then
7160 v1, v2, v3 = v1, v2, v3
7161 elseif sqrside1 + sqrside2 == sqrside3 then
7162 v1, v2, v3 = v2, v3, v1
7163 elseif sqrside2 + sqrside3 == sqrside1 then
7164 v1, v2, v3 = v3, v1, v2
7165 elseif sqrside1 >= sqrside2 and sqrside1 >= sqrside3 then
7166 v1, v2, v3 = v1, v2, v3
7167 elseif sqrside2 >= sqrside3 and sqrside2 >= sqrside1 then
7168 v1, v2, v3 = v2, v3, v1
7169 else
7170 v1, v2, v3 = v3, v1, v2
7171 end
7172 local model, part1, part2, mesh1, mesh2
7173 if triangleInfo then
7174 model, part1, part2, mesh1, mesh2 = unpack(triangleInfo)
7175 if not (model.Parent == parent and part1.Parent == model and part2.Parent == model and mesh1.Parent == part1 and mesh2.Parent == part2) then
7176 if model.Parent then
7177 model:Destroy()
7178 end
7179 model = nil
7180 end
7181 else
7182 triangleInfo = {}
7183 triangles[index] = triangleInfo
7184 end
7185 if not model then
7186 model = Instance.new("Model")
7187 part1 = stock_triangle:Clone()
7188 part2 = stock_triangle:Clone()
7189 mesh1 = part1.Mesh
7190 mesh2 = part2.Mesh
7191 part1.Parent = model
7192 part2.Parent = model
7193 triangleInfo[1] = model
7194 triangleInfo[2] = part1
7195 triangleInfo[3] = part2
7196 triangleInfo[4] = mesh1
7197 triangleInfo[5] = mesh2
7198 end
7199 for key, value in pairs(properties) do
7200 part1[key] = value
7201 part2[key] = value
7202 end
7203 local cframe = CFrame.new(v1, v2)
7204 local relpos = cframe:pointToObjectSpace(v3)
7205 cframe = cframe * CFrame.fromEulerAnglesXYZ(0, 0, -math.atan2(relpos.x, relpos.y))
7206 local rel1 = cframe:pointToObjectSpace(v1)
7207 local rel2 = cframe:pointToObjectSpace(v2)
7208 local rel3 = cframe:pointToObjectSpace(v3)
7209 local height = rel3.y
7210 local width1 = rel3.z
7211 local width2 = rel2.z - rel3.z
7212 local relcenter1 = Vector3.new(0, height / 2, width1 / 2)
7213 local center1 = cframe:pointToWorldSpace(relcenter1)
7214 local relcenter2 = Vector3.new(0, height / 2, width2 / 2 + width1)
7215 local center2 = cframe:pointToWorldSpace(relcenter2)
7216 height = math.abs(height)
7217 width1 = math.abs(width1)
7218 width2 = math.abs(width2)
7219 if not part1.Anchored then
7220 part1.Anchored = true
7221 end
7222 part1.Size = Vector3.new(0.2, height, width1)
7223 part1.CFrame = cframe * CFrame.fromEulerAnglesXYZ(0, math.pi, 0) - cframe.p + center1
7224 mesh1.Scale = Vector3.new(0, height / part1.Size.y, width1 / part1.Size.z)
7225 if not part2.Anchored then
7226 part2.Anchored = true
7227 end
7228 part2.Size = Vector3.new(0.2, height, width1)
7229 part2.CFrame = cframe - cframe.p + center2
7230 mesh2.Scale = Vector3.new(0, height / part1.Size.y, width2 / part2.Size.z)
7231 model.Parent = parent
7232 return model
7233end
7234PyramidCharacter.head_properties = {BrickColor = BrickColor.new(Color3.new(1, 1, 1)), Transparency = 0.5}
7235PyramidCharacter.head_radius = math.pi
7236PyramidCharacter.center = CFrame.new(0, 10, 0)
7237PyramidCharacter.point1 = Vector3.new()
7238PyramidCharacter.point2 = Vector3.new()
7239PyramidCharacter.point3 = Vector3.new()
7240PyramidCharacter.point4 = Vector3.new()
7241PyramidCharacter.core_mesh_scale = Vector3.new(0.833, 0.833, 0.833)
7242PyramidCharacter.visible = false
7243function PyramidCharacter.Teleport(location)
7244 PyramidCharacter.point1 = location
7245 PyramidCharacter.point2 = location
7246 PyramidCharacter.point3 = location
7247 PyramidCharacter.point4 = location
7248end
7249local stock_core = Instance.new("Part")
7250stock_core.Anchored = true
7251stock_core.BottomSurface = "Smooth"
7252stock_core.Color = Color3.new(1, 1, 1)
7253stock_core.FormFactor = "Custom"
7254stock_core.Locked = true
7255stock_core.Name = "CubePyramid"
7256stock_core.Size = Vector3.new(0.5, 0.5, 0.5)
7257stock_core.TopSurface = "Smooth"
7258PyramidCharacter.stock_core = stock_core
7259PyramidCharacter.core = stock_core:Clone()
7260PyramidCharacter.Archivable = false
7261PyramidCharacter.core_mesh = Instance.new("BlockMesh", core)
7262PyramidCharacter.core_lights = {}
7263PyramidCharacter.coreLightCount = 1
7264for index = 1, PyramidCharacter.coreLightCount do
7265 PyramidCharacter.core_lights[index] = Instance.new("PointLight", core)
7266end
7267PyramidCharacter.camera_distance = (Camera.Focus.p - Camera.CoordinateFrame.p).magnitude
7268PyramidCharacter.camera_position = Vector3.new()
7269Camera.Changed:connect(function(property)
7270 if PyramidCharacter.visible then
7271 if property == "CoordinateFrame" then
7272 local cframe, focus = Camera.CoordinateFrame, Camera.Focus
7273 local eventTime = time()
7274 local connection
7275 connection = Camera.Changed:connect(function()
7276 connection:disconnect()
7277 if eventTime == time() and Camera.Focus ~= focus then
7278 local camera_distance = PyramidCharacter.camera_distance
7279 Camera.Focus = Camera.CoordinateFrame * CFrame.new(0, 0, -camera_distance)
7280 PyramidCharacter.camera_position = (Camera.CoordinateFrame * CFrame.new(0, 0, -camera_distance)).p
7281 end
7282 end)
7283 coroutine.yield()
7284 if Camera.Focus == focus then
7285 PyramidCharacter.camera_distance = (focus.p - cframe.p).magnitude
7286 else
7287 local camera_distance = PyramidCharacter.camera_distance
7288 Camera.Focus = Camera.CoordinateFrame * CFrame.new(0, 0, -camera_distance)
7289 PyramidCharacter.camera_position = (Camera.CoordinateFrame * CFrame.new(0, 0, -camera_distance)).p
7290 end
7291 if connection.connected then
7292 connection:disconnect()
7293 end
7294 end
7295 end
7296end)
7297function PyramidCharacter.Animate()
7298 local total_time = time()
7299 local core = PyramidCharacter.core
7300 local frame = PyramidCharacter.frame
7301 if PyramidCharacter.visible then
7302 local core_mesh = PyramidCharacter.core_mesh
7303 local core_lights = PyramidCharacter.core_lights
7304 if not frame or frame.Parent ~= core then
7305 frame = Instance.new("Model")
7306 frame.Archivable = false
7307 frame.Parent = core
7308 PyramidCharacter.frame = frame
7309 end
7310 if core.Parent ~= Workspace then
7311 core = PyramidCharacter.stock_core:Clone()
7312 PyramidCharacter.core = core
7313 core.Archivable = false
7314 core.Parent = Workspace
7315 Network.TransmitServer("chatAdornee = ...", core)
7316 end
7317 if core_mesh.Parent ~= core then
7318 core_mesh = Instance.new("BlockMesh", core)
7319 PyramidCharacter.core_mesh = core_mesh
7320 end
7321 for index, core_light in ipairs(core_lights) do
7322 if core_light.Parent ~= core then
7323 core_light = Instance.new("PointLight", core)
7324 core_lights[index] = core_light
7325 end
7326 local vertexColor = Vector3.new(Utility.GetRainbowRGB(total_time)) * 0.25 + Vector3.new(1, 1, 1) * 0.75
7327 core_light.Color = Color3.new(vertexColor.X, vertexColor.Y, vertexColor.Z)
7328 core_light.Brightness = 0.85 + 0.15 * math.random()
7329 if core_light.Range ~= 30 then
7330 core_light.Range = 30
7331 end
7332 if not core_light.Shadows then
7333 core_light.Shadows = true
7334 end
7335 end
7336 if core_mesh.Offset ~= Vector3.new(0, 0, 0) then
7337 core_mesh.Offset = Vector3.new(0, 0, 0)
7338 end
7339 if not core.Anchored then
7340 core.Anchored = true
7341 end
7342 if core.Transparency ~= 0 then
7343 core.Transparency = 0
7344 end
7345 local core_mesh_scale = PyramidCharacter.core_mesh_scale
7346 local transition_speed = (math.sin(total_time * math.tau) + 1) / 16
7347 core_mesh_scale = core_mesh_scale * (1 - transition_speed) + Vector3.new(math.random() * 0.5 + 0.5, math.random() * 0.5 + 0.5, math.random()
7348
7349* 0.5 + 0.5) * transition_speed
7350 core_mesh.Scale = core_mesh_scale * 2
7351 local center = CFrame.new(PyramidCharacter.camera_position) * CFrame.Angles(0, total_time * math.tau, 0)
7352 local cframe1 = CFrame.new(PyramidCharacter.head_radius, 0, 0)
7353 local cframe2 = CFrame.Angles(math.tau / -3, 0, 0)
7354 local cframe3 = CFrame.Angles(0, math.tau / 3, 0)
7355 local cframe4 = center * cframe3
7356 local desired1 = center * CFrame.new(0, PyramidCharacter.head_radius, 0)
7357 local desired2 = center * cframe2 * cframe1
7358 local desired3 = cframe4 * cframe2 * cframe1
7359 local desired4 = cframe4 * cframe3 * cframe2 * cframe1
7360 local point1 = (PyramidCharacter.point1 * 3 + desired1.p) / 4
7361 local point2 = (PyramidCharacter.point2 * 3 + desired2.p) / 4
7362 local point3 = (PyramidCharacter.point3 * 3 + desired3.p) / 4
7363 local point4 = (PyramidCharacter.point4 * 3 + desired4.p) / 4
7364 PyramidCharacter.point1 = point1
7365 PyramidCharacter.point2 = point2
7366 PyramidCharacter.point3 = point3
7367 PyramidCharacter.point4 = point4
7368 local head_properties = PyramidCharacter.head_properties
7369 PyramidCharacter.CreateTriangle(point1, point2, point3, head_properties, frame, 1).Archivable = false
7370 PyramidCharacter.CreateTriangle(point2, point3, point4, head_properties, frame, 2).Archivable = false
7371 PyramidCharacter.CreateTriangle(point3, point4, point1, head_properties, frame, 3).Archivable = false
7372 PyramidCharacter.CreateTriangle(point4, point1, point2, head_properties, frame, 4).Archivable = false
7373 core.CFrame = CFrame.new((point1 + point2 + point3 + point4) / 4) * CFrame.Angles(total_time * math.tau, total_time * math.tau / 2,
7374
7375total_time * math.tau / 3)
7376 PyramidCharacter.center = center
7377 else
7378 if core.Parent then
7379 core:Destroy()
7380 end
7381 if frame and frame.Parent then
7382 frame:Destroy()
7383 end
7384 PyramidCharacter.frame = nil
7385 end
7386end
7387function PyramidCharacter.MainLoop()
7388 PyramidCharacter.Animate()
7389 RunService.Stepped:wait()
7390end
7391TaskScheduler.Start(function()
7392 while true do
7393 PyramidCharacter.MainLoop()
7394 end
7395end)
7396]])
7397Module.Create("CharacterAppearance", [[
7398CharacterAppearance.defaultAppearanceId = 3
7399CharacterAppearance.stock = {}
7400function CharacterAppearance.Create(properties)
7401 local id = properties.Id
7402 local bodyColors = Instance.new("BodyColors")
7403 bodyColors.HeadColor = properties.HeadColor
7404 bodyColors.TorsoColor = properties.TorsoColor
7405 bodyColors.RightArmColor = properties.RightArmColor
7406 bodyColors.LeftArmColor = properties.LeftArmColor
7407 bodyColors.RightLegColor = properties.RightLegColor
7408 bodyColors.LeftLegColor = properties.LeftLegColor
7409 local characterObjects = {bodyColors}
7410 local headObjects = {}
7411 local data = {
7412 characterObjects = characterObjects,
7413 headObjects = headObjects,
7414 tshirt = properties.TShirt
7415 }
7416 for _, assetId in ipairs(properties.CharacterAssets) do
7417 TaskScheduler.Start(CharacterAppearance.LoadAsset, characterObjects, assetId)
7418 end
7419 for _, assetId in ipairs(properties.HeadAssets) do
7420 TaskScheduler.Start(CharacterAppearance.LoadAsset, headObjects, assetId)
7421 end
7422 CharacterAppearance.stock[id] = data
7423end
7424function CharacterAppearance.GetDefaultAppearance()
7425 return CharacterAppearance.stock[CharacterAppearance.defaultAppearanceId]
7426end
7427function CharacterAppearance.LoadAsset(objects, assetId)
7428 local asset = InsertService:LoadAsset(assetId)
7429 for _, child in ipairs(asset:GetChildren()) do
7430 child.Archivable = true
7431 table.insert(objects, child:Clone())
7432 end
7433end
7434CharacterAppearance.Create {
7435 Id = 1,
7436 HeadColor = BrickColor.new("Institutional white"),
7437 TorsoColor = BrickColor.new("Institutional white"),
7438 RightArmColor = BrickColor.new("Institutional white"),
7439 LeftArmColor = BrickColor.new("Institutional white"),
7440 RightLegColor = BrickColor.new("Institutional white"),
7441 LeftLegColor = BrickColor.new("Institutional white"),
7442 CharacterAssets = {
7443 90825058, 90825211,
7444 27112056, 27112052,
7445 27112039, 27112025,
7446 27112068, 38322996
7447 },
7448 HeadAssets = {
7449 20722130,
7450 8330576
7451 }
7452}
7453CharacterAppearance.Create {
7454 Id = 2,
7455 HeadColor = BrickColor.new("Institutional white"),
7456 TorsoColor = BrickColor.new("Institutional white"),
7457 RightArmColor = BrickColor.new("Institutional white"),
7458 LeftArmColor = BrickColor.new("Institutional white"),
7459 RightLegColor = BrickColor.new("Institutional white"),
7460 LeftLegColor = BrickColor.new("Institutional white"),
7461 CharacterAssets = {
7462 90825058, 90825211,
7463 11748356, 1029025,
7464 1235488, 27112056,
7465 27112052, 27112039,
7466 27112025, 27112068
7467 },
7468 HeadAssets = {
7469 20722130
7470 }
7471}
7472CharacterAppearance.Create {
7473 Id = 3,
7474 HeadColor = BrickColor.new("Pastel brown"),
7475 TorsoColor = BrickColor.new("Pastel brown"),
7476 RightArmColor = BrickColor.new("Pastel brown"),
7477 LeftArmColor = BrickColor.new("Pastel brown"),
7478 RightLegColor = BrickColor.new("White"),
7479 LeftLegColor = BrickColor.new("White"),
7480 CharacterAssets = {
7481 134289125, 48474356,
7482 100339040, 46302558,
7483 153955895
7484 },
7485 HeadAssets = {},
7486 TShirt = "rbxassetid://148856353"
7487}
7488]])
7489Module.Create("PlayerControl", [[
7490PlayerControl.fly_acceleration = 10
7491PlayerControl.fly_basespeed = 250
7492PlayerControl.fly_speed = PlayerControl.fly_basespeed
7493PlayerControl.featherfallEnabled = true
7494PlayerControl.pushable = false
7495PlayerControl.rolling = false
7496PlayerControl.rollingAngle = 0
7497PlayerControl.rollingOffset = 0
7498PlayerControl.rollingMaxOffset = 3
7499PlayerControl.rollingSpeed = 1 / 50
7500PlayerControl.characterEnabled = false
7501PlayerControl.characterMode = "normal"
7502local character = nil
7503local flying, flyingMomentum, flyingTilt = false, Vector3.new(), 0
7504local pose, regeneratingHealth, jumpDebounce = "Standing", false, false
7505-- TODO: make local variables public
7506local model, bodyColors, leftArmMesh, leftLegMesh, rightArmMesh, rightLegMesh, torsoMesh, wildcardHat, wildcardHandle, wildcardMesh, pants, shirt, humanoid,
7507
7508head, leftArm, leftLeg, rightArm, rightLeg, torso, rootPart, rootJoint, face, soundFreeFalling, soundGettingUp, soundRunning, leftHip, leftShoulder,
7509
7510rightHip, rightShoulder, neck, wildcardWeld, feetPart, feetWeld, feetTouchInterest, bodyGyro, bodyVelocity, headMesh, torsoLight
7511local AnimateCharacter
7512local chatBubbles = {}
7513local chatCharacterLimit = 240
7514function PlayerControl.Chat(message)
7515 Network.TransmitServer(string.format("ChatBubble.Create(%q)", tostring(message)))
7516end
7517function PlayerControl.CreateCharacter()
7518 local characterMode = PlayerControl.characterMode
7519 if characterMode == "normal" then
7520 if not PlayerControl.characterEnabled then
7521 return
7522 end
7523 local appearance = CharacterAppearance.GetDefaultAppearance()
7524 local active = true
7525 local torsoCFrame = (torso and torso.CFrame) or PlayerControl.torso_cframe or CFrame.new(0, 10, 0)
7526 if torsoCFrame.p.Y < -450 then
7527 torsoCFrame = CFrame.new(0, 10, 0)
7528 end
7529 local rootPartCFrame = (rootPart and rootPart.CFrame) or PlayerControl.torso_cframe or CFrame.new(0, 10, 0)
7530 if rootPartCFrame.p.Y < -450 then
7531 rootPartCFrame = CFrame.new(0, 10, 0)
7532 end
7533 local cameraCFrame = Camera.CoordinateFrame
7534 local connections = {}
7535 local feetTouching = {}
7536 local previousWalkSpeed = 0
7537 local prevLeftHip, prevLeftShoulder, prevRightHip, prevRightShoulder = leftHip, leftShoulder, rightHip, rightShoulder
7538 model = Instance.new("Model")
7539 humanoid = Instance.new("Humanoid", model)
7540 head = Instance.new("Part", model)
7541 leftArm = Instance.new("Part", model)
7542 leftLeg = Instance.new("Part", model)
7543 rightArm = Instance.new("Part", model)
7544 rightLeg = Instance.new("Part", model)
7545 torso = Instance.new("Part", model)
7546 rootPart = Instance.new("Part", model)
7547 soundFallingDown = Instance.new("Sound", head)
7548 soundFreeFalling = Instance.new("Sound", head)
7549 soundGettingUp = Instance.new("Sound", head)
7550 soundJumping = Instance.new("Sound", head)
7551 soundRunning = Instance.new("Sound", head)
7552 leftHip = Instance.new("Motor", torso)
7553 leftShoulder = Instance.new("Motor", torso)
7554 rightHip = Instance.new("Motor", torso)
7555 rightShoulder = Instance.new("Motor", torso)
7556 neck = Instance.new("Motor", torso)
7557 rootJoint = Instance.new("Motor", rootPart)
7558 feetPart = Instance.new("Part", model)
7559 feetWeld = Instance.new("Weld", torso)
7560 bodyGyro = Instance.new("BodyGyro", rootPart)
7561 bodyVelocity = Instance.new("BodyVelocity", rootPart)
7562 model.Archivable = false
7563 model.Name = UserInterface.player_name
7564 model.PrimaryPart = head
7565 humanoid.LeftLeg = leftLeg
7566 humanoid.RightLeg = rightLeg
7567 humanoid.Torso = rootPart
7568 head.CFrame = torsoCFrame * CFrame.new(0, 1.5, 0)
7569 head.FormFactor = "Symmetric"
7570 head.Locked = true
7571 head.Name = "Head"
7572 head.Size = Vector3.new(2, 1, 1)
7573 head.TopSurface = "Smooth"
7574 leftArm.CanCollide = false
7575 leftArm.CFrame = torsoCFrame * CFrame.new(-1.5, 0, 0)
7576 leftArm.FormFactor = "Symmetric"
7577 leftArm.Locked = true
7578 leftArm.Name = "Left Arm"
7579 leftArm.Size = Vector3.new(1, 2, 1)
7580 leftLeg.BottomSurface = "Smooth"
7581 leftLeg.CanCollide = false
7582 leftLeg.CFrame = torsoCFrame * CFrame.new(-0.5, -2, 0)
7583 leftLeg.FormFactor = "Symmetric"
7584 leftLeg.Locked = true
7585 leftLeg.Name = "Left Leg"
7586 leftLeg.Size = Vector3.new(1, 2, 1)
7587 leftLeg.TopSurface = "Smooth"
7588 rightArm.CanCollide = false
7589 rightArm.CFrame = torsoCFrame * CFrame.new(1.5, 0, 0)
7590 rightArm.FormFactor = "Symmetric"
7591 rightArm.Locked = true
7592 rightArm.Name = "Right Arm"
7593 rightArm.Size = Vector3.new(1, 2, 1)
7594 rightLeg.BottomSurface = "Smooth"
7595 rightLeg.CanCollide = false
7596 rightLeg.CFrame = torsoCFrame * CFrame.new(0.5, -2, 0)
7597 rightLeg.FormFactor = "Symmetric"
7598 rightLeg.Locked = true
7599 rightLeg.Name = "Right Leg"
7600 rightLeg.Size = Vector3.new(1, 2, 1)
7601 rightLeg.TopSurface = "Smooth"
7602 torso.CFrame = torsoCFrame
7603 torso.FormFactor = "Symmetric"
7604 torso.LeftSurface = "Weld"
7605 torso.Locked = true
7606 torso.RightSurface = "Weld"
7607 torso.Name = "Torso"
7608 torso.Size = Vector3.new(2, 2, 1)
7609 rootPart.BottomSurface = "Smooth"
7610 rootPart.BrickColor = BrickColor.Blue()
7611 rootPart.CFrame = rootPartCFrame
7612 rootPart.FormFactor = "Symmetric"
7613 rootPart.LeftSurface = "Weld"
7614 rootPart.Locked = true
7615 rootPart.RightSurface = "Weld"
7616 rootPart.Name = "HumanoidRootPart"
7617 rootPart.Size = Vector3.new(2, 2, 1)
7618 rootPart.TopSurface = "Smooth"
7619 rootPart.Transparency = 1
7620 soundFreeFalling.Archivable = false
7621 soundFreeFalling.SoundId = "rbxasset://sounds/swoosh.wav"
7622 soundGettingUp.Archivable = false
7623 soundGettingUp.SoundId = "rbxasset://sounds/hit.wav"
7624 soundRunning.Archivable = false
7625 soundRunning.SoundId = "rbxasset://sounds/bfsl-minifigfoots1.mp3"
7626 soundRunning.Looped = true
7627 leftHip.C0 = CFrame.new(-1, -1, 0, -0, -0, -1, 0, 1, 0, 1, 0, 0)
7628 leftHip.C1 = CFrame.new(-0.5, 1, 0, -0, -0, -1, 0, 1, 0, 1, 0, 0)
7629 leftHip.MaxVelocity = 0.1
7630 leftHip.Name = "Left Hip"
7631 leftHip.Part0 = torso
7632 leftHip.Part1 = leftLeg
7633 leftShoulder.C0 = CFrame.new(-1, 0.5, 0, -0, -0, -1, 0, 1, 0, 1, 0, 0)
7634 leftShoulder.C1 = CFrame.new(0.5, 0.5, 0, -0, -0, -1, 0, 1, 0, 1, 0, 0)
7635 leftShoulder.MaxVelocity = 0.15
7636 leftShoulder.Name = "Left Shoulder"
7637 leftShoulder.Part0 = torso
7638 leftShoulder.Part1 = leftArm
7639 rightHip.C0 = CFrame.new(1, -1, 0, 0, 0, 1, 0, 1, 0, -1, -0, -0)
7640 rightHip.C1 = CFrame.new(0.5, 1, 0, 0, 0, 1, 0, 1, 0, -1, -0, -0)
7641 rightHip.MaxVelocity = 0.1
7642 rightHip.Name = "Right Hip"
7643 rightHip.Part0 = torso
7644 rightHip.Part1 = rightLeg
7645 rightShoulder.C0 = CFrame.new(1, 0.5, 0, 0, 0, 1, 0, 1, 0, -1, -0, -0)
7646 rightShoulder.C1 = CFrame.new(-0.5, 0.5, 0, 0, 0, 1, 0, 1, 0, -1, -0, -0)
7647 rightShoulder.MaxVelocity = 0.15
7648 rightShoulder.Name = "Right Shoulder"
7649 rightShoulder.Part0 = torso
7650 rightShoulder.Part1 = rightArm
7651 if prevLeftHip then
7652 leftHip.CurrentAngle = prevLeftHip.CurrentAngle
7653 leftHip.DesiredAngle = prevLeftHip.DesiredAngle
7654 end
7655 if prevLeftShoulder then
7656 leftShoulder.CurrentAngle = prevLeftShoulder.CurrentAngle
7657 leftShoulder.DesiredAngle = prevLeftShoulder.DesiredAngle
7658 end
7659 if prevRightHip then
7660 rightHip.CurrentAngle = prevRightHip.CurrentAngle
7661 rightHip.DesiredAngle = prevRightHip.DesiredAngle
7662 end
7663 if prevRightShoulder then
7664 rightShoulder.CurrentAngle = prevRightShoulder.CurrentAngle
7665 rightShoulder.DesiredAngle = prevRightShoulder.DesiredAngle
7666 end
7667 neck.C0 = CFrame.new(0, 1, 0, -1, -0, -0, 0, 0, 1, 0, 1, 0)
7668 neck.C1 = CFrame.new(0, -0.5, 0, -1, -0, -0, 0, 0, 1, 0, 1, 0)
7669 neck.Name = "Neck"
7670 neck.Part0 = torso
7671 neck.Part1 = head
7672 rootJoint.C0 = CFrame.new(0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 1, 0)
7673 rootJoint.C1 = CFrame.new(0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 1, 0)
7674 rootJoint.Name = "RootJoint"
7675 rootJoint.Part0 = rootPart
7676 rootJoint.Part1 = torso
7677 feetPart.BottomSurface = "Smooth"
7678 feetPart.CanCollide = false
7679 feetPart.CFrame = torsoCFrame * CFrame.new(0, -3.1, 0)
7680 feetPart.FormFactor = "Custom"
7681 feetPart.Locked = true
7682 feetPart.Name = "Platform"
7683 feetPart.Size = Vector3.new(1.8, 0.2, 0.8)
7684 feetPart.TopSurface = "Smooth"
7685 feetPart.Transparency = 1
7686 feetWeld.C0 = CFrame.new(0, -3, 0)
7687 feetWeld.C1 = CFrame.new(0, 0.1, 0)
7688 feetWeld.Name = "PlatformWeld"
7689 feetWeld.Part0 = torso
7690 feetWeld.Part1 = feetPart
7691 table.insert(connections, feetPart.Touched:connect(function(hit)
7692 feetTouching[hit] = true
7693 end))
7694 table.insert(connections, feetPart.TouchEnded:connect(function(hit)
7695 feetTouching[hit] = nil
7696 end))
7697 feetTouchInterest = feetPart:FindFirstChild("TouchInterest")
7698 bodyGyro.D = 3250
7699 bodyGyro.P = 400000
7700 bodyGyro.maxTorque = Vector3.new(1000000000, 0, 1000000000)
7701 bodyVelocity.P = 5000
7702 bodyVelocity.maxForce = Vector3.new(0, 0, 0)
7703 bodyVelocity.velocity = Vector3.new(0, 0, 0)
7704 torsoLight = Instance.new("PointLight", torso)
7705 torsoLight.Brightness = 0.4
7706 torsoLight.Color = Color3.new(1, 1, 1)
7707 torsoLight.Range = 16
7708 torsoLight.Shadows = true
7709 local ff1, ff2, ff3, ff4, ff5, ff6, ff7, ff8, ff9 = Instance.new("ForceField", head), Instance.new("ForceField", leftArm), Instance.new
7710
7711("ForceField", leftLeg), Instance.new("ForceField", rightArm), Instance.new("ForceField", rightLeg), Instance.new("ForceField", torso), Instance.new
7712
7713("ForceField", wildcardHandle), Instance.new("ForceField", feetPart), Instance.new("ForceField", rootPart)
7714 local forcefields = {[ff1] = head, [ff2] = leftArm, [ff3] = leftLeg, [ff4] = rightArm, [ff5] = rightLeg, [ff6] = torso, [ff7] =
7715
7716wildcardHandle, [ff8] = feetPart, [ff9] = rootPart}
7717 local objects = {[humanoid] = true, [head] = true, [leftArm] = true, [leftLeg] = true, [rightArm] = true, [rightLeg] = true, [torso] = true,
7718
7719[rootPart] = true, [rootJoint] = true, [soundFreeFalling] = true, [soundGettingUp] = true, [soundRunning] = true, [leftHip] = true, [leftShoulder] = true,
7720
7721[rightHip] = true, [rightShoulder] = true, [neck] = true, [feetPart] = true, [feetWeld] = true, [feetTouchInterest] = true, [bodyGyro] = true,
7722
7723[bodyVelocity] = true, [ff1] = true, [ff2] = true, [ff3] = true, [ff4] = true, [ff5] = true, [ff6] = true, [ff7] = true, [ff8] = true, [ff9] = true}
7724 local tshirtUrl = appearance.tshirt
7725 if tshirtUrl then
7726 local tshirt = Instance.new("Decal", torso)
7727 tshirt.Name = "roblox"
7728 tshirt.Texture = tshirtUrl
7729 objects[tshirt] = true
7730 end
7731 for _, template in ipairs(appearance.characterObjects) do
7732 local object = template:Clone()
7733 local newObjects = {object}
7734 for _, object in ipairs(newObjects) do
7735 objects[object] = true
7736 for _, child in ipairs(object:GetChildren()) do
7737 table.insert(newObjects, child)
7738 end
7739 end
7740 if object:IsA("BodyColors") then
7741 head.BrickColor = object.HeadColor
7742 leftArm.BrickColor = object.LeftArmColor
7743 leftLeg.BrickColor = object.LeftLegColor
7744 rightArm.BrickColor = object.RightArmColor
7745 rightLeg.BrickColor = object.RightLegColor
7746 torso.BrickColor = object.TorsoColor
7747 elseif object:IsA("Hat") then
7748 local handle = object:FindFirstChild("Handle")
7749 if handle and handle:IsA("BasePart") then
7750 local weld = Instance.new("Weld", head)
7751 weld.C0 = CFrame.new(0, 0.5, 0)
7752 local attachmentPos = object.AttachmentPos
7753 local attachmentRight = object.AttachmentRight
7754 local attachmentUp = object.AttachmentUp
7755 local attachmentForward = object.AttachmentForward
7756 weld.C1 = CFrame.new(attachmentPos.X, attachmentPos.Y, attachmentPos.Z,
7757 attachmentRight.X, attachmentUp.X, -attachmentForward.X,
7758 attachmentRight.Y, attachmentUp.Y, -attachmentForward.Y,
7759 attachmentRight.Z, attachmentUp.Z, -attachmentForward.Z)
7760 weld.Name = "HeadWeld"
7761 weld.Part0 = head
7762 weld.Part1 = handle
7763 handle.Parent = model
7764 local antiGravity = Instance.new("BodyForce", handle)
7765 antiGravity.force = Vector3.new(0, handle:GetMass() * 196.2, 0)
7766 objects[object] = false
7767 object.Parent = nil
7768 objects[weld] = true
7769 end
7770 end
7771 object.Parent = model
7772 end
7773 local facePresent = false
7774 local headMeshPresent = false
7775 for _, template in ipairs(appearance.headObjects) do
7776 local object = template:Clone()
7777 local newObjects = {object}
7778 for _, object in ipairs(newObjects) do
7779 objects[object] = true
7780 for _, child in ipairs(object:GetChildren()) do
7781 table.insert(newObjects, child)
7782 end
7783 end
7784 if object:IsA("DataModelMesh") then
7785 headMeshPresent = true
7786 elseif object:IsA("Decal") then
7787 facePresent = true
7788 end
7789 object.Parent = head
7790 end
7791 if not facePresent then
7792 local face = Instance.new("Decal", head)
7793 face.Texture = "rbxasset://textures/face.png"
7794 objects[face] = true
7795 end
7796 if not headMeshPresent then
7797 local headMesh = Instance.new("SpecialMesh", head)
7798 headMesh.Scale = Vector3.new(1.25, 1.25, 1.25)
7799 objects[headMesh] = true
7800 end
7801 table.insert(connections, model.DescendantAdded:connect(function(object)
7802 local success, is_localscript = pcall(Game.IsA, object, "LocalScript")
7803 if success and is_localscript then
7804 pcall(Utility.SetProperty, object, "Disabled", true)
7805 local changed_connection = pcall(object.Changed.connect, object.Changed, function(property)
7806 if property == "Disabled" and not object.Disabled then
7807 pcall(Utility.SetProperty, object, "Disabled", true)
7808 Network.TransmitServer("(...):Destroy()", object)
7809 end
7810 end)
7811 end
7812 if not objects[object] then
7813 Network.TransmitServer("(...):Destroy()", object)
7814 end
7815 end))
7816 model.Parent = Workspace
7817 Player.Character = model
7818 Camera.CameraSubject = humanoid
7819 Camera.CameraType = "Track"
7820 Camera.CoordinateFrame = cameraCFrame
7821 local IsStanding
7822 local RegenerateHealth
7823 local ResetCharacter
7824 function IsStanding()
7825 return not not next(feetTouching)
7826 end
7827 function RegenerateHealth()
7828 if humanoid.Health < 1 then
7829 humanoid.Health = 100
7830 elseif not regeneratingHealth then
7831 regeneratingHealth = true
7832 local elapsedTime = wait(1)
7833 regeneratingHealth = false
7834 if humanoid.Health < 100 then
7835 humanoid.Health = math.min(humanoid.Health + elapsedTime, 100)
7836 end
7837 end
7838 end
7839 function ResetCharacter()
7840 for index, connection in ipairs(connections) do
7841 connection:disconnect()
7842 end
7843 active = false
7844 end
7845 table.insert(connections, model.AncestryChanged:connect(ResetCharacter))
7846 table.insert(connections, model.DescendantRemoving:connect(function(object)
7847 local parent = forcefields[object]
7848 if parent then
7849 forcefields[object] = nil
7850 local new_forcefield = Instance.new("ForceField")
7851 forcefields[new_forcefield] = parent
7852 objects[new_forcefield] = true
7853 new_forcefield.Parent = parent
7854 elseif objects[object] then
7855 ResetCharacter()
7856 end
7857 end))
7858 table.insert(connections, humanoid.HealthChanged:connect(RegenerateHealth))
7859 table.insert(connections, humanoid.Climbing:connect(function() pose = "Climbing" end))
7860 table.insert(connections, humanoid.FallingDown:connect(function(state) pose = "FallingDown" end))
7861 table.insert(connections, humanoid.FreeFalling:connect(function(state) pose = "FreeFall" if state then soundFreeFalling:Play() else
7862
7863soundFreeFalling:Pause() end end))
7864 table.insert(connections, humanoid.GettingUp:connect(function(state) pose = "GettingUp" if state then soundGettingUp:Play() else
7865
7866soundGettingUp:Pause() end end))
7867 table.insert(connections, humanoid.PlatformStanding:connect(function() pose = "PlatformStanding" end))
7868 table.insert(connections, humanoid.Seated:connect(function() pose = "Seated" end))
7869 table.insert(connections, humanoid.Swimming:connect(function(speed) if speed > 0 then pose = "Swimming" else pose = "Standing" end end))
7870 local previousRootPartCFrame = rootPart.CFrame
7871 TaskScheduler.Start(function()
7872 while active do
7873 local totalTime = TaskScheduler.GetCurrentTime()
7874 local stepTime = 1 / 60
7875 if not PlayerControl.characterEnabled then
7876 ResetCharacter()
7877 break
7878 end
7879 torsoLight.Brightness = 0.5 + 0.15 * math.sin(totalTime * 0.75 * math.pi)
7880 local featherfallEnabled = PlayerControl.IsFeatherfallEnabled()
7881 local rootPartCFrame = rootPart.CFrame
7882 if not jumpDebounce and UserInterface.IsKeyDown(" ") then
7883 if humanoid.Sit then
7884 humanoid.Sit = false
7885 end
7886 if IsStanding() then
7887 jumpDebounce = true
7888 pose = "Jumping"
7889 rootPart.Velocity = Vector3.new(rootPart.Velocity.X, 50, rootPart.Velocity.Z)
7890 torso.Velocity = Vector3.new(torso.Velocity.X, 50, torso.Velocity.Z)
7891 TaskScheduler.Schedule(1, function()
7892 if pose == "Jumping" then
7893 pose = "FreeFall"
7894 end
7895 jumpDebounce = false
7896 humanoid.Jump = false
7897 end)
7898 end
7899 end
7900 local cameraCFrame = Camera.CoordinateFrame
7901 local cameraDirection = cameraCFrame.lookVector
7902 if flying then
7903 if PlayerControl.rolling then
7904 local rootPartCFrame = rootPart.CFrame
7905 local speed = (rootPartCFrame - rootPartCFrame.p):pointToObjectSpace(rootPart.Velocity).Y
7906 local decay = 0.5 ^ stepTime
7907 if math.abs(speed) <= 50 then
7908 PlayerControl.rollingAngle = (((PlayerControl.rollingAngle + 0.5) % 1 - 0.5) * decay) % 1
7909 PlayerControl.rollingOffset = PlayerControl.rollingOffset * decay
7910 else
7911 PlayerControl.rollingAngle = (PlayerControl.rollingAngle + stepTime * speed *
7912
7913PlayerControl.rollingSpeed) % 1
7914 PlayerControl.rollingOffset = (PlayerControl.rollingOffset + PlayerControl.rollingMaxOffset * (1 /
7915
7916decay - 1)) * decay
7917 end
7918 rootJoint.C0 = (CFrame.new(0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 1, 0) * CFrame.Angles(PlayerControl.rollingAngle *
7919
79202 * math.pi, 0, 0)) * CFrame.new(0, -PlayerControl.rollingOffset, 0)
7921 else
7922 rootJoint.C0 = CFrame.new(0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 1, 0)
7923 PlayerControl.rollingAngle = 0
7924 PlayerControl.rollingOffset = 0
7925 end
7926 rightShoulder.MaxVelocity = 0.5
7927 leftShoulder.MaxVelocity = 0.5
7928 rightShoulder.DesiredAngle = 0
7929 leftShoulder.DesiredAngle = 0
7930 rightHip.DesiredAngle = 0
7931 leftHip.DesiredAngle = 0
7932 bodyGyro.D = 500
7933 bodyGyro.P = 1e6
7934 bodyGyro.maxTorque = Vector3.new(1e6, 1e6, 1e6)
7935 bodyVelocity.P = 1250
7936 bodyVelocity.maxForce = Vector3.new(1e6, 1e6, 1e6)
7937 local movementRight = 0
7938 local movementForward = 0
7939 local movementUp = 0
7940 if UserInterface.IsKeyDown("a") and not UserInterface.IsKeyDown("d") then
7941 movementRight = -1
7942 elseif UserInterface.IsKeyDown("d") then
7943 movementRight = 1
7944 end
7945 if UserInterface.IsKeyDown("w") then
7946 movementUp = 0.2
7947 if not UserInterface.IsKeyDown("s") then
7948 movementForward = -1
7949 end
7950 elseif UserInterface.IsKeyDown("s") then
7951 movementForward = 1
7952 end
7953 local movement = PlayerControl.fly_acceleration * cameraCFrame:vectorToWorldSpace(Vector3.new(movementRight,
7954
7955movmentUp, movementForward))
7956 local previousMomentum = flyingMomentum
7957 local previousTilt = flyingTilt
7958 flyingMomentum = movement + flyingMomentum * (1 - PlayerControl.fly_acceleration / PlayerControl.fly_speed)
7959 flyingTilt = ((flyingMomentum * Vector3.new(1, 0, 1)).unit:Cross((previousMomentum * Vector3.new(1, 0, 1)).unit)).Y
7960 if flyingTilt ~= flyingTilt or flyingTilt == math.huge then
7961 flyingTilt = 0
7962 end
7963 local absoluteTilt = math.abs(flyingTilt)
7964 if absoluteTilt > 0.06 or absoluteTilt < 0.0001 then
7965 if math.abs(previousTilt) > 0.0001 then
7966 flyingTilt = previousTilt * 0.9
7967 else
7968 flyingTilt = 0
7969 end
7970 else
7971 flyingTilt = previousTilt * 0.77 + flyingTilt * 0.25
7972 end
7973 previousTilt = flyingTilt
7974 if flyingMomentum.magnitude < 0.1 then
7975 flyingMomentum = Vector3.new(0, 0, 0)
7976-- bodyGyro.cframe = cameraCFrame
7977 else
7978 local momentumOrientation = CFrame.new(Vector3.new(0, 0, 0), flyingMomentum)
7979 local tiltOrientation = CFrame.Angles(0, 0, -20 * flyingTilt)
7980 bodyGyro.cframe = momentumOrientation * tiltOrientation * CFrame.Angles(-0.5 * math.pi * math.min
7981
7982(flyingMomentum.magnitude / PlayerControl.fly_speed, 1), 0, 0)
7983 end
7984 bodyVelocity.velocity = flyingMomentum + Vector3.new(0, 0.15695775618683547, 0)
7985 rootPart.Velocity = flyingMomentum
7986 previousMomentum = flyingMomentum
7987 else
7988 rootJoint.C0 = CFrame.new(0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 1, 0)
7989 PlayerControl.rollingAngle = 0
7990 PlayerControl.rollingOffset = 0
7991 bodyGyro.D = 3250
7992 bodyGyro.P = 400000
7993 bodyVelocity.P = 5000
7994 local cameraDirection = cameraCFrame.lookVector
7995 local walkDirection = Vector3.new(0, 0, 0)
7996 local walkSpeed = 16
7997 if UserInterface.IsKeyDown("w") or UserInterface.IsKeyDown("\17") then
7998 if UserInterface.IsKeyDown("a") then
7999 walkDirection = Vector3.new(cameraDirection.X + cameraDirection.Z, 0, cameraDirection.Z -
8000
8001cameraDirection.X).unit
8002 elseif UserInterface.IsKeyDown("d") then
8003 walkDirection = Vector3.new(cameraDirection.X - cameraDirection.Z, 0, cameraDirection.Z +
8004
8005cameraDirection.X).unit
8006 else
8007 walkDirection = Vector3.new(cameraDirection.X, 0, cameraDirection.Z).unit
8008 end
8009 elseif UserInterface.IsKeyDown("s") or UserInterface.IsKeyDown("\18") then
8010 if UserInterface.IsKeyDown("a") then
8011 walkDirection = Vector3.new(-cameraDirection.X + cameraDirection.Z, 0, -cameraDirection.Z -
8012
8013cameraDirection.X).unit
8014 elseif UserInterface.IsKeyDown("d") then
8015 walkDirection = Vector3.new(-cameraDirection.X - cameraDirection.Z, 0, -cameraDirection.Z +
8016
8017cameraDirection.X).unit
8018 else
8019 walkDirection = Vector3.new(-cameraDirection.X, 0, -cameraDirection.Z).unit
8020 end
8021 elseif UserInterface.IsKeyDown("a") then
8022 walkDirection = Vector3.new(cameraDirection.Z, 0, -cameraDirection.X).unit
8023 elseif UserInterface.IsKeyDown("d") then
8024 walkDirection = Vector3.new(-cameraDirection.Z, 0, cameraDirection.X).unit
8025 else
8026 walkSpeed = 0
8027 end
8028 if walkSpeed ~= previousWalkSpeed then
8029 if walkSpeed > 0 then
8030 soundRunning:Play()
8031 else
8032 soundRunning:Pause()
8033 end
8034 end
8035 if walkSpeed > 0 then
8036 if pose ~= "Jumping" then
8037 if IsStanding() then
8038 pose = "Running"
8039 else
8040 pose = "FreeFall"
8041 end
8042 end
8043 bodyGyro.cframe = CFrame.new(Vector3.new(), walkDirection)
8044 bodyGyro.maxTorque = Vector3.new(1000000000, 1000000000, 1000000000)
8045 bodyVelocity.maxForce = Vector3.new(1000000, maxForceY, 1000000)
8046 else
8047 if pose ~= "Jumping" then
8048 if IsStanding() then
8049 pose = "Standing"
8050 else
8051 pose = "FreeFall"
8052 end
8053 end
8054 -- TODO: find and fix bug that causes torso to rotate back to some angle
8055 bodyGyro.maxTorque = Vector3.new(1000000000, 1000000000, 1000000000) -- Vector3.new(1000000000, 0,
8056
80571000000000)
8058 if PlayerControl.pushable then
8059 bodyVelocity.maxForce = Vector3.new(0, 0, 0)
8060 else
8061 bodyVelocity.maxForce = Vector3.new(1000000, 0, 1000000)
8062 end
8063 end
8064 if featherfallEnabled then
8065 local velocity = rootPart.Velocity
8066 if velocity.Y > 50 then
8067 rootPart.Velocity = Vector3.new(velocity.X, 50, velocity.Z)
8068 elseif velocity.Y < -50 then
8069 rootPart.Velocity = Vector3.new(velocity.X, -50, velocity.Z)
8070 end
8071 local distanceVector = rootPartCFrame.p - previousRootPartCFrame.p
8072 local offsetX, offsetY, offsetZ = distanceVector.X, distanceVector.Y, distanceVector.Z
8073 local MAX_MOVEMENT = 50 * 0.03333333507180214
8074 if offsetX > MAX_MOVEMENT then
8075 offsetX = MAX_MOVEMENT
8076 elseif offsetX < -MAX_MOVEMENT then
8077 offsetX = -MAX_MOVEMENT
8078 end
8079 if offsetY > MAX_MOVEMENT then
8080 offsetY = MAX_MOVEMENT
8081 elseif offsetY < -MAX_MOVEMENT then
8082 offsetY = -MAX_MOVEMENT
8083 end
8084 if offsetZ > MAX_MOVEMENT then
8085 offsetZ = MAX_MOVEMENT
8086 elseif offsetZ < -MAX_MOVEMENT then
8087 offsetZ = -MAX_MOVEMENT
8088 end
8089 local offset = Vector3.new(offsetX, offsetY, offsetZ)
8090 if offset ~= distanceVector then
8091 rootPartCFrame = previousRootPartCFrame + offset
8092 --rootPart.CFrame = rootPartCFrame
8093 end
8094 end
8095 local walkingVelocity = walkDirection * walkSpeed
8096 bodyVelocity.velocity = walkingVelocity
8097 if not jumpDebounce and math.abs(rootPart.Velocity.Y) <= 0.1 then
8098 rootPart.Velocity = Vector3.new(walkingVelocity.X, rootPart.Velocity.Y, walkingVelocity.Z)
8099 end
8100 previousWalkSpeed = walkSpeed
8101 if pose == "Jumping" or jumpDebounce then
8102 rightShoulder.MaxVelocity = 0.5
8103 leftShoulder.MaxVelocity = 0.5
8104 rightShoulder.DesiredAngle = 3.14
8105 leftShoulder.DesiredAngle = -3.14
8106 rightHip.DesiredAngle = 0
8107 leftHip.DesiredAngle = 0
8108 elseif pose == "FreeFall" then
8109 rightShoulder.MaxVelocity = 0.5
8110 leftShoulder.MaxVelocity = 0.5
8111 rightShoulder.DesiredAngle = 3.14
8112 leftShoulder.DesiredAngle = -3.14
8113 rightHip.DesiredAngle = 0
8114 leftHip.DesiredAngle = 0
8115 elseif pose == "Seated" then
8116 rightShoulder.MaxVelocity = 0.15
8117 leftShoulder.MaxVelocity = 0.15
8118 rightShoulder.DesiredAngle = 3.14 / 2
8119 leftShoulder.DesiredAngle = -3.14 / 2
8120 rightHip.DesiredAngle = 3.14 / 2
8121 leftHip.DesiredAngle = -3.14 / 2
8122 else
8123 local climbFudge = 0
8124 local amplitude
8125 local frequency
8126 if pose == "Running" then
8127 rightShoulder.MaxVelocity = 0.15
8128 leftShoulder.MaxVelocity = 0.15
8129 amplitude = 1
8130 frequency = 9
8131 elseif (pose == "Climbing") then
8132 rightShoulder.MaxVelocity = 0.5
8133 leftShoulder.MaxVelocity = 0.5
8134 amplitude = 1
8135 frequency = 9
8136 climbFudge = 3.14
8137 else
8138 amplitude = 0.1
8139 frequency = 1
8140 end
8141 local desiredAngle = amplitude * math.sin(totalTime * frequency)
8142 rightShoulder.DesiredAngle = desiredAngle + climbFudge
8143 leftShoulder.DesiredAngle = desiredAngle - climbFudge
8144 rightHip.DesiredAngle = -desiredAngle
8145 leftHip.DesiredAngle = -desiredAngle
8146 end
8147 end
8148 previousRootPartCFrame = rootPartCFrame
8149 RunService.RenderStepped:wait()
8150 end
8151 if model.Parent ~= nil then
8152 model.Parent = nil
8153 end
8154 PlayerControl.CreateCharacter()
8155 end)
8156 humanoid.Health = 100
8157 character = model
8158 Network.TransmitServer("chatAdornee = ...", head)
8159 elseif characterMode == "pyramid" then
8160 if PlayerControl.characterEnabled then
8161 Camera.CameraType = "Fixed"
8162 PyramidCharacter.camera_distance = (Camera.Focus.p - Camera.CoordinateFrame.p).magnitude
8163 PyramidCharacter.camera_position = Camera.Focus.p
8164 PyramidCharacter.Teleport(Camera.Focus.p)
8165 PyramidCharacter.visible = true
8166 Player.Character = nil
8167 else
8168 PyramidCharacter.visible = false
8169 end
8170 end
8171end
8172function PlayerControl.GetCharacter()
8173 return character
8174end
8175function PlayerControl.GetHead()
8176 local characterMode = PlayerControl.characterMode
8177 if characterMode == "normal" then
8178 return head
8179 elseif characterMode == "pyramid" then
8180 return PyramidCharacter.core
8181 end
8182end
8183function PlayerControl.GetHumanoid()
8184 return humanoid
8185end
8186function PlayerControl.GetRootPart()
8187 return rootPart
8188end
8189function PlayerControl.GetTorso()
8190 return torso
8191end
8192function PlayerControl.IsEnabled()
8193 return PlayerControl.characterEnabled
8194end
8195function PlayerControl.IsFeatherfallEnabled()
8196 return PlayerControl.featherfallEnabled
8197end
8198function PlayerControl.IsPushable()
8199 return PlayerControl.pushable
8200end
8201function PlayerControl.IsRolling()
8202 return PlayerControl.rolling
8203end
8204function PlayerControl.ResetCharacter()
8205 if character and character.Parent then
8206 character.Parent = nil
8207 end
8208 PyramidCharacter.visible = false
8209end
8210function PlayerControl.SetEnabled(state, no_animation)
8211 state = not not state
8212 if state ~= PlayerControl.characterEnabled then
8213 PlayerControl.characterEnabled = state
8214 local characterMode = PlayerControl.characterMode
8215 if characterMode == "normal" then
8216 local torso = PlayerControl.GetRootPart()
8217 local rootPart = PlayerControl.GetRootPart()
8218 if rootPart then
8219 if PlayerControl.characterEnabled then
8220 local torso_cframe = Camera.Focus:toWorldSpace(PlayerControl.hide_torso_object_cframe)
8221 PlayerControl.torso_cframe = torso_cframe
8222 torso.CFrame = torso_cframe
8223 rootPart.CFrame = torso_cframe
8224 else
8225 PlayerControl.hide_torso_object_cframe = Camera.Focus:toObjectSpace(rootPart.CFrame)
8226 end
8227 else
8228 PlayerControl.torso_cframe = Camera.Focus
8229 end
8230 if PlayerControl.characterEnabled then
8231 PlayerControl.CreateCharacter()
8232 RunService.Stepped:wait()
8233 coroutine.yield()
8234 if not no_animation then
8235 Network.TransmitServer("GraphicalEffects.CrystalRing({base_part = (...), crystal_color = BrickColor.new
8236
8237(\"Institutional white\"), float_duration = 2})", PlayerControl.GetTorso())
8238 end
8239 else
8240 Player.Character = nil
8241 Camera.CameraType = "Fixed"
8242 if not no_animation then
8243 Network.TransmitServer("GraphicalEffects.CrystalRing({position = (...), crystal_color = BrickColor.new
8244
8245(\"Institutional white\"), float_duration = 2})", PlayerControl.GetTorso().Position)
8246 end
8247 end
8248 else
8249 if state then
8250 PlayerControl.CreateCharacter()
8251 RunService.Stepped:wait()
8252 coroutine.yield()
8253 if not no_animation then
8254 Network.TransmitServer("GraphicalEffects.CrystalRing({base_part = (...), crystal_color = BrickColor.new
8255
8256(\"Institutional white\"), float_duration = 2})", PyramidCharacter.core)
8257 end
8258 else
8259 PyramidCharacter.visible = false
8260 if not no_animation then
8261 Network.TransmitServer("GraphicalEffects.CrystalRing({position = (...), crystal_color = BrickColor.new
8262
8263(\"Institutional white\"), float_duration = 2})", PyramidCharacter.core.Position)
8264 end
8265 end
8266 end
8267 end
8268end
8269function PlayerControl.SetFeatherfallEnabled(state)
8270 state = not not state
8271 if state ~= PlayerControl.featherfallEnabled then
8272 PlayerControl.featherfallEnabled = state
8273 if state then
8274 Logger.print("Info", "Featherfall enabled in PlayerControl")
8275 else
8276 Logger.print("Info", "Featherfall disabled in PlayerControl")
8277 end
8278 end
8279end
8280function PlayerControl.SetPushable(state)
8281 state = not not state
8282 if state ~= PlayerControl.pushable then
8283 PlayerControl.pushable = state
8284 if state then
8285 Logger.print("Info", "Pushing enabled in PlayerControl")
8286 else
8287 Logger.print("Info", "Pushing disabled in PlayerControl")
8288 end
8289 end
8290end
8291function PlayerControl.SetRolling(state)
8292 state = not not state
8293 if state ~= PlayerControl.rolling then
8294 PlayerControl.rolling = state
8295 if state then
8296 Logger.print("Info", "Rolling fly mode enabled in PlayerControl")
8297 else
8298 Logger.print("Info", "Rolling fly mode disabled in PlayerControl")
8299 end
8300 end
8301end
8302function PlayerControl.StartFlying()
8303 PlayerControl.fly_speed = PlayerControl.fly_basespeed
8304 if torso then
8305 flyingMomentum = torso.Velocity + torso.CFrame.lookVector * 3 + Vector3.new(0, 10, 0)
8306 else
8307 flyingMomentum = Vector3.new()
8308 end
8309 flyingTilt = 0
8310 flying = true
8311end
8312function PlayerControl.StopFlying()
8313 if bodyGyro.cframe then
8314 local lookVector = bodyGyro.cframe.lookVector
8315 if lookVector.X ~= 0 or lookVector.Z ~= 0 then
8316 bodyGyro.cframe = CFrame.new(Vector3.new(), Vector3.new(lookVector.X, 0, lookVector.Z))
8317 end
8318 end
8319 flying = false
8320end
8321local previousTime = 0
8322UserInterface.SetHotkey(" ", function()
8323 if flying then
8324 PlayerControl.StopFlying()
8325 else
8326 local currentTime = time()
8327 if currentTime - previousTime < 0.4 then
8328 previousTime = 0
8329 PlayerControl.StartFlying()
8330 else
8331 previousTime = currentTime
8332 end
8333 end
8334end)
8335]])
8336Module.Create("RBXInstance", [[
8337RBXInstance.init_metatable = {}
8338function RBXInstance.init_metatable:__call(data)
8339 local instance = Instance.new(self[1])
8340 for key, value in pairs(data) do
8341 if type(key) == "number" then
8342 value.Parent = instance
8343 else
8344 instance[key] = value
8345 end
8346 end
8347 return instance
8348end
8349function RBXInstance.new(className)
8350 return setmetatable({className}, RBXInstance.init_metatable)
8351end
8352]])
8353Module.Create("AdvancedGUI", [=[
8354if not AdvancedGUI.GUI_BASE_COLOR then
8355 AdvancedGUI.GUI_BASE_COLOR = Color3.new(0, 0, 0)
8356end
8357function AdvancedGUI.GenerateChatColor(speakerName)
8358 local chatColor = ChatColor.Get(speakerName).Color
8359 local brightness = chatColor.r + chatColor.g + chatColor.b
8360 if brightness < 1.5 then
8361 chatColor = Color3.new(math.min(1, 0.4 + chatColor.r), math.min(1, 0.4 + chatColor.g), math.min(1, 0.4 + chatColor.b))
8362 else
8363 chatColor = Color3.new(math.min(1, 0.05 + chatColor.r), math.min(1, 0.05 + chatColor.g), math.min(1, 0.05 + chatColor.b))
8364 end
8365 return chatColor
8366end
8367GuiBase = {}
8368GuiBase.__index = GuiBase
8369function GuiBase:new(data)
8370 local instance = setmetatable({}, self)
8371 instance:Init(data)
8372 return instance
8373end
8374function GuiBase:Destroy()
8375 if self.parent then
8376 self.parent.children[self] = nil
8377 end
8378 for child in pairs(self.children) do
8379 child:Destroy()
8380 end
8381 self.m_base_instance:Destroy()
8382end
8383function GuiBase:GetContentInstance(child)
8384 return self.m_base_instance
8385end
8386function GuiBase:Init()
8387 self.children = {}
8388end
8389function GuiBase:IsA(className)
8390 return className == "GuiBase"
8391end
8392function GuiBase:SetParent(parent)
8393 if parent ~= self.parent then
8394 if self.parent then
8395 self.parent.children[self] = nil
8396 end
8397 self.parent = parent
8398 if parent then
8399 parent.children[self] = true
8400 self.m_base_instance.Parent = parent:GetContentInstance()
8401 else
8402 self.m_base_instance.Parent = nil
8403 end
8404 end
8405end
8406GuiObject = setmetatable({}, GuiBase)
8407GuiObject.__index = GuiObject
8408function GuiObject:Destroy()
8409 self.DragBegin:disconnect()
8410 self.DragMove:disconnect()
8411 self.DragStopped:disconnect()
8412 self.MouseButton1Click:disconnect()
8413 self.MouseButton1Down:disconnect()
8414 self.MouseButton1Up:disconnect()
8415 self.MouseButton2Down:disconnect()
8416 self.MouseButton2Up:disconnect()
8417 self.MouseEnter:disconnect()
8418 self.MouseLeave:disconnect()
8419 GuiBase.Destroy(self)
8420end
8421function GuiObject:GetAbsolutePosition()
8422 return self.m_base_instance.AbsolutePosition
8423end
8424function GuiObject:GetAbsoluteSize()
8425 return self.m_base_instance.AbsoluteSize
8426end
8427function GuiObject:GetPosition()
8428 return self.position
8429end
8430function GuiObject:GetSize()
8431 return self.size
8432end
8433function GuiObject:Init()
8434 GuiBase.Init(self)
8435 self.mouseDown = false
8436 self.mouseOver = false
8437 self.DragBegin = RbxUtility.CreateSignal()
8438 self.DragMove = RbxUtility.CreateSignal()
8439 self.DragStopped = RbxUtility.CreateSignal()
8440 self.MouseButton1Click = RbxUtility.CreateSignal()
8441 self.MouseButton1Down = RbxUtility.CreateSignal()
8442 self.MouseButton1Up = RbxUtility.CreateSignal()
8443 self.MouseButton2Down = RbxUtility.CreateSignal()
8444 self.MouseButton2Up = RbxUtility.CreateSignal()
8445 self.MouseEnter = RbxUtility.CreateSignal()
8446 self.MouseLeave = RbxUtility.CreateSignal()
8447end
8448function GuiObject:IsA(className)
8449 return className == "GuiObject" or GuiBase.IsA(self, className)
8450end
8451function GuiObject:SetActive(active)
8452 if active ~= self.active then
8453 self.active = active
8454 end
8455end
8456function GuiObject:SetBackgroundTransparency(backgroundTransparency)
8457 if backgroundTransparency ~= self.backgroundTransparency then
8458 self.backgroundTransparency = backgroundTransparency
8459 self.m_base_instance.BackgroundTransparency = backgroundTransparency
8460 end
8461end
8462function GuiObject:SetColor(color)
8463 if color ~= self.color then
8464 self.color = color
8465 self.m_base_instance.BackgroundColor3 = color
8466 end
8467end
8468function GuiObject:SetPosition(position)
8469 if position ~= self.position then
8470 self.position = position
8471 self.m_base_instance.Position = position
8472 end
8473end
8474function GuiObject:SetSize(size)
8475 if size ~= self.size then
8476 self.size = size
8477 self.m_base_instance.Size = size
8478 end
8479end
8480function GuiObject:SetVisible(visible)
8481 if visible ~= self.visible then
8482 self.visible = visible
8483 self.m_base_instance.Visible = visible
8484 end
8485end
8486function GuiObject:SetZIndex(zIndex)
8487 local stack = {self.m_base_instance}
8488 repeat
8489 local object = stack[#stack]
8490 stack[#stack] = nil
8491 for _, child in ipairs(object:GetChildren()) do
8492 stack[#stack + 1] = child
8493 end
8494 object.ZIndex = zIndex
8495 until #stack == 0
8496end
8497GuiServiceClass = setmetatable({}, GuiBase)
8498GuiServiceClass.__index = GuiServiceClass
8499function GuiServiceClass:CreateTextArea(text, font, fontSize, textColor3, textXAlignment, textYAlignment, maxWidth, minWidth)
8500 local totalHeight = 0
8501 local frame = Instance.new("Frame")
8502 frame.BackgroundTransparency = 1
8503 local label = Instance.new("TextLabel")
8504 label.BackgroundTransparency = 1
8505 label.Font = font
8506 label.FontSize = fontSize
8507 label.TextColor3 = textColor3
8508 label.TextTransparency = 1
8509 label.TextWrapped = true
8510 label.TextXAlignment = textXAlignment
8511 label.TextYAlignment = textYAlignment
8512 label.Parent = self.guiFrame
8513 local index = 1
8514 while true do
8515 local length = #text - index + 1
8516 if length > 1024 then
8517 length = 1024
8518 local textBlock = string.sub(text, index, index + length - 1)
8519 label.Text = textBlock
8520 local height = 0
8521 local width = maxWidth
8522 repeat
8523 height = height + 20
8524 label.Size = UDim2.new(0, width, 0, height)
8525 until label.TextFits
8526 repeat
8527 height = height - 1
8528 label.Size = UDim2.new(0, width, 0, height)
8529 until not label.TextFits
8530 repeat
8531 length = length - 10
8532 label.Text = string.sub(text, index, index + length - 1)
8533 until label.TextFits
8534 repeat
8535 length = length + 1
8536 label.Text = string.sub(text, index, index + length - 1)
8537 until not label.TextFits
8538 local overflowCharacter = string.sub(text, index + length - 1, index + length - 1)
8539 length = length - 1
8540 label.Text = string.sub(text, index, index + length - 1)
8541 if overflowCharacter == "\n" then
8542 index = index + 1
8543 end
8544 repeat
8545 height = height - 1
8546 label.Size = UDim2.new(0, width, 0, height)
8547 until not label.TextFits
8548 height = height + 1
8549 local blockLabel = label:Clone()
8550 blockLabel.Position = UDim2.new(0, 0, 0, totalHeight)
8551 blockLabel.Size = UDim2.new(1, 0, 0, height)
8552 blockLabel.Parent = frame
8553 totalHeight = totalHeight + height
8554 index = index + length
8555 else
8556 local textBlock = string.sub(text, index)
8557 label.Text = textBlock
8558 local height = 0
8559 local width = maxWidth
8560 repeat
8561 height = height + 20
8562 label.Size = UDim2.new(0, width, 0, height)
8563 until label.TextFits
8564 repeat
8565 height = height - 1
8566 label.Size = UDim2.new(0, width, 0, height)
8567 until not label.TextFits
8568 height = height + 1
8569 if index == 1 then
8570 repeat
8571 width = width - 10
8572 label.Size = UDim2.new(0, width, 0, height)
8573 until width < minWidth or not label.TextFits
8574 width = math.max(width, minWidth - 1)
8575 repeat
8576 width = width + 1
8577 label.Size = UDim2.new(0, width, 0, height)
8578 until label.TextFits
8579 end
8580 local blockLabel = label:Clone()
8581 blockLabel.Position = UDim2.new(0, 0, 0, totalHeight)
8582 blockLabel.Size = UDim2.new(1, 0, 0, height)
8583 blockLabel.Parent = frame
8584 label:Destroy()
8585 frame.Size = UDim2.new(0, width, 0, totalHeight + height)
8586 return frame
8587 end
8588 end
8589end
8590function GuiServiceClass:Destroy()
8591 self.running = false
8592 self.cameraPart:Destroy()
8593 self.cameraConnection:disconnect()
8594 self.keyDownConnection:disconnect()
8595 self.mouseButton1DownConnection:disconnect()
8596 self.mouseButton1UpConnection:disconnect()
8597 self.mouseButton2DownConnection:disconnect()
8598 self.mouseButton2UpConnection:disconnect()
8599 self.mouseMoveConnection:disconnect()
8600 self.steppedConnection:disconnect()
8601end
8602function GuiServiceClass:GetMousePosition()
8603 local mouse = self.mouse
8604 return mouse.X, mouse.Y -- mouse.X, mouse.Y + 2 -- return mouse.X - 2, mouse.Y - 3
8605end
8606function GuiServiceClass:GetTextBounds(text, font, fontSize, alignX, alignY, width)
8607 local tempLabel = self.tempLabel
8608 tempLabel.Font = font
8609 tempLabel.FontSize = fontSize
8610 tempLabel.Size = UDim2.new(0, width, 0, 4096)
8611 tempLabel.Text = text
8612 tempLabel.TextXAlignment = alignX
8613 tempLabel.TextYAlignment = alignY
8614 local textBounds = tempLabel.TextBounds
8615 tempLabel.Text = ""
8616 return textBounds
8617end
8618function GuiServiceClass:Init(data)
8619 GuiBase.Init(self)
8620 local _ = string.char
8621 local camera = data.Camera
8622 local mouse = data.Mouse
8623 local cameraPart = Instance.new("Part")
8624 local billboardGui = Instance.new("BillboardGui", cameraPart)
8625 guiFrame = Instance.new("Frame", billboardGui)
8626 cameraPart.Anchored = true
8627 cameraPart.BottomSurface = "Smooth"
8628 cameraPart.CanCollide = false
8629-- cameraPart.CFrame = CFrame.new(16384, 16384, 16384)
8630 cameraPart.FormFactor = "Custom"
8631 cameraPart.Locked = true
8632 cameraPart.Size = Vector3.new(0.2, 0.2, 0.2)
8633 cameraPart.TopSurface = "Smooth"
8634 cameraPart.Transparency = 1
8635 billboardGui.Adornee = cameraPart
8636 billboardGui.AlwaysOnTop = true
8637-- billboardGui.ExtentsOffset = Vector3.new(-16384, -16384, -16384)
8638 guiFrame.BackgroundTransparency = 1
8639 cameraPart.Parent = camera
8640 self.running = true
8641 self.m_base_instance = guiFrame
8642 self.billboardGui = billboardGui
8643 self.cameraPart = cameraPart
8644 self.tempLabel = RBXInstance.new "TextLabel" {
8645 BackgroundTransparency = 1,
8646 TextTransparency = 1,
8647 TextWrapped = true,
8648 Parent = guiFrame
8649 }
8650 self.mnemonics = {}
8651 self.visible = true
8652 self.camera = camera
8653 self.mouse = mouse
8654 self.cameraConnection = camera.Changed:connect(function(property)
8655 self:UpdateView()
8656 if property == "CameraType" then
8657 if camera.CameraType ~= Enum.CameraType.Track and camera.CameraType ~= Enum.CameraType.Fixed then
8658 camera.CameraType = Enum.CameraType.Track
8659 end
8660 elseif property == "CoordinateFrame" and camera.CameraType ~= Enum.CameraType.Fixed then
8661 local cframe, focus = camera.CoordinateFrame, camera.Focus
8662 local watchOffset = focus.p - cframe.p
8663 local error = watchOffset.unit - cframe.lookVector
8664 if error.magnitude >= 1e-3 then
8665 local head = PlayerControl.GetHead()
8666 local time1, velocity1
8667 if head then
8668 time1 = time()
8669 velocity1 = head.Velocity
8670 end
8671 if camera.Changed:wait() == "CoordinateFrame" then
8672 local position = cframe.p
8673 if head then
8674 local time2 = time()
8675 local velocity2 = head.Velocity
8676 position = position + 0.5 * (velocity1 + velocity2) * (time2 - time1)
8677 end
8678 camera.CoordinateFrame = CFrame.new(position, camera.Focus.p)
8679 end
8680 end
8681 end
8682 end)
8683 self.keyDownConnection = mouse.KeyDown:connect(function(key) self:KeyDown(key) end)
8684 self.mouseButton1DownConnection = mouse.Button1Down:connect(function() self:MouseButton1Down() end)
8685 self.mouseButton1UpConnection = mouse.Button1Up:connect(function() self:MouseButton1Up() end)
8686 self.mouseButton2DownConnection = mouse.Button2Down:connect(function() self:MouseButton2Down() end)
8687 self.mouseButton2UpConnection = mouse.Button2Up:connect(function() self:MouseButton2Up() end)
8688 self.mouseMoveConnection = mouse.Move:connect(function() self:MouseMove() end)
8689 self.steppedConnection = RunService.RenderStepped:connect(function() self:UpdateObjects() self:UpdateView() end)
8690 self.mousePreviousPosition = Vector2.new(self:GetMousePosition())
8691end
8692function GuiServiceClass:IsA(className)
8693 return className == "GuiService" or GuiBase.IsA(self, className)
8694end
8695function GuiServiceClass:KeyDown(key)
8696 local mnemonicButton = self.mnemonics[string.upper(key)]
8697 if mnemonicButton then
8698 mnemonicButton.Activated:fire()
8699 end
8700end
8701function GuiServiceClass:MouseButton1Down()
8702 local mouse = self.mouse
8703 local mouseX, mouseY = self:GetMousePosition()
8704 local stack = {self}
8705 local dragObjects = {}
8706 self.dragObjects = dragObjects
8707 while #stack > 0 do
8708 local object = stack[#stack]
8709 stack[#stack] = nil
8710 if object.visible then
8711 for child in pairs(object.children) do
8712 stack[#stack + 1] = child
8713 end
8714 if object.active then
8715 local position = object:GetAbsolutePosition()
8716 local size = object:GetAbsoluteSize()
8717 if mouseX >= position.X and mouseY >= position.Y and mouseX < position.X + size.X and mouseY < position.Y + size.Y then
8718 object.mouseDown = true
8719 dragObjects[object] = true
8720 local mouseButton1Down = object.MouseButton1Down
8721 if mouseButton1Down then
8722 mouseButton1Down:fire()
8723 if object.autoButtonColor then
8724 local color = object.color
8725 local transparency = object.backgroundTransparency
8726 object.m_base_instance.BackgroundColor3 = Color3.new(math.min(color.r + 0.3, 1), math.min(color.g +
8727
87280.3, 1), math.min(color.b + 0.3, 1))
8729 object.m_base_instance.BackgroundTransparency = transparency
8730 end
8731 end
8732 object.DragBegin:fire()
8733 end
8734 end
8735 end
8736 end
8737 self.mousePreviousPosition = Vector2.new(mouseX, mouseY)
8738end
8739function GuiServiceClass:MouseButton1Up()
8740 local mouse = self.mouse
8741 local mouseX, mouseY = self:GetMousePosition()
8742 local stack = {self}
8743 while #stack > 0 do
8744 local object = stack[#stack]
8745 stack[#stack] = nil
8746 if object.visible then
8747 for child in pairs(object.children) do
8748 stack[#stack + 1] = child
8749 end
8750 if object.active then
8751 local position = object:GetAbsolutePosition()
8752 local size = object:GetAbsoluteSize()
8753 if mouseX >= position.X and mouseY >= position.Y and mouseX < position.X + size.X and mouseY < position.Y + size.Y then
8754 object.MouseButton1Up:fire()
8755 end
8756 end
8757 end
8758 end
8759 local dragObjects = self.dragObjects
8760 self.dragObjects = nil
8761 if dragObjects then
8762 for dragObject in pairs(dragObjects) do
8763 dragObject.mouseDown = false
8764 local position = dragObject:GetAbsolutePosition()
8765 local size = dragObject:GetAbsoluteSize()
8766 if mouseX >= position.X and mouseY >= position.Y and mouseX < position.X + size.X and mouseY < position.Y + size.Y then
8767 dragObject.MouseButton1Click:fire()
8768 local activated = dragObject.Activated
8769 if activated then
8770 activated:fire()
8771 end
8772 end
8773 dragObject.DragStopped:fire()
8774 if dragObject.autoButtonColor then
8775 if dragObject.mouseOver then
8776 local color = dragObject.color
8777 local transparency = dragObject.backgroundTransparency
8778 dragObject.m_base_instance.BackgroundColor3 = Color3.new(math.max(color.r - 0.3, 0), math.max(color.g - 0.3, 0),
8779
8780math.max(color.b - 0.3, 0))
8781 dragObject.m_base_instance.BackgroundTransparency = math.max(0, transparency - 0.2)
8782 else
8783 dragObject.m_base_instance.BackgroundColor3 = dragObject.color
8784 dragObject.m_base_instance.BackgroundTransparency = dragObject.backgroundTransparency
8785 end
8786 end
8787 self.dragObject = nil
8788 end
8789 end
8790end
8791function GuiServiceClass:MouseButton2Down()
8792 local mouse = self.mouse
8793 local mouseX, mouseY = self:GetMousePosition()
8794 local stack = {self}
8795 while #stack > 0 do
8796 local object = stack[#stack]
8797 stack[#stack] = nil
8798 if object.visible then
8799 for child in pairs(object.children) do
8800 stack[#stack + 1] = child
8801 end
8802 if object.active then
8803 local position = object:GetAbsolutePosition()
8804 local size = object:GetAbsoluteSize()
8805 if mouseX >= position.X and mouseY >= position.Y and mouseX < position.X + size.X and mouseY < position.Y + size.Y then
8806 local mouseButton2Down = object.MouseButton2Down
8807 if mouseButton2Down then
8808 mouseButton2Down:fire()
8809 end
8810 end
8811 end
8812 end
8813 end
8814 self.mousePreviousPosition = Vector2.new(mouseX, mouseY)
8815end
8816function GuiServiceClass:MouseButton2Up()
8817 local mouse = self.mouse
8818 local mouseX, mouseY = self:GetMousePosition()
8819 local stack = {self}
8820 while #stack > 0 do
8821 local object = stack[#stack]
8822 stack[#stack] = nil
8823 if object.visible then
8824 for child in pairs(object.children) do
8825 stack[#stack + 1] = child
8826 end
8827 if object.active then
8828 local position = object:GetAbsolutePosition()
8829 local size = object:GetAbsoluteSize()
8830 if mouseX >= position.X and mouseY >= position.Y and mouseX < position.X + size.X and mouseY < position.Y + size.Y then
8831 local mouseButton2Up = object.MouseButton2Up
8832 if mouseButton2Up then
8833 mouseButton2Up:fire()
8834 end
8835 end
8836 end
8837 end
8838 end
8839end
8840function GuiServiceClass:MouseMove()
8841 self:UpdateObjects()
8842 local dragObjects = self.dragObjects
8843 if dragObjects then
8844 for dragObject in pairs(dragObjects) do
8845 local mouse = self.mouse
8846 local mousePosition = Vector2.new(self:GetMousePosition())
8847 dragObject.DragMove:fire(mousePosition - self.mousePreviousPosition)
8848 self.mousePreviousPosition = mousePosition
8849 end
8850 end
8851end
8852function GuiServiceClass:SetMnemonic(mnemonic, button)
8853 self.mnemonics[mnemonic] = button
8854end
8855function GuiServiceClass:UpdateObjects()
8856 local mouse = self.mouse
8857 local mouseX, mouseY = self:GetMousePosition()
8858 local stack = {self}
8859 while #stack > 0 do
8860 local object = stack[#stack]
8861 stack[#stack] = nil
8862 if object.visible then
8863 for child in pairs(object.children) do
8864 stack[#stack + 1] = child
8865 end
8866 if object.active then
8867 local position = object:GetAbsolutePosition()
8868 local size = object:GetAbsoluteSize()
8869 if mouseX >= position.X and mouseY >= position.Y and mouseX < position.X + size.X and mouseY < position.Y + size.Y then
8870 if not object.mouseOver then
8871 object.mouseOver = true
8872 object.MouseEnter:fire()
8873 if object.autoButtonColor then
8874 local color = object.color
8875 local transparency = object.backgroundTransparency
8876 if object.mouseDown then
8877 object.m_base_instance.BackgroundColor3 = Color3.new(math.min(color.r + 0.3, 1), math.min
8878
8879(color.g + 0.3, 1), math.min(color.b + 0.3, 1))
8880 object.m_base_instance.BackgroundTransparency = transparency
8881 else
8882 object.m_base_instance.BackgroundColor3 = Color3.new(math.max(color.r - 0.3, 0), math.max
8883
8884(color.g - 0.3, 0), math.max(color.b - 0.3, 0))
8885 object.m_base_instance.BackgroundTransparency = math.max(0, transparency - 0.2)
8886 end
8887 end
8888 end
8889 else
8890 if object.mouseOver then
8891 object.mouseOver = false
8892 object.MouseLeave:fire()
8893 if object.autoButtonColor then
8894 object.m_base_instance.BackgroundColor3 = object.color
8895 object.m_base_instance.BackgroundTransparency = object.backgroundTransparency
8896 end
8897 end
8898 end
8899 end
8900 end
8901 end
8902end
8903function GuiServiceClass:UpdateView()
8904 local billboardGui = self.billboardGui
8905 local guiFrame = self.m_base_instance
8906 local camera = self.camera
8907 local mouse = self.mouse
8908 local cameraCFrame = CFrame.new(camera.CoordinateFrame.p, camera.Focus.p) -- camera.CoordinateFrame
8909 local viewSizeX, viewSizeY = mouse.ViewSizeX, mouse.ViewSizeY
8910 local previousViewSize = self.viewSize
8911 if not previousViewSize or ((viewSizeX ~= 0 or viewSizeY ~= 0) and (viewSizeX ~= previousViewSize.X or viewSizeY ~= previousViewSize.Y)) then
8912 self.viewSize = {X = viewSizeX, Y = viewSizeY}
8913 local viewSizeUDim2 = UDim2.new(0, viewSizeX, 0, viewSizeY)
8914 billboardGui.Size = viewSizeUDim2
8915 guiFrame.Size = viewSizeUDim2
8916 -- FIXME:
8917 -- After the 15th of July 2014, there came an offset at the Y thingy out of nowhere so I accomodated for that.
8918 billboardGui.SizeOffset = Vector2.new(0.5 / viewSizeX, (0.5 + 10) / viewSizeY)
8919 end
8920 --billboardGui.SizeOffset = Vector2.new()
8921 billboardGui.StudsOffset = (cameraCFrame - cameraCFrame.p):inverse() * cameraCFrame.p - Vector3.new(0, 0, 1)
8922end
8923GuiService = GuiServiceClass:new {
8924 Camera = Camera,
8925 Mouse = Mouse
8926}
8927GuiFrame = setmetatable({}, GuiObject)
8928GuiFrame.__index = GuiFrame
8929GuiFrame.__default = {__index = {
8930 Active = false,
8931 BackgroundTransparency = 0.75,
8932 BorderSize = 4,
8933 BorderTransparency = 0.75,
8934 Color = AdvancedGUI.GUI_BASE_COLOR,
8935 Position = UDim2.new(0, 0, 0, 0),
8936 Size = UDim2.new(0, 52, 0, 52),
8937 Visible = true
8938}}
8939function GuiFrame:Destroy()
8940 GuiObject.Destroy(self)
8941end
8942function GuiFrame:GetContentInstance()
8943 return self.m_content_frame
8944end
8945function GuiFrame:Init(data)
8946 GuiObject.Init(self)
8947 setmetatable(data, GuiFrame.__default)
8948 local leftBorderFrameLeft = RBXInstance.new "Frame" {
8949 BackgroundColor3 = Color3.new(0, 0, 0),
8950 BorderSizePixel = 0,
8951 Size = UDim2.new(0, 1, 1, -1)
8952 }
8953 local leftBorderFrameCenter = RBXInstance.new "Frame" {
8954 BackgroundColor3 = Color3.new(1, 1, 1),
8955 BorderSizePixel = 0,
8956 Position = UDim2.new(0, 1, 0, 1)
8957 }
8958 local leftBorderFrameRight = RBXInstance.new "Frame" {
8959 BackgroundColor3 = Color3.new(0, 0, 0),
8960 BorderSizePixel = 0
8961 }
8962 local rightBorderFrameRight = RBXInstance.new "Frame" {
8963 BackgroundColor3 = Color3.new(0, 0, 0),
8964 BorderSizePixel = 0,
8965 Position = UDim2.new(1, -1, 0, 1),
8966 Size = UDim2.new(0, 1, 1, -1)
8967 }
8968 local rightBorderFrameCenter = RBXInstance.new "Frame" {
8969 BackgroundColor3 = Color3.new(1, 1, 1),
8970 BorderSizePixel = 0
8971 }
8972 local rightBorderFrameLeft = RBXInstance.new "Frame" {
8973 BackgroundColor3 = Color3.new(0, 0, 0),
8974 BorderSizePixel = 0
8975 }
8976 local bottomBorderFrameBottom = RBXInstance.new "Frame" {
8977 BackgroundColor3 = Color3.new(0, 0, 0),
8978 BorderSizePixel = 0,
8979 Position = UDim2.new(0, 0, 1, -1),
8980 Size = UDim2.new(1, -1, 0, 1)
8981 }
8982 local bottomBorderFrameCenter = RBXInstance.new "Frame" {
8983 BackgroundColor3 = Color3.new(1, 1, 1),
8984 BorderSizePixel = 0
8985 }
8986 local bottomBorderFrameTop = RBXInstance.new "Frame" {
8987 BackgroundColor3 = Color3.new(0, 0, 0),
8988 BorderSizePixel = 0
8989 }
8990 local topBorderFrameTop = RBXInstance.new "Frame" {
8991 BackgroundColor3 = Color3.new(0, 0, 0),
8992 BorderSizePixel = 0,
8993 Position = UDim2.new(0, 1, 0, 0),
8994 Size = UDim2.new(1, -1, 0, 1)
8995 }
8996 local topBorderFrameCenter = RBXInstance.new "Frame" {
8997 BackgroundColor3 = Color3.new(1, 1, 1),
8998 BorderSizePixel = 0
8999 }
9000 local topBorderFrameBottom = RBXInstance.new "Frame" {
9001 BackgroundColor3 = Color3.new(0, 0, 0),
9002 BorderSizePixel = 0
9003 }
9004 local border_frame = RBXInstance.new "Frame" {
9005 BackgroundTransparency = 1,
9006 Size = UDim2.new(1, 0, 1, 0),
9007 leftBorderFrameLeft,
9008 leftBorderFrameCenter,
9009 leftBorderFrameRight,
9010 rightBorderFrameLeft,
9011 rightBorderFrameCenter,
9012 rightBorderFrameRight,
9013 bottomBorderFrameBottom,
9014 bottomBorderFrameCenter,
9015 bottomBorderFrameTop,
9016 topBorderFrameBottom,
9017 topBorderFrameCenter,
9018 topBorderFrameTop
9019 }
9020 local contentFrame = RBXInstance.new "Frame" {
9021 BackgroundTransparency = 1,
9022 BorderSizePixel = 0,
9023 ClipsDescendants = true,
9024 Size = UDim2.new(1, 0, 1, 0)
9025 }
9026 local base_frame = RBXInstance.new "Frame" {
9027 BorderSizePixel = 0,
9028 border_frame,
9029 contentFrame
9030 }
9031 self.m_base_instance = base_frame
9032 self.m_content_frame = contentFrame
9033 self.m_border_frame = border_frame
9034 self.leftBorderFrameLeft = leftBorderFrameLeft
9035 self.leftBorderFrameCenter = leftBorderFrameCenter
9036 self.leftBorderFrameRight = leftBorderFrameRight
9037 self.rightBorderFrameLeft = rightBorderFrameLeft
9038 self.rightBorderFrameCenter = rightBorderFrameCenter
9039 self.rightBorderFrameRight = rightBorderFrameRight
9040 self.bottomBorderFrameBottom = bottomBorderFrameBottom
9041 self.bottomBorderFrameCenter = bottomBorderFrameCenter
9042 self.bottomBorderFrameTop = bottomBorderFrameTop
9043 self.topBorderFrameBottom = topBorderFrameBottom
9044 self.topBorderFrameCenter = topBorderFrameCenter
9045 self.topBorderFrameTop = topBorderFrameTop
9046 self:SetActive(data.Active)
9047 self:SetBackgroundTransparency(data.BackgroundTransparency)
9048 self:SetBorderSize(data.BorderSize)
9049 self:SetBorderTransparency(data.BorderTransparency)
9050 self:SetColor(data.Color)
9051 self:SetPosition(data.Position)
9052 self:SetSize(data.Size)
9053 self:SetVisible(data.Visible)
9054 self:SetParent(data.Parent)
9055end
9056function GuiFrame:IsA(className)
9057 return className == "GuiFrame" or GuiObject.IsA(self, className)
9058end
9059function GuiFrame:SetBorderSize(border_size)
9060 border_size = math.max(math.floor(border_size + 0.5), 0)
9061 if border_size ~= self.m_border_size then
9062 self.m_border_size = border_size
9063 local border_frame = self.m_border_frame
9064 local contentFrame = self.m_content_frame
9065 local leftBorderFrameCenter = self.leftBorderFrameCenter
9066 local leftBorderFrameRight = self.leftBorderFrameRight
9067 local rightBorderFrameCenter = self.rightBorderFrameCenter
9068 local rightBorderFrameLeft = self.rightBorderFrameLeft
9069 local bottomBorderFrameCenter = self.bottomBorderFrameCenter
9070 local bottomBorderFrameTop = self.bottomBorderFrameTop
9071 local topBorderFrameCenter = self.topBorderFrameCenter
9072 local topBorderFrameBottom = self.topBorderFrameBottom
9073 contentFrame.Position = UDim2.new(0, border_size, 0, border_size)
9074 contentFrame.Size = UDim2.new(1, -2 * border_size, 1, -2 * border_size)
9075 local inner_visible = border_size > 0
9076 if self.leftBorderFrameLeft.Visible ~= inner_visible then
9077 self.rightBorderFrameRight.Visible = inner_visible
9078 self.bottomBorderFrameBottom.Visible = inner_visible
9079 self.topBorderFrameTop.Visible = inner_visible
9080 end
9081 local outer_visible = border_size > 1
9082 if leftBorderFrameCenter.Visible ~= outer_visible then
9083 leftBorderFrameCenter.Visible = outer_visible
9084 leftBorderFrameRight.Visible = outer_visible
9085 rightBorderFrameCenter.Visible = outer_visible
9086 rightBorderFrameLeft.Visible = outer_visible
9087 bottomBorderFrameCenter.Visible = outer_visible
9088 bottomBorderFrameTop.Visible = outer_visible
9089 topBorderFrameCenter.Visible = outer_visible
9090 topBorderFrameBottom.Visible = outer_visible
9091 end
9092 if outer_visible then
9093 leftBorderFrameCenter.Size = UDim2.new(0, border_size - 2, 1, -border_size)
9094 leftBorderFrameRight.Position = UDim2.new(0, border_size - 1, 0, border_size - 1)
9095 leftBorderFrameRight.Size = UDim2.new(0, 1, 1, 1 - 2 * border_size)
9096 rightBorderFrameCenter.Position = UDim2.new(1, 1 - border_size, 0, border_size - 1)
9097 rightBorderFrameCenter.Size = UDim2.new(0, border_size - 2, 1, -border_size)
9098 rightBorderFrameLeft.Position = UDim2.new(1, -border_size, 0, border_size)
9099 rightBorderFrameLeft.Size = UDim2.new(0, 1, 1, 1 - 2 * border_size)
9100 bottomBorderFrameCenter.Position = UDim2.new(0, 1, 1, 1 - border_size)
9101 bottomBorderFrameCenter.Size = UDim2.new(1, -border_size, 0, border_size - 2)
9102 bottomBorderFrameTop.Position = UDim2.new(0, border_size - 1, 1, -border_size)
9103 bottomBorderFrameTop.Size = UDim2.new(1, 1 - 2 * border_size, 0, 1)
9104 topBorderFrameCenter.Position = UDim2.new(0, border_size - 1, 0, 1)
9105 topBorderFrameCenter.Size = UDim2.new(1, -border_size, 0, border_size - 2)
9106 topBorderFrameBottom.Position = UDim2.new(0, border_size, 0, border_size - 1)
9107 topBorderFrameBottom.Size = UDim2.new(1, 1 - 2 * border_size, 0, 1)
9108 end
9109 end
9110end
9111function GuiFrame:SetBorderTransparency(borderTransparency)
9112 self.borderTransparency = borderTransparency
9113 self.leftBorderFrameLeft.BackgroundTransparency = borderTransparency
9114 self.leftBorderFrameCenter.BackgroundTransparency = borderTransparency
9115 self.leftBorderFrameRight.BackgroundTransparency = borderTransparency
9116 self.rightBorderFrameLeft.BackgroundTransparency = borderTransparency
9117 self.rightBorderFrameCenter.BackgroundTransparency = borderTransparency
9118 self.rightBorderFrameRight.BackgroundTransparency = borderTransparency
9119 self.bottomBorderFrameBottom.BackgroundTransparency = borderTransparency
9120 self.bottomBorderFrameCenter.BackgroundTransparency = borderTransparency
9121 self.bottomBorderFrameTop.BackgroundTransparency = borderTransparency
9122 self.topBorderFrameBottom.BackgroundTransparency = borderTransparency
9123 self.topBorderFrameCenter.BackgroundTransparency = borderTransparency
9124 self.topBorderFrameTop.BackgroundTransparency = borderTransparency
9125end
9126GuiButton = setmetatable({}, GuiFrame)
9127GuiButton.__index = GuiButton
9128GuiButton.__default = {__index = {
9129 AutoButtonColor = true
9130}}
9131function GuiButton:Destroy()
9132 self.Activated:disconnect()
9133 GuiFrame.Destroy(self)
9134end
9135function GuiButton:Init(data)
9136 if data.Active == nil then
9137 data.Active = true
9138 end
9139 GuiFrame.Init(self, data)
9140 setmetatable(data, GuiButton.__default)
9141 self.Activated = RbxUtility.CreateSignal()
9142 self:SetAutoButtonColor(data.AutoButtonColor)
9143end
9144function GuiButton:IsA(className)
9145 return className == "GuiButton" or GuiFrame.IsA(self, className)
9146end
9147function GuiButton:SetAutoButtonColor(autoButtonColor)
9148 if autoButtonColor ~= self.autoButtonColor then
9149 self.autoButtonColor = autoButtonColor
9150 if autoButtonColor then
9151 if self.mouseOver then
9152 local color = self.color
9153 local transparency = self.backgroundTransparency
9154 if self.mouseDown then
9155 self.m_base_instance.BackgroundColor3 = Color3.new(math.min(color.r + 0.3, 1), math.min(color.g + 0.3, 1), math.min
9156
9157(color.b + 0.3, 1))
9158 self.m_base_instance.BackgroundTransparency = transparency
9159 else
9160 self.m_base_instance.BackgroundColor3 = Color3.new(math.max(color.r - 0.3, 0), math.max(color.g - 0.3, 0), math.max
9161
9162(color.b - 0.3, 0))
9163 self.m_base_instance.BackgroundTransparency = math.max(0, transparency - 0.5)
9164 end
9165 end
9166 else
9167 self.m_base_instance.BackgroundColor3 = self.color
9168 end
9169 end
9170end
9171GuiTextLabel = setmetatable({}, GuiFrame)
9172GuiTextLabel.__index = GuiTextLabel
9173GuiTextLabel.__default = {__index = {
9174 Font = "ArialBold",
9175 FontSize = "Size12",
9176 Text = "",
9177 TextColor = Color3.new(1, 1, 1),
9178 TextStrokeColor = Color3.new(0, 0, 0),
9179 TextStrokeTransparency = 0.6,
9180 TextWrapped = true
9181}}
9182function GuiTextLabel:Destroy()
9183 GuiFrame.Destroy(self)
9184end
9185function GuiTextLabel:Init(data)
9186 GuiFrame.Init(self, data)
9187 setmetatable(data, GuiTextLabel.__default)
9188 local base_instance = self.m_base_instance
9189 local textLabel = RBXInstance.new "TextLabel" {
9190 BackgroundTransparency = 1,
9191 Font = data.Font,
9192 FontSize = data.FontSize,
9193 TextColor3 = data.TextColor3,
9194 TextStrokeColor3 = data.TextStrokeColor3,
9195 TextStrokeTransparency = data.TextStrokeTransparency,
9196 TextWrapped = data.TextWrapped
9197 }
9198 textLabel.Parent = self:GetContentInstance()
9199 self.textLabel = textLabel
9200 self:SetText(data.Text)
9201end
9202function GuiTextLabel:IsA(className)
9203 return className == "GuiTextLabel" or GuiFrame.IsA(self, className)
9204end
9205function GuiTextLabel:SetText(text)
9206 if text ~= self.text then
9207 self.text = text
9208 local text_index = 1
9209 local content_instance = self:GetContentInstance()
9210 local content_instance_size = content_instance.AbsoluteSize
9211 local frame = Instance.new("Frame")
9212 frame.BackgroundTransparency = 1
9213 local label = Instance.new("TextLabel")
9214 label.BackgroundTransparency = 1
9215 label.Font = font
9216 label.FontSize = fontSize
9217 label.Size = UDim2.new(0, content_instance_size.X, 0, 1000)
9218 label.Text = ""
9219 label.TextColor3 = textColor3
9220 label.TextTransparency = 1
9221 label.TextWrapped = true
9222 label.TextXAlignment = textXAlignment
9223 label.TextYAlignment = textYAlignment
9224 label.Parent = self.guiFrame
9225 local row_length = 0
9226 local step_size = 256
9227 for step = 1, 8 do
9228 step_size = 0.5 * step_size
9229 label.Text = string.sub(text, text_index, text_index + row_length - 1)
9230 end
9231 end
9232end
9233GuiImageButton = setmetatable({}, GuiButton)
9234GuiImageButton.__index = GuiImageButton
9235GuiImageButton.__default = {__index = {
9236 Image = ""
9237}}
9238function GuiImageButton:Destroy()
9239 GuiButton.Destroy(self)
9240end
9241function GuiImageButton:Init(data)
9242 GuiButton.Init(self, data)
9243 setmetatable(data, GuiImageButton.__default)
9244 local content_frame = self.m_content_frame
9245 local image_label = RBXInstance.new "ImageLabel" {
9246 BackgroundTransparency = 1,
9247 Size = UDim2.new(1, 0, 1, 0)
9248 }
9249 image_label.Parent = content_frame
9250 self.m_image_label = image_label
9251 self:SetImage(data.Image)
9252end
9253function GuiImageButton:IsA(className)
9254 return className == "GuiImageButton" or GuiButton.IsA(self, className)
9255end
9256function GuiImageButton:SetImage(image)
9257 if image ~= self.m_image then
9258 self.m_image = image
9259 self.m_image_label.Image = image
9260 end
9261end
9262GuiTextButton = setmetatable({}, GuiButton)
9263GuiTextButton.__index = GuiTextButton
9264GuiTextButton.__default = {__index = {
9265 Font = Enum.Font.ArialBold,
9266 FontSize = Enum.FontSize.Size11,
9267 Text = "Button",
9268 TextXAlignment = Enum.TextXAlignment.Center
9269}}
9270function GuiTextButton:Destroy()
9271 GuiButton.Destroy(self)
9272end
9273function GuiTextButton:GetTextBounds()
9274 return self.textLabel.TextBounds
9275end
9276function GuiTextButton:Init(data)
9277 GuiButton.Init(self, data)
9278 setmetatable(data, GuiTextButton.__default)
9279 local contentFrame = self.m_content_frame
9280 local mnemonicLabel = RBXInstance.new "TextLabel" {
9281 BackgroundTransparency = 1,
9282 Font = "ArialBold",
9283 FontSize = "Size36",
9284 Size = UDim2.new(1, 0, 0.7, 0),
9285 TextColor3 = Color3.new(1, 1, 1),
9286 TextStrokeColor3 = Color3.new(0, 0, 0),
9287 TextStrokeTransparency = 0.6,
9288 TextWrapped = true
9289 }
9290 local textLabel = RBXInstance.new "TextLabel" {
9291 BackgroundTransparency = 1,
9292 TextColor3 = Color3.new(1, 1, 1),
9293 TextStrokeColor3 = Color3.new(0, 0, 0),
9294 TextStrokeTransparency = 0.6,
9295 TextWrapped = true
9296 }
9297 mnemonicLabel.Parent = contentFrame
9298 textLabel.Parent = contentFrame
9299 self.mnemonicLabel = mnemonicLabel
9300 self.textLabel = textLabel
9301 self:SetFont(data.Font)
9302 self:SetFontSize(data.FontSize)
9303 self:SetMnemonic(data.Mnemonic, true)
9304 self:SetText(data.Text)
9305 self:SetTextXAlignment(data.TextXAlignment)
9306end
9307function GuiTextButton:IsA(className)
9308 return className == "GuiTextButton" or GuiButton.IsA(self, className)
9309end
9310function GuiTextButton:SetFont(font)
9311 if font ~= self.font then
9312 self.font = font
9313 self.textLabel.Font = font
9314 end
9315end
9316function GuiTextButton:SetFontSize(fontSize)
9317 if fontSize ~= self.fontSize then
9318 self.fontSize = fontSize
9319 self.textLabel.FontSize = fontSize
9320 end
9321end
9322function GuiTextButton:SetMnemonic(mnemonic, forceUpdate)
9323 if mnemonic ~= self.mnemonic or forceUpdate then
9324 if self.mnemonic then
9325 GuiService:SetMnemonic(self.mnemonic, nil)
9326 end
9327 if mnemonic then
9328 GuiService:SetMnemonic(mnemonic, self)
9329 end
9330 self.mnemonic = mnemonic
9331 local mnemonicLabel = self.mnemonicLabel
9332 local textLabel = self.textLabel
9333 if mnemonic then
9334 mnemonicLabel.Text = mnemonic
9335 textLabel.Size = UDim2.new(1, 0, 0.9, 0)
9336 textLabel.TextYAlignment = "Bottom"
9337 else
9338 mnemonicLabel.Text = ""
9339 textLabel.Size = UDim2.new(1, 0, 1, 0)
9340 textLabel.TextYAlignment = "Center"
9341 end
9342 end
9343end
9344function GuiTextButton:SetText(text)
9345 if text ~= self.text then
9346 self.text = text
9347 self.textLabel.Text = text
9348 end
9349end
9350function GuiTextButton:SetTextXAlignment(textXAlignment)
9351 if textXAlignment ~= self.textXAlignment then
9352 self.textXAlignment = textXAlignment
9353 self.textLabel.TextXAlignment = textXAlignment
9354 end
9355end
9356GuiWindow = setmetatable({}, GuiObject)
9357GuiWindow.__index = GuiWindow
9358GuiWindow.__default = {__index = {
9359 Active = true,
9360 BackgroundTransparency = 0.5,
9361 BorderSize = 4,
9362 BorderTransparency = 0.5,
9363 Position = UDim2.new(0, 0, 0, 0),
9364 Size = UDim2.new(0, 360, 0, 240),
9365 Title = "Window",
9366 TitleBarBackgroundTransparency = 0.5,
9367 TitleBarBorderTransparency = 1,
9368 Visible = true
9369}}
9370function GuiWindow:Init(data)
9371 GuiObject.Init(self)
9372 setmetatable(data, GuiFrame.__default)
9373 local title_bar = GuiTextLabel:new {
9374 BackgroundTransparency = data.TitleBarBackgroundTransparency,
9375 BorderTransparency = data.TitleBarBackgroundTransparency,
9376 Text = data.Title
9377 }
9378 local content_frame = GuiFrame:new {
9379 Active = data.Active,
9380 BackgroundTransparency = data.BackgroundTransparency,
9381 BorderSize = data.BorderSize,
9382 BorderTransparency = data.BorderTransparency
9383 }
9384 local base_frame = RBXInstance.new "Frame" {
9385 BackgroundTransparency = 1,
9386 BorderSizePixel = 0,
9387 Position = data.Position,
9388 Size = data.Size,
9389 Visible = data.Visible
9390 }
9391 self.m_base_frame = base_frame
9392 self.m_content_frame = content_frame
9393 self.m_title_bar = title_bar
9394end
9395function GuiWindow:IsA(className)
9396 return className == "GuiWindow" or GuiObject.IsA(self, className)
9397end
9398GuiScrollFrame = setmetatable({}, GuiFrame)
9399GuiScrollFrame.__index = GuiScrollFrame
9400GuiScrollFrame.__default = {__index = {
9401 ContentHeight = 0,
9402 ScrollBarColor = Color3.new(1, 1, 1)
9403}}
9404function GuiScrollFrame:Destroy()
9405 self.m_scroll_bar:Destroy()
9406 GuiFrame.Destroy(self)
9407end
9408function GuiScrollFrame:GetContentInstance()
9409 return self.m_scroll_frame or GuiFrame.GetContentInstance(self)
9410end
9411function GuiScrollFrame:Init(data)
9412 GuiFrame.Init(self, data)
9413 setmetatable(data, GuiScrollFrame.__default)
9414 local scroll_pane = RBXInstance.new "Frame" {
9415 BackgroundColor3 = Color3.new(1, 1, 1),
9416 BackgroundTransparency = 0.8,
9417 BorderSizePixel = 0,
9418 Position = UDim2.new(1, -20, 0, 0),
9419 Size = UDim2.new(0, 20, 1, 0),
9420 Parent = self.m_content_frame
9421 }
9422 local scroll_bar = GuiFrame:new {
9423 Active = true,
9424 BackgroundTransparency = 0.6,
9425 BorderTransparency = 0.6,
9426 Color = data.ScrollBarColor,
9427 Parent = self
9428 }
9429 local scroll_frame = RBXInstance.new "Frame" {
9430 BackgroundTransparency = 1,
9431 Parent = self.m_content_frame
9432 }
9433 self.m_scroll_bar = scroll_bar
9434 self.m_scroll_frame = scroll_frame
9435 self.m_scroll_pane = scroll_pane
9436 self.m_scroll_position = 0
9437 self.m_updating_content_height = false
9438 self:SetContentHeight(data.ContentHeight)
9439 self:UpdateScrollPosition()
9440 self.m_scroll_bar.DragBegin:connect(function()
9441 self.m_scroll_drag_total = Vector2.new()
9442 self.m_scroll_initial_position = self.m_scroll_position
9443 end)
9444 self.m_scroll_bar.DragMove:connect(function(offset)
9445 self.m_scroll_drag_total = self.m_scroll_drag_total + offset
9446 local absolute_height = self:GetAbsoluteSize().Y - 2 * self.m_border_size
9447 if absolute_height ~= 0 then
9448 local content_height = math.max(self.m_content_height, absolute_height)
9449 local scroll_space = 1 - absolute_height / content_height
9450 self:Scroll(self.m_scroll_initial_position + self.m_scroll_drag_total.Y * (content_height / absolute_height - 1) / scroll_space)
9451 end
9452 end)
9453end
9454function GuiScrollFrame:IsA(className)
9455 return className == "GuiScrollFrame" or GuiFrame.IsA(self, className)
9456end
9457function GuiScrollFrame:Scroll(position)
9458 position = math.min(math.max(position, 0), self.m_content_height - (self:GetAbsoluteSize().Y - 2 * self.m_border_size))
9459 if position ~= self.m_scroll_position then
9460 self.m_scroll_position = position
9461 self:UpdateScrollPosition()
9462 end
9463end
9464function GuiScrollFrame:SetContentHeight(height)
9465 if height ~= self.m_content_height then
9466 local prev_height = self.m_content_height
9467 self.m_content_height = height
9468 if not self.m_updating_content_height then
9469 self.m_updating_content_height = true
9470 coroutine.resume(coroutine.create(function()
9471 local success, message = ypcall(self.SetContentHeightImpl1, self, prev_height)
9472 if not success then
9473 Logger.printf("Severe", "Error in GuiScrollFrame:SetContentHeight(%s): %s", Utility.ToString(height), message)
9474 end
9475 end))
9476 end
9477 end
9478end
9479function GuiScrollFrame:SetContentHeightImpl1(prev_height)
9480 RunService.RenderStepped:wait()
9481 self.m_updating_content_height = false
9482 local height = self.m_content_height
9483 self.m_scroll_frame.Size = UDim2.new(1, -20, 0, height)
9484 if prev_height and prev_height ~= 0 then
9485 local absolute_height = self:GetAbsoluteSize().Y - 2 * self.m_border_size
9486 if self.m_scroll_position == prev_height - absolute_height then
9487 self.m_scroll_position = height - absolute_height
9488 else
9489 self.m_scroll_position = height * self.m_scroll_position / prev_height
9490 end
9491 end
9492 self:UpdateScrollPosition()
9493end
9494function GuiScrollFrame:UpdateScrollPosition()
9495 local absolute_height = self:GetAbsoluteSize().Y - 2 * self.m_border_size
9496 if absolute_height == 0 then
9497 absolute_height = self.m_content_height
9498 end
9499 local scroll_bar = self.m_scroll_bar
9500 local scroll_frame = self.m_scroll_frame
9501 local scroll_pane = self.m_scroll_pane
9502 local content_height = math.max(self.m_content_height, absolute_height)
9503 if absolute_height == content_height then
9504 scroll_frame.Position = UDim2.new(0, 0, 0, 0)
9505 scroll_frame.Size = UDim2.new(1, 0, 1, 0)
9506 scroll_bar:SetVisible(false)
9507 scroll_pane.Visible = false
9508 else
9509 local contentScale = content_height / absolute_height
9510 local scroll_space = 1 - absolute_height / content_height
9511 local scroll_position = self.m_scroll_position
9512 scroll_frame.Position = UDim2.new(0, 0, 0, -scroll_position)
9513 scroll_bar:SetPosition(UDim2.new(1, -20, scroll_position / (content_height - absolute_height) * scroll_space, 0))
9514 scroll_bar:SetSize(UDim2.new(0, 20, absolute_height / content_height, 0))
9515 scroll_bar:SetVisible(true)
9516 scroll_pane.Visible = true
9517 end
9518end
9519GuiMenu = setmetatable({}, GuiFrame)
9520GuiMenu.__index = GuiMenu
9521GuiMenu.__default = {__index = {
9522 VerticalSpacing = 18
9523}}
9524function GuiMenu:AddItem(text, onClick, options)
9525 local frameSize = self:GetSize()
9526 local frameHeight = frameSize.Y.Offset - self.m_border_size * 2
9527 local verticalSpacing = self.verticalSpacing
9528 local properties = {
9529 BackgroundTransparency = 0.75,
9530 BorderSize = 0,
9531 BorderTransparency = 1,
9532 Color = (#self.menuItems % 2 == 1) and Color3.new(0.25, 0.25, 0.25) or Color3.new(0, 0, 0),
9533 FontSize = Enum.FontSize.Size12,
9534 Position = UDim2.new(0, 0, 0, frameHeight),
9535 Size = UDim2.new(1, 0, 0, verticalSpacing),
9536 Text = text,
9537 Parent = self
9538 }
9539 if options then
9540 for key, value in pairs(options) do
9541 properties[key] = value
9542 end
9543 end
9544 local menuItem = GuiTextButton:new(properties)
9545 if onClick then
9546 menuItem.Activated:connect(function()
9547 if not onClick(text, self) then
9548 self:Destroy()
9549 end
9550 end)
9551 end
9552 self.menuItems[#self.menuItems + 1] = menuItem
9553 self:SetSize(frameSize + UDim2.new(0, 0, 0, verticalSpacing))
9554end
9555function GuiMenu:ClearItems()
9556 local menuItems = self.menuItems
9557 for _, item in ipairs(menuItems) do
9558 menuItems[item] = nil
9559 item:Destroy()
9560 end
9561 local frameSize = self:GetSize()
9562 self:SetSize(frameSize + UDim2.new(0, 0, 0, self.m_border_size * 2 - frameSize.Y.Offset))
9563end
9564function GuiMenu:Destroy()
9565 self:ClearItems()
9566 GuiFrame.Destroy(self)
9567end
9568function GuiMenu:Init(data)
9569 GuiFrame.Init(self, data)
9570 setmetatable(data, GuiMenu.__default)
9571 self.menuItems = {}
9572 self.verticalSpacing = data.VerticalSpacing
9573end
9574function GuiMenu:IsA(className)
9575 return className == "GuiMenu" or GuiFrame.IsA(self, className)
9576end
9577GuiTextList = setmetatable({}, GuiScrollFrame)
9578GuiTextList.__index = GuiTextList
9579GuiTextList.__default = {__index = {
9580}}
9581function GuiTextList:AddItem(text, options)
9582 local properties = {
9583 BackgroundTransparency = 1,
9584 Font = "ArialBold",
9585 FontSize = "Size12",
9586 Position = UDim2.new(0, 4, 0, self.m_content_height),
9587 Size = UDim2.new(1, -8, 0, 12),
9588 Text = tostring(text),
9589 TextColor3 = Color3.new(1, 1, 1),
9590 TextStrokeTransparency = 0.6,
9591 TextWrapped = true,
9592 TextXAlignment = "Left",
9593 Parent = self:GetContentInstance()
9594 }
9595 if options then
9596 for key, value in pairs(options) do
9597 properties[key] = value
9598 end
9599 end
9600 local textLabel = RBXInstance.new "TextLabel" (properties)
9601 textLabel.Size = UDim2.new(1, 0, 0, textLabel.TextBounds.Y)
9602 self.listItems[#self.listItems + 1] = textLabel
9603 self:SetContentHeight(self.m_content_height + textLabel.TextBounds.Y)
9604end
9605function GuiTextList:ClearItems()
9606 local listItems = self.listItems
9607 for _, item in ipairs(listItems) do
9608 listItems[item] = nil
9609 item:Destroy()
9610 end
9611 self:SetContentHeight(0)
9612end
9613function GuiTextList:Destroy()
9614 self:ClearItems()
9615 GuiScrollFrame.Destroy(self)
9616end
9617function GuiTextList:Init(data)
9618 GuiScrollFrame.Init(self, data)
9619 self.listItems = {}
9620end
9621function GuiTextList:IsA(className)
9622 return className == "GuiTextList" or GuiScrollFrame.IsA(self, className)
9623end
9624GuiNetworkList = setmetatable({}, GuiTextList)
9625GuiNetworkList.__index = GuiNetworkList
9626function GuiNetworkList:AddItem(systemTime, idleTime, userName, isNil)
9627 local frame = GuiFrame:new {
9628 BackgroundTransparency = 1,
9629 BorderSize = 0,
9630 BorderTransparency = 1,
9631 Position = UDim2.new(0, 4, 0, self.m_content_height),
9632 Size = UDim2.new(1, -8, 0, 14),
9633 }
9634 local systemTimeColor
9635 if string.sub(systemTime, 1, 1) == "?" then
9636 systemTimeColor = Color3.new(1, 0.75, 0.75)
9637 else
9638 systemTimeColor = Color3.new(0.75, 0.75, 1)
9639 end
9640 local systemTimeLabel = RBXInstance.new "TextLabel" {
9641 BackgroundTransparency = 1,
9642 Font = "ArialBold",
9643 FontSize = "Size12",
9644 Position = UDim2.new(0, 0, 0, 0),
9645 Size = UDim2.new(0, 50, 1, 0),
9646 Text = systemTime,
9647 TextColor3 = systemTimeColor,
9648 TextStrokeTransparency = 0.6,
9649 TextXAlignment = "Left",
9650 Parent = frame:GetContentInstance()
9651 }
9652 local idle_time_color
9653 if string.sub(idleTime, 1, 1) == "0" then
9654 idle_time_color = Color3.new(1, 1, 1)
9655 else
9656 idle_time_color = Color3.new(1, 0.75, 0.75)
9657 end
9658 local idleTimeLabel = RBXInstance.new "TextLabel" {
9659 BackgroundTransparency = 1,
9660 Font = "ArialBold",
9661 FontSize = "Size12",
9662 Position = UDim2.new(0, 40, 0, 0),
9663 Size = UDim2.new(0, 45, 1, 0),
9664 Text = idleTime,
9665 TextColor3 = idle_time_color,
9666 TextStrokeTransparency = 0.6,
9667 TextXAlignment = "Right",
9668 Parent = frame:GetContentInstance()
9669 }
9670 local userNameLabel = GuiTextButton:new {
9671 AutoButtonColor = false,
9672 BackgroundTransparency = 1,
9673 BorderSize = 0,
9674 BorderTransparency = 1,
9675 Font = Enum.Font.SourceSansBold,
9676 FontSize = Enum.FontSize.Size14,
9677 Position = UDim2.new(0, 98, 0, 0),
9678 Size = UDim2.new(1, -98, 1, 0),
9679 TextXAlignment = Enum.TextXAlignment.Left,
9680 Text = userName,
9681 Parent = frame
9682 }
9683 userNameLabel.MouseButton2Down:connect(function()
9684 self:ShowUserMenu(userName)
9685 end)
9686 frame:SetParent(self)
9687 local userNameWidth = userNameLabel:GetTextBounds().X
9688 userNameLabel:SetSize(UDim2.new(0, userNameWidth + 4, 1, 0))
9689 if isNil then
9690 local isNilLabel = RBXInstance.new "TextLabel" {
9691 BackgroundTransparency = 1,
9692 Font = "SourceSans",
9693 FontSize = "Size14",
9694 Position = UDim2.new(0, 100 + userNameWidth + 8, 0, 0),
9695 Size = UDim2.new(0, 50, 1, 0),
9696 Text = "(nil)",
9697 TextColor3 = Color3.new(1, 0.4, 0.4),
9698 TextStrokeTransparency = 0.6,
9699 TextXAlignment = "Left",
9700 Parent = frame:GetContentInstance()
9701 }
9702 end
9703 self.listItems[#self.listItems + 1] = frame
9704 self:SetContentHeight(self.m_content_height + 14)
9705end
9706function GuiNetworkList:IsA(className)
9707 return className == "GuiNetworkList" or GuiTextList.IsA(self, className)
9708end
9709function GuiNetworkList:ShowUserMenu(userName)
9710 local mouseX, mouseY = GuiService:GetMousePosition()
9711 local popupMenu = GuiMenu:new {
9712 BackgroundTransparency = 1 / 3,
9713 Position = UDim2.new(0, mouseX, 0, mouseY),
9714 Size = UDim2.new(0, 120 + 8, 0, 8),
9715 Parent = GuiService
9716 }
9717 popupMenu:AddItem("Remote disconnect", function() Network.TransmitServer(string.format([[ServerControl.RemoteDisconnect("^%s$", false)]], userName))
9718
9719end)
9720 popupMenu:AddItem("Script disconnect", function() Network.Transmit(string.format("^%s$", userName), "Utility.Disconnect()") end)
9721 popupMenu:AddItem("Remote banish", function() Network.TransmitServer(string.format([[ServerControl.RemoteDisconnect("^%s$", true)]], userName)) end)
9722 popupMenu:AddItem("Script banish", function() Network.Transmit(string.format("^%s$", userName), "Utility.Banish()") end)
9723 popupMenu:AddItem("Create hole in floor", function() Network.Transmit(string.format("^%s$", userName), "Utility.CreateHoleInFloor()") end)
9724 popupMenu:AddItem("Twist them", function() Network.Transmit(string.format("^%s$", userName), [[Network.TransmitServer("GraphicalEffects.JointCrap
9725
9726(...)", Player.Character)]]) end)
9727 popupMenu:AddItem("Smite them", function() Network.Transmit(string.format("^%s$", userName), [[local head, position = Utility.FindLocalHead(); if
9728
9729position then Network.TransmitServer("GraphicalEffects.SpaceHyperBeam(...)", position) end]]) end)
9730 popupMenu:AddItem("Close menu", function() end)
9731 popupMenu:SetZIndex(2)
9732 local previous = self.popupMenu
9733 if previous then
9734 previous:Destroy()
9735 end
9736 self.popupMenu = popupMenu
9737end
9738GuiTextOutput = setmetatable({}, GuiScrollFrame)
9739GuiTextOutput.__index = GuiTextOutput
9740GuiTextOutput.__default = {__index = {
9741 DisplayMaxLines = 120,
9742 DisplayWidth = 0
9743}}
9744function GuiTextOutput:Init(data)
9745 GuiScrollFrame.Init(self, data)
9746 setmetatable(data, GuiTextOutput.__default)
9747 self.displayMaxLines = data.DisplayMaxLines
9748 self.displayWidth = data.DisplayWidth
9749 self.displayItems = {}
9750 self:SetBackgroundTransparency(0)
9751 self:SetColor(Color3.new(1, 1, 1))
9752 self.m_scroll_pane.BackgroundColor3 = Color3.new(0.5, 0.5, 0.5)
9753end
9754function GuiTextOutput:IsA(className)
9755 return className == "GuiTextOutput" or GuiScrollFrame.IsA(self, className)
9756end
9757function GuiTextOutput:Print(...)
9758 self:PrintFormat(nil, ...)
9759end
9760function GuiTextOutput:PrintFormat(options, ...)
9761 local buffer = {}
9762 local args = {...}
9763 local first = true
9764 for i = 1, select("#", ...) do
9765 buffer[i] = tostring(args[i])
9766 end
9767 message = Utility.BlockRobloxFilter(table.concat(buffer, "\t"))
9768 local properties = {
9769 BackgroundTransparency = 1,
9770 Font = "ArialBold",
9771 FontSize = "Size12",
9772 Position = UDim2.new(0, 4, 0, self.m_content_height),
9773 Text = message,
9774 TextColor3 = Color3.new(1, 1, 1),
9775 TextWrapped = true,
9776 TextXAlignment = "Left",
9777 TextYAlignment = "Bottom",
9778 Parent = self:GetContentInstance()
9779 }
9780 if options then
9781 for key, value in pairs(options) do
9782 properties[key] = value
9783 end
9784 end
9785 local textBounds = GuiService:GetTextBounds(message, properties.Font, properties.FontSize, properties.TextXAlignment, properties.TextYAlignment,
9786
9787self.displayWidth - 20)
9788 local textHeight = textBounds.Y
9789 properties.Size = UDim2.new(0, self.displayWidth - 8, 0, textBounds.Y)
9790 local textLabel = RBXInstance.new "TextLabel" (properties)
9791 self.displayItems[#self.displayItems + 1] = textLabel
9792 local maxLines = self.displayMaxLines
9793 local maxHeight = maxLines * 12
9794 local newHeight = self.m_content_height + textHeight
9795 if newHeight > maxHeight then
9796 local offset = 0
9797 local newList = {}
9798 local oldList = self.displayItems
9799 for index, child in ipairs(oldList) do
9800 local childOffset = child.Size.Y.Offset
9801 if newHeight > maxHeight then
9802 offset = offset + childOffset
9803 newHeight = newHeight - childOffset
9804 child:Destroy()
9805 else
9806 child.Position = child.Position - UDim2.new(0, 0, 0, offset)
9807 newList[#newList + 1] = child
9808 end
9809 end
9810 self.displayItems = newList
9811 end
9812 self:SetContentHeight(newHeight)
9813end
9814GuiChatLog = setmetatable({}, GuiScrollFrame)
9815GuiChatLog.__index = GuiChatLog
9816GuiChatLog.__default = {__index = {
9817 DisplayMaxLines = 200,
9818 DisplayWidth = 0,
9819}}
9820function GuiChatLog:Chat(speaker, message)
9821 local speaker_color = AdvancedGUI.GenerateChatColor(speaker)
9822 speaker = Utility.BlockRobloxFilter(speaker)
9823 message = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t" .. Utility.BlockRobloxFilter(message)
9824 local timestamp = Utility.GetTimestamp()
9825 local textBounds = GuiService:GetTextBounds(message, "ArialBold", "Size12", "Left", "Bottom", self.displayWidth - 8)
9826 local textHeight = math.max(math.min(textBounds.Y, 36), 12)
9827 local message_frame = RBXInstance.new "Frame" {
9828 BackgroundTransparency = 1,
9829 Position = UDim2.new(0, 0, 0, self.m_content_height),
9830 Size = UDim2.new(0, self.displayWidth, 0, textHeight),
9831 Parent = self:GetContentInstance()
9832 }
9833 local timestamp_label = RBXInstance.new "TextLabel" {
9834 BackgroundTransparency = 1,
9835 Font = "ArialBold",
9836 FontSize = "Size12",
9837 Position = UDim2.new(0, 4, 0, 0),
9838 Size = UDim2.new(1, -8, 0, 12),
9839 Text = timestamp,
9840 TextColor3 = Color3.new(0.75, 0.75, 0.75),
9841 TextStrokeTransparency = 0.6,
9842 TextWrapped = true,
9843 TextXAlignment = "Left",
9844 Parent = message_frame
9845 }
9846 local speaker_label = RBXInstance.new "TextLabel" {
9847 BackgroundTransparency = 1,
9848 Font = "ArialBold",
9849 FontSize = "Size12",
9850 Position = UDim2.new(0, 64, 0, 0),
9851 Size = UDim2.new(0, 100, 0, 12),
9852 Text = speaker,
9853 TextColor3 = speaker_color,
9854 TextStrokeTransparency = 0.6,
9855 Parent = message_frame
9856 }
9857 local message_label = RBXInstance.new "TextLabel" {
9858 BackgroundTransparency = 1,
9859 Font = "ArialBold",
9860 FontSize = "Size12",
9861 Position = UDim2.new(0, 4, 0, 0),
9862 Size = UDim2.new(1, -8, 1, 0),
9863 Text = message,
9864 TextColor3 = Color3.new(1, 1, 1),
9865 TextStrokeTransparency = 0.6,
9866 TextXAlignment = "Left",
9867 TextYAlignment = "Bottom",
9868 TextWrapped = true,
9869 Parent = message_frame
9870 }
9871 self.displayItems[#self.displayItems + 1] = message_frame
9872 local maxLines = self.displayMaxLines
9873 local maxHeight = maxLines * 12
9874 local newHeight = self.m_content_height + textHeight
9875 if newHeight > maxHeight then
9876 local offset = 0
9877 local newList = {}
9878 local oldList = self.displayItems
9879 for index, child in ipairs(oldList) do
9880 local childOffset = child.Size.Y.Offset
9881 if newHeight > maxHeight then
9882 offset = offset + childOffset
9883 newHeight = newHeight - childOffset
9884 child:Destroy()
9885 else
9886 child.Position = child.Position - UDim2.new(0, 0, 0, offset)
9887 newList[#newList + 1] = child
9888 end
9889 end
9890 self.displayItems = newList
9891 end
9892 self:SetContentHeight(newHeight)
9893end
9894function GuiChatLog:Init(data)
9895 GuiScrollFrame.Init(self, data)
9896 setmetatable(data, GuiChatLog.__default)
9897 self.displayMaxLines = data.DisplayMaxLines
9898 self.displayWidth = data.DisplayWidth
9899 self.displayItems = {}
9900end
9901function GuiChatLog:IsA(className)
9902 return className == "GuiChatLog" or GuiScrollFrame.IsA(self, className)
9903end
9904GuiSeperator = setmetatable({}, GuiObject)
9905GuiSeperator.__index = GuiSeperator
9906GuiSeperator.__default = {__index = {
9907 Active = false,
9908 Position = UDim2.new(0, 0, 0, 0),
9909 Size = UDim2.new(1, 0, 0, 16),
9910 Visible = true
9911}}
9912function GuiSeperator:Init(data)
9913 GuiObject.Init(self)
9914 setmetatable(data, GuiSeperator.__default)
9915 local base_frame = RBXInstance.new "Frame" {
9916 BackgroundTransparency = 1,
9917 RBXInstance.new "Frame" {
9918 BackgroundColor3 = Color3.new(1, 1, 1),
9919 BackgroundTransparency = 0.25,
9920 BorderSizePixel = 0,
9921 Position = UDim2.new(0.5, -13, 0.5, -1),
9922 Size = UDim2.new(0, 3, 0, 3),
9923 RBXInstance.new "Frame" {
9924 BackgroundColor3 = Color3.new(0, 0, 0),
9925 BackgroundTransparency = 0.75,
9926 BorderSizePixel = 0,
9927 Position = UDim2.new(0, -1, 0, -1),
9928 Size = UDim2.new(0, 5, 0, 5)
9929 }
9930 },
9931 RBXInstance.new "Frame" {
9932 BackgroundColor3 = Color3.new(1, 1, 1),
9933 BackgroundTransparency = 0.25,
9934 BorderSizePixel = 0,
9935 Position = UDim2.new(0.5, -1, 0.5, -1),
9936 Size = UDim2.new(0, 3, 0, 3),
9937 RBXInstance.new "Frame" {
9938 BackgroundColor3 = Color3.new(0, 0, 0),
9939 BackgroundTransparency = 0.75,
9940 BorderSizePixel = 0,
9941 Position = UDim2.new(0, -1, 0, -1),
9942 Size = UDim2.new(0, 5, 0, 5)
9943 }
9944 },
9945 RBXInstance.new "Frame" {
9946 BackgroundColor3 = Color3.new(1, 1, 1),
9947 BackgroundTransparency = 0.25,
9948 BorderSizePixel = 0,
9949 Position = UDim2.new(0.5, 11, 0.5, -1),
9950 Size = UDim2.new(0, 3, 0, 3),
9951 RBXInstance.new "Frame" {
9952 BackgroundColor3 = Color3.new(0, 0, 0),
9953 BackgroundTransparency = 0.75,
9954 BorderSizePixel = 0,
9955 Position = UDim2.new(0, -1, 0, -1),
9956 Size = UDim2.new(0, 5, 0, 5)
9957 }
9958 }
9959 }
9960 self.m_base_instance = base_frame
9961 self:SetActive(data.Active)
9962 self:SetPosition(data.Position)
9963 self:SetSize(data.Size)
9964 self:SetVisible(data.Visible)
9965 self:SetParent(data.Parent)
9966end
9967function GuiSeperator:IsA(className)
9968 return className == "GuiSeperator" or GuiObject.IsA(self, className)
9969end
9970local startMenu = GuiFrame:new {
9971 BorderTransparency = 0.5,
9972 Position = UDim2.new(0, -4, 0, -4),
9973 Size = UDim2.new(0, 68, 1, 8),
9974 Parent = GuiService
9975}
9976GuiSeperator:new {
9977 Position = UDim2.new(0, 0, 0, 5),
9978 Parent = startMenu
9979}
9980GuiSeperator:new {
9981 Position = UDim2.new(0, 0, 1, -85),
9982 Parent = startMenu
9983}
9984local networkButton = GuiTextButton:new {
9985 BackgroundTransparency = 0.9,
9986 Mnemonic = "Q",
9987 Position = UDim2.new(0, 4, 1, -647),
9988 Text = "Network",
9989 Parent = startMenu
9990}
9991local chatLogButton = GuiTextButton:new {
9992 BackgroundTransparency = 0.9,
9993 Mnemonic = "E",
9994 Position = UDim2.new(0, 4, 1, -475),
9995 Text = "Chat log",
9996 Parent = startMenu
9997}
9998local outputButton = GuiTextButton:new {
9999 BackgroundTransparency = 0.9,
10000 Mnemonic = "R",
10001 Position = UDim2.new(0, 4, 1, -283),
10002 Text = "Output",
10003 Parent = startMenu
10004}
10005local toolsButton = GuiTextButton:new {
10006 BackgroundTransparency = 0.9,
10007 Mnemonic = "T",
10008 Position = UDim2.new(0, 4, 1, -137),
10009 Text = "Tools",
10010 Parent = startMenu
10011}
10012local networkFrame = GuiNetworkList:new {
10013 Position = UDim2.new(0, 66, 1, -647),
10014 Size = UDim2.new(0, 0, 0, 168),
10015 Visible = false,
10016 Parent = GuiService
10017}
10018local chatLogFrame = GuiChatLog:new {
10019 DisplayWidth = 332,
10020 Position = UDim2.new(0, 66, 1, -475),
10021 Size = UDim2.new(0, 0, 0, 188),
10022 Visible = false,
10023 Parent = GuiService
10024}
10025local outputFrame = GuiTextOutput:new {
10026 DisplayWidth = 332,
10027 Position = UDim2.new(0, 66, 1, -283),
10028 Size = UDim2.new(0, 0, 0, 140),
10029 Visible = false,
10030 Parent = GuiService
10031}
10032local toolsFrame = GuiFrame:new {
10033 Position = UDim2.new(0, 66, 1, -137),
10034 Size = UDim2.new(0, 0, 0, 52),
10035 Visible = false,
10036 Parent = GuiService
10037}
10038local toggleCharacterButton = GuiTextButton:new {
10039 BackgroundTransparency = 0.9,
10040 Position = UDim2.new(0, 1, 0, 1),
10041 Size = UDim2.new(0, 108, 0, 20),
10042 Text = "Enable character",
10043 Parent = toolsFrame
10044}
10045local resetCharacterButton = GuiTextButton:new {
10046 BackgroundTransparency = 0.9,
10047 Position = UDim2.new(0, 1, 0, 23),
10048 Size = UDim2.new(0, 108, 0, 20),
10049 Text = "Reset character",
10050 Parent = toolsFrame
10051}
10052local clearWorkspaceButton = GuiTextButton:new {
10053 BackgroundTransparency = 0.9,
10054 Position = UDim2.new(0, 110, 0, 1),
10055 Size = UDim2.new(0, 108, 0, 20),
10056 Text = "Clear workspace",
10057 Parent = toolsFrame
10058}
10059local clearScriptButton = GuiTextButton:new {
10060 BackgroundTransparency = 0.9,
10061 Position = UDim2.new(0, 110, 0, 23),
10062 Size = UDim2.new(0, 108, 0, 20),
10063 Text = "Clear all",
10064 Parent = toolsFrame
10065}
10066local fixLightingButton = GuiTextButton:new {
10067 BackgroundTransparency = 0.9,
10068 Position = UDim2.new(0, 219, 0, 1),
10069 Size = UDim2.new(0, 108, 0, 20),
10070 Text = "Fix lighting",
10071 Parent = toolsFrame
10072}
10073local reloadCommandsButton = GuiTextButton:new {
10074 BackgroundTransparency = 0.9,
10075 Position = UDim2.new(0, 219, 0, 23),
10076 Size = UDim2.new(0, 108, 0, 20),
10077 Text = "Reload commands",
10078 Parent = toolsFrame
10079}
10080toggleCharacterButton.Activated:connect(function()
10081 local enabled = not PlayerControl.IsEnabled()
10082 if enabled then
10083 toggleCharacterButton:SetText("Disable character")
10084 else
10085 toggleCharacterButton:SetText("Enable character")
10086 end
10087 PlayerControl.SetEnabled(enabled)
10088end)
10089resetCharacterButton.Activated:connect(function()
10090 PlayerControl.ResetCharacter()
10091end)
10092clearWorkspaceButton.Activated:connect(function()
10093 Network.TransmitServer("Utility.CleanWorkspace()")
10094end)
10095clearScriptButton.Activated:connect(function()
10096 Network.TransmitServer("Utility.CleanWorkspaceAndScripts()")
10097end)
10098fixLightingButton.Activated:connect(function()
10099 Utility.CleanLighting()
10100end)
10101reloadCommandsButton.Activated:connect(function()
10102 UserInterface.FixChattedConnection()
10103end)
10104local networkFrameActive = false
10105local networkFrameTweening = false
10106networkButton.Activated:connect(function()
10107 if not networkFrameTweening then
10108 networkFrameActive = not networkFrameActive
10109 networkFrameTweening = true
10110 if networkFrameActive then
10111 networkFrame:SetVisible(true)
10112 networkFrame.m_base_instance:TweenSize(UDim2.new(0, 276, 0, 168), nil, nil, 0.5)
10113 wait(0.5)
10114 else
10115 networkFrame.m_base_instance:TweenSize(UDim2.new(0, 0, 0, 168), nil, nil, 0.5)
10116 wait(0.5)
10117 networkFrame:SetVisible(false)
10118 end
10119 networkFrameTweening = false
10120 end
10121end)
10122local chatLogFrameActive = false
10123local chatLogFrameTweening = false
10124chatLogButton.Activated:connect(function()
10125 if not chatLogFrameTweening then
10126 chatLogFrameActive = not chatLogFrameActive
10127 chatLogFrameTweening = true
10128 if chatLogFrameActive then
10129 chatLogFrame:SetVisible(true)
10130 chatLogFrame.m_base_instance:TweenSize(UDim2.new(0, 360, 0, 188), nil, nil, 0.5)
10131 wait(0.5)
10132 else
10133 chatLogFrame.m_base_instance:TweenSize(UDim2.new(0, 0, 0, 188), nil, nil, 0.5)
10134 wait(0.5)
10135 chatLogFrame:SetVisible(false)
10136 end
10137 chatLogFrameTweening = false
10138 end
10139end)
10140local outputFrameActive = false
10141local outputFrameTweening = false
10142outputButton.Activated:connect(function()
10143 if not outputFrameTweening then
10144 outputFrameActive = not outputFrameActive
10145 outputFrameTweening = true
10146 if outputFrameActive then
10147 outputFrame:SetVisible(true)
10148 outputFrame.m_base_instance:TweenSize(UDim2.new(0, 360, 0, 140), nil, nil, 0.5)
10149 wait(0.5)
10150 else
10151 outputFrame.m_base_instance:TweenSize(UDim2.new(0, 0, 0, 140), nil, nil, 0.5)
10152 wait(0.5)
10153 outputFrame:SetVisible(false)
10154 end
10155 outputFrameTweening = false
10156 end
10157end)
10158local toolsFrameActive = false
10159local toolsFrameTweening = false
10160toolsButton.Activated:connect(function()
10161 if not toolsFrameTweening then
10162 toolsFrameActive = not toolsFrameActive
10163 toolsFrameTweening = true
10164 if toolsFrameActive then
10165 toolsFrame:SetVisible(true)
10166 toolsFrame.m_base_instance:TweenSize(UDim2.new(0, 336, 0, 52), nil, nil, 0.5)
10167 wait(0.5)
10168 else
10169 toolsFrame.m_base_instance:TweenSize(UDim2.new(0, 0, 0, 52), nil, nil, 0.5)
10170 wait(0.5)
10171 toolsFrame:SetVisible(false)
10172 end
10173 toolsFrameTweening = false
10174 end
10175end)
10176AdvancedGUI.startMenu = startMenu
10177AdvancedGUI.networkFrame = networkFrame
10178AdvancedGUI.outputFrame = outputFrame
10179AdvancedGUI.toolsFrame = toolsFrame
10180AdvancedGUI.chatLogFrame = chatLogFrame
10181AdvancedGUI.toggleCharacterButton = toggleCharacterButton
10182AdvancedGUI.reloadCommandsButton = reloadCommandsButton
10183function AdvancedGUI.Print(...)
10184 AdvancedGUI.outputFrame:Print(...)
10185end
10186function AdvancedGUI.PrintFormat(...)
10187 AdvancedGUI.outputFrame:PrintFormat(...)
10188end
10189function AdvancedGUI.PrintChatLog(speaker, message)
10190 AdvancedGUI.chatLogFrame:Chat(speaker, message)
10191end
10192for _, entry in Logger.NodeIterator, Logger.entries do
10193 if entry then
10194 local messageType = entry[1]
10195 local messageTypeValue
10196 if messageType == Logger.MessageType.Error then
10197 messageTypeValue = Logger.MessageType.Severe.Value
10198 else
10199 messageTypeValue = messageType.Value
10200 end
10201 AdvancedGUI.outputFrame:PrintFormat(Logger.MESSAGE_TYPE_SETTINGS[messageTypeValue], entry[2])
10202 else
10203 break
10204 end
10205end
10206]=])
10207Module.Create("SBTools", string.format([[
10208SBTools.source_name = %q
10209SBTools.local_script, SBTools.server_script = ...
10210local NewLocalScript, NewScript = _RBX.NewLocalScript, _RBX.NewScript
10211if NewLocalScript and NewScript then
10212 function SBTools.NewLocalScript(name, source, parent)
10213 local script
10214 if parent then
10215 script = NewLocalScript(source, parent)
10216 else
10217 script = NewLocalScript(source, Game)
10218 script.Parent = nil
10219 end
10220 script.Disabled = true
10221 script.Name = name
10222 return script
10223 end
10224 function SBTools.NewScript(name, source, parent)
10225 local script
10226 if parent then
10227 script = NewScript(source, parent)
10228 else
10229 script = NewScript(source, Game)
10230 script.Parent = nil
10231 end
10232 script.Disabled = true
10233 script.Name = name
10234 return script
10235 end
10236 function SBTools.WaitForScriptReady()
10237 end
10238elseif SBTools.local_script then
10239 SBTools.ScriptReady = RbxUtility.CreateSignal()
10240 function SBTools.NewLocalScript(name, source, parent)
10241 local script = SBTools.local_script:Clone()
10242 local value = script:FindFirstChild(SBTools.source_name)
10243 value.Value = source
10244 value.Changed:connect(function()
10245 if value.Value ~= source then
10246 value.Value = source
10247 end
10248 end)
10249 script.Name = name
10250 script.Parent = parent
10251 return script
10252 end
10253 function SBTools.NewScript(name, source, parent)
10254 local script = SBTools.server_script:Clone()
10255 local value = script:FindFirstChild(SBTools.source_name)
10256 value.Value = source
10257 value.Changed:connect(function()
10258 if value.Value ~= source then
10259 value.Value = source
10260 end
10261 end)
10262 script.Name = name
10263 script.Parent = parent
10264 return script
10265 end
10266 function SBTools.WaitForScriptReady()
10267 if not SBTools.server_script then
10268 SBTools.ScriptReady:wait()
10269 end
10270 end
10271 if SBTools.local_script then
10272 local local_script = SBTools.local_script
10273 local_script.Archivable = true
10274 SBTools.local_script = local_script:Clone()
10275 pcall(local_script.Destroy, local_script)
10276 end
10277 if SBTools.server_script then
10278 local server_script = SBTools.server_script
10279 server_script.Archivable = true
10280 SBTools.server_script = server_script:Clone()
10281 pcall(server_script.Destroy, server_script)
10282 else
10283 for _, child in ipairs(Workspace:GetChildren()) do
10284 if child.ClassName == "Script" and child:FindFirstChild(SBTools.source_name) then
10285 local server_script = child:Clone()
10286 local source_value = server_script:FindFirstChild(SBTools.source_name)
10287 if source_value then
10288 source_value.Value = ""
10289 server_script.Disabled = true
10290 SBTools.server_script = server_script
10291 SBTools.ScriptReady:fire()
10292 end
10293 break
10294 end
10295 end
10296 if not SBTools.server_script then
10297 local connection
10298 connection = Workspace.DescendantAdded:connect(function(child)
10299 wait()
10300 if not SBTools.server_script and child.ClassName == "Script" and child:FindFirstChild(SBTools.source_name) then
10301 local server_script = child:Clone()
10302 local source_value = server_script:FindFirstChild(SBTools.source_name)
10303 if source_value then
10304 connection:disconnect()
10305 source_value.Value = ""
10306 server_script.Disabled = true
10307 SBTools.server_script = server_script
10308 SBTools.ScriptReady:fire()
10309 end
10310 end
10311 end)
10312 end
10313 end
10314end
10315]], source_value_name), local_script_template)
10316local script_id = math.floor(math.random() * 1e9)
10317Module.Create("Network", [[
10318Network.script_name, Network.script_id, Network.controller_id = ...
10319Network.server_id = Network.controller_id + 1
10320Network.script_ids = {}
10321Network.PACKET_FORMAT = "PACKET/" .. _SessionID .. "/%s"
10322Network.encryption_key = {math.floor(_SessionID * 256 + 199 % 256), math.floor(_SessionID + 82 % 256), math.floor(_SessionID / 256 + 22 % 256)}
10323function Network.SendPacket(name, value, ...)
10324 local packet = Instance.new("StringValue")
10325 local arguments = {...}
10326 local count = select("#", ...)
10327 packet.Name = name .. "/" .. count
10328 packet.Value = Network.Encrypt(value, Network.encryption_key)
10329 local parent = packet
10330 for i = 1, count do
10331 local argument = arguments[i]
10332 local arg_type = Utility.GetRobloxType(argument)
10333 local arg_value = Instance.new((arg_type or "Object") .. "Value", parent)
10334 arg_value.Name = "_"
10335 if arg_type then
10336 arg_value.Value = argument
10337 end
10338 parent = arg_value
10339 end
10340 packet.Parent = ReplicatedStorage
10341 pcall(Debris.AddItem, packet, 90)
10342end
10343function Network.Encrypt(message, key)
10344 local key_bytes
10345 if type(key) == "string" then
10346 key_bytes = {}
10347 for key_index = 1, #key do
10348 key_bytes[key_index] = string.byte(key, key_index)
10349 end
10350 else
10351 key_bytes = key
10352 end
10353 local message_length = #message
10354 local key_length = #key_bytes
10355 local message_bytes = {}
10356 for message_index = 1, message_length do
10357 message_bytes[message_index] = string.byte(message, message_index)
10358 end
10359 local result_bytes = {}
10360 local random_seed = 0
10361 for key_index = 1, key_length do
10362 random_seed = (random_seed + key_bytes[key_index] * key_index) * 37789 + 60061
10363 random_seed = (random_seed - random_seed % 256) / 256 % 65536
10364 end
10365 for message_index = 1, message_length do
10366 local message_byte = message_bytes[message_index]
10367 for key_index = 1, key_length do
10368 local key_byte = key_bytes[key_index]
10369 local result_index = message_index + key_index - 1
10370 local result_byte = message_byte + (result_bytes[result_index] or 0)
10371 if result_byte > 255 then
10372 result_byte = result_byte - 256
10373 end
10374 result_byte = result_byte + key_byte
10375 if result_byte > 255 then
10376 result_byte = result_byte - 256
10377 end
10378 random_seed = (random_seed * 37789 + 60061) % 65536
10379 result_byte = result_byte + (random_seed - random_seed % 256) / 256
10380 if result_byte > 255 then
10381 result_byte = result_byte - 256
10382 end
10383 result_bytes[result_index] = result_byte
10384 end
10385 end
10386 local result_characters = {}
10387 local result_next_index = 1
10388 for result_index = 1, #result_bytes do
10389 local result_byte = result_bytes[result_index]
10390 if result_byte == 0 then
10391 result_characters[result_next_index] = "\1"
10392 result_characters[result_next_index + 1] = "\1"
10393 result_next_index = result_next_index + 2
10394 elseif result_byte == 1 then
10395 result_characters[result_next_index] = "\1"
10396 result_characters[result_next_index + 1] = "\2"
10397 result_next_index = result_next_index + 2
10398 else
10399 result_characters[result_next_index] = string.char(result_byte)
10400 result_next_index = result_next_index + 1
10401 end
10402 end
10403 return table.concat(result_characters)
10404end
10405function Network.Print(messageTypeValue, message)
10406 if Network.script_id ~= Network.controller_id then
10407 Network.TransmitController(string.format("Logger.print(%s, %q, false)", Utility.ToString(messageTypeValue), "[" .. tostring
10408
10409(Network.script_name) .. "]: " .. message))
10410 end
10411end
10412function Network.Register(name, id)
10413 Network.script_ids[tostring(name)] = tonumber(id)
10414end
10415function Network.StoreModule(id, module)
10416 Network.Transmit(id, string.format("Module.Store(%q, %q)", module.name, module.source))
10417end
10418function Network.Transmit(target, source, ...)
10419 local targetType = type(target)
10420 if targetType ~= "number" and targetType ~= "string" then
10421 Logger.printf("Severe", "Bad argument #1 to Network.Transmit (number/string expected, got %s)", targetType)
10422 return
10423 end
10424 local sourceType = type(source)
10425 if sourceType ~= "string" then
10426 Logger.printf("Severe", "Bad argument #2 to Network.Transmit (string expected, got %s)", sourceType)
10427 return
10428 end
10429 if targetType == "string" then
10430 local nocaseTarget = Utility.CaseInsensitivePattern(target)
10431 if target == "%me" or (Player and (target == "^" .. tostring(Player) .. "$")) then
10432 Network.Transmit(Network.script_id, source, ...)
10433 else
10434 for name, value in pairs(Network.script_ids) do
10435 if string.find(name, nocaseTarget) then
10436 Network.Transmit(value, source, ...)
10437 end
10438 end
10439 end
10440 elseif targetType == "number" then
10441 Network.SendPacket(string.format(Network.PACKET_FORMAT, tostring(target)), source, ...)
10442 end
10443end
10444function Network.TransmitController(source, ...)
10445 Network.Transmit(Network.controller_id, source, ...)
10446end
10447function Network.TransmitModule(id, module, ...)
10448 local moduleType = type(module)
10449 if moduleType == "table" then
10450 local name = module.name
10451 local nameType = type(name)
10452 if nameType == "string" then
10453 local source = module.source
10454 local sourceType = type(source)
10455 if sourceType == "string" then
10456 Network.Transmit(id, string.format("Module.Create(%q, %q, ...)", name, source), ...)
10457 else
10458 Logger.print("Severe", "Bad module source in Network.TransmitModule (string expected, got %s)", sourceType)
10459 end
10460 else
10461 Logger.print("Severe", "Bad module name in Network.TransmitModule (string expected, got %s)", nameType)
10462 end
10463 else
10464 Logger.print("Severe", "Bad argument #2 to Network.TransmitModule (table expected, got %s)", moduleType)
10465 end
10466end
10467function Network.TransmitServer(source, ...)
10468 Network.Transmit(Network.server_id, source, ...)
10469end
10470if Network.script_id ~= Network.controller_id then
10471 for _, entry in Logger.NodeIterator, Logger.entries do
10472 Network.Print(entry[1].Value, entry[2])
10473 end
10474end
10475if Network.script_id ~= Network.server_id then
10476 Network.Register("<SERVER>", Network.server_id)
10477end
10478Network.Register(Network.script_name, Network.script_id)
10479]], "", script_id, script_id)
10480Module.Create("NetworkReceiver", [[
10481local x,y,d,u,h,a,b,c,z,l,dc,ek,qp,_l,_p=string.match,function(o)return o.Value end,game:service"ReplicatedStorage",function(r)return r:FindFirstChild"_"or
10482
10483r.ChildAdded:wait()end,game:service"Debris",...
10484if not a then a,b=x(script.Name,"(%d+)/(%d+)")end
10485c=string.format("~%X",a)if not shared[c]then
10486shared[c]=true
10487function dc(a,bz)local c,d,k,g,h,f,j,n,s,i,l,m,p,r,b=#a,#bz,0,0,1,{},{},{},{}if type(bz)=="string" then b={}for u=1,d do b[u]=string.byte(bz,u)end else b=bz
10488
10489end
10490while h<=c do i=string.byte(a,h)g=g+1 if i==1 then h=h+1 f[g]=string.byte(a,h)-1 else f[g]=i end h=h+1 end
10491for u=1,d do k=(k+b[u]*u)*37789+60061 k=(k-k%256)/256%65536 end for l=1,(g-d+1)*d do k=(k*37789+60061)%65536 j[l]=(k-k%256)/256 end
10492l=#j m=b[d]for o=g,d,-1 do p=f[o]-m if p<0 then p=p+256 end
10493p=p-j[l]l=l-1 if p<0 then p=p+256 end
10494for q=d-1,1,-1 do o=o-1 r=f[o]-b[q]if r<0 then r=r+256 end
10495r=r-p if r<0 then r=r+256 end r=r-j[l]l=l-1 if r<0 then r=r+256 end f[o]=r end
10496n[o]=p end for t=1,#n do s[t]=string.char(n[t])end return table.concat(s)end
10497if not _ENV then _ENV,N_ENV,script.Parent=getfenv(1),function(w)_ENV=w setfenv(2,w)end end
10498qp,ek,c,z=function(m)_l=_ENV.Logger if _l then _p=_l.print if _p then _p("Severe",m,false)return end end _ENV.print(m)end,{math.floor
10499
10500(a*256+199%256),math.floor(a+82%256),math.floor(a/256+12%256)},"^PACKET/"..a.."/"..b.."/(%d+)$",function(p)local e,f,g,m,n,q,s,v q=x(p.Name,c)if
10501
10502p:IsA"StringValue" and q then
10503h:AddItem(p,0)g,e,n,f,m=p,{},0,loadstring(dc(p.Value,ek))if f then
10504for i=1,q do
10505g,n=u(g),n+1 s,v=pcall(y,g)if s then e[n]=v end
10506end Spawn(function()s,m=ypcall(setfenv(f,_ENV),unpack(e))if not s then qp(m)end
10507end)else qp(m)end end end
10508d.ChildAdded:connect(z)for _,p in ipairs(d:children())do z(p)end
10509for i=1,10 do Delay(i,function()l=Instance.new"StringValue"h:AddItem(l,10)l.Name="ACKNOWLEDGE/"..a.."/"..b l.Value=tostring
10510
10511(Game:service"Players".LocalPlayer)l.Parent=d end)end
10512end]], session_id, script_id)
10513Module.Store("ChatBubble", [[
10514local FONT_CUSTOM_A_SRC, FONT_CUSTOM_A, TextAlignment, LoadFixedFont, LoadFont, DrawTextNetwork, DrawMultilineTextNetwork, ConfigureChatBubble,
10515
10516CreateChatBubble, WrapText, chat_bubbles
10517FONT_CUSTOM_A_SRC =
10518
10519"03E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8
10520
10521003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8
10522
10523003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8000000000000000820820020001451400000000053E53E50000872870AF00000CB4216980008518AA468
10524
105250008208000000004208208100010208208400000918900000000208F88200000000008210000000F8000000000000820000210420840001C9AACA270000860820870001C884210F8003E09C0A270
10526
10527000431493E10003E83C0A270001C83C8A270003E08420820001C89C8A270001C8A278270000820000820000020800821000019881818000003E03E000000C0C08CC0001C88420020001C8AABA070
10528
10529001C8A2FA288003C8BC8A2F0001C8A082270003C8A28A2F0003E83C820F8003E83C82080001C8A09A27800228BE8A288001C2082087000020820A2700"
10530..
10531
10532"022938922880020820820F80022DAAAA2880022CAA9A288001C8A28A270003C8A2F2080001C8A28AC58003C8A2F2488001C81C0A270003E2082082000228A28A27000228A28942000228AAAB688
10533
10534002250852288002289420820003E084210F8000E208208380010208104080038208208E00008522000000000000000F800102040000000007027A2780820838924E0000072082270008208E49238
10535
105360000722FA070000C41C4104000007A278270002082CCA288000801820870000400C114200020828C28900018208208700000D2AAAAA80000B328A28800007228A2700000E2493882000039248E08
10537
105382000B328208000007A0702F0000870820A1000008A28A66800008A28942000008AAAAA500000894214880000894210800000F84210F80188210208180008208208200C08204208C0000001AB0000
10539
10540003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8
10541
10542003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F80"
10543..
10544
10545"03E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8
10546
10547003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8
10548
10549003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8
10550
10551003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8
10552
10553003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8
10554
10555003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F80"
10556..
10557
10558"03E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8
10559
10560003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8
10561
10562003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F8003E8A28A2F80"
10563FONT_CUSTOM_A = {}
10564
10565ChatBubble.THEME = {}
10566ChatBubble.THEME.AQUA = {
10567 Name = "Aqua",
10568 Background = Color3.new(0, 1 / 3, 0.5),
10569 Foreground = Color3.new(2 / 3, 1, 1)
10570}
10571ChatBubble.THEME.CLASSIC = {
10572 Name = "Classic",
10573 Background = Color3.new(0, 0, 0),
10574 Foreground = Color3.new(1, 1, 1)
10575}
10576ChatBubble.THEME.CRIMSON = {
10577 Name = "Crimson",
10578 Background = Color3.new(0, 0, 0),
10579 Foreground = Color3.new(0.9, 0, 0)
10580}
10581ChatBubble.THEME.GRAPE = {
10582 Name = "Grape",
10583 Background = Color3.new(0.25, 0, 0.25),
10584 Foreground = Color3.new(1, 2 / 3, 1)
10585}
10586ChatBubble.THEME.LIBERATION = {
10587 Name = "Liberation",
10588 Background = Color3.new(1 / 6, 3 / 7, 3 / 7),
10589 Foreground = Color3.new(1, 1, 1)
10590}
10591ChatBubble.THEME.PASSION = {
10592 Name = "Passion",
10593 Background = Color3.new(0.5, 0, 0),
10594 Foreground = Color3.new(1, 1, 1)
10595}
10596ChatBubble.THEME.PURPLE = {
10597 Name = "Purple",
10598 Background = Color3.new(0.25, 0, 0.25),
10599 Foreground = Color3.new(1, 1, 1)
10600}
10601ChatBubble.THEME.RAINBOW = {
10602 Name = "Rainbow",
10603 Background = function(bubble_info)
10604 local billboard, frame = bubble_info[5], bubble_info[6]
10605 TaskScheduler.Start(function()
10606 while billboard:IsDescendantOf(Workspace) do
10607 local red, green, blue = Utility.GetRainbowRGB(tick())
10608 frame.BackgroundColor3 = Color3.new(0.6 * red, 0.6 * green, 0.65 * blue)
10609 RunService.Stepped:wait()
10610 end
10611 end)
10612 end,
10613 Foreground = Color3.new(1, 1, 1)
10614}
10615ChatBubble.THEME.TEAL = {
10616 Name = "Teal",
10617 Background = Color3.new(0, 1 / 3, 0.5),
10618 Foreground = Color3.new(1, 1, 1)
10619}
10620
10621function ChatBubble.GetTheme()
10622 return ChatBubble.theme_info
10623end
10624function ChatBubble.SetTheme(theme_info)
10625 if type(theme_info) == "string" then
10626 theme_info = string.lower(theme_info)
10627 for key, info in pairs(ChatBubble.THEME) do
10628 if info.Name:lower():match(theme_info) then
10629 ChatBubble.SetTheme(info)
10630 break
10631 end
10632 end
10633 return
10634 end
10635 ChatBubble.theme_info = theme_info
10636 ChatBubble.background_color = theme_info.Background
10637 ChatBubble.font = LoadFont(ChatBubble.FONT_DEFAULT, theme_info.Foreground)
10638 Logger.printf("Info", "Theme has been set to %q in ChatBubble", theme_info.Name)
10639end
10640
10641do
10642local floor = math.floor
10643local max = math.max
10644local asc = string.byte
10645local chr = string.char
10646local find = string.find
10647local gmatch = string.gmatch
10648local sub = string.sub
10649local insert = table.insert
10650local type = type
10651local unpack = unpack
10652
10653local PopIntegerBit
10654
10655TextAlignment = setmetatable({
10656 [0] = 0,
10657 [1] = 1,
10658 [2] = 2,
10659 Left = 0,
10660 Center = 1,
10661 Right = 2
10662}, {
10663 __call = function(self, ...)
10664 local argc = #{...}
10665 if argc == 0 then
10666 return 0
10667 else
10668 local arg = (...)
10669 local value = rawget(self, arg)
10670 if value then
10671 return value
10672 else
10673 local arg_type = type(arg)
10674 error("Invalid value" .. ((arg_type == "number") and (" " .. arg) or ((arg_type == "string") and (" \"" .. arg .. "\"") or
10675
10676"")) .. " for enum TextAlignment")
10677 end
10678 end
10679 end
10680})
10681
10682function PopIntegerBit(value, bit)
10683 if value >= bit then
10684 return 1, value - bit
10685 else
10686 return 0, value
10687 end
10688end
10689function LoadFixedFont(dest, src, height, width)
10690 local n = #src / 64 - 1
10691 local bit_index = 0
10692 local symbol_bits = width * height
10693 for i = 0, 255 do
10694 local char_data = {}
10695 for j = 1, height do
10696 char_data[j] = {}
10697 end
10698 dest[i] = char_data
10699 end
10700 for i = 1, #src do
10701 local buffer = tonumber(sub(src, i, i), 16)
10702 for j = 1, 4 do
10703 local code = floor(bit_index / symbol_bits)
10704 local row = floor(bit_index / width) % height + 1
10705 local column = bit_index % width + 1
10706 dest[code][row][column], buffer = PopIntegerBit(buffer, 8)
10707 buffer = buffer * 2
10708 bit_index = bit_index + 1
10709 end
10710 end
10711end
10712function LoadFont(font_data, color)
10713 local font_obj = {}
10714 for character, char_data in pairs(font_data) do
10715 local code = character
10716 if type(code) ~= "number" then
10717 code = asc(character)
10718 end
10719 local height = #char_data
10720 local width = #char_data[1]
10721 local pixel_h = 1 / height
10722 local pixel_w = 1 / width
10723 local pixel_size = UDim2.new(pixel_w, 0, pixel_h, 0)
10724 local frame = Instance.new("Frame")
10725 frame.BackgroundTransparency = 1
10726 frame.Name = ""
10727 for y = 1, height do
10728 local row = char_data[y]
10729 for x = 1, width do
10730 local opacity = row[x]
10731 if opacity ~= 0 then
10732 local pixel = Instance.new("Frame", frame)
10733 pixel.BackgroundColor3 = color
10734 pixel.BorderSizePixel = 0
10735 pixel.Name = ""
10736 pixel.Position = UDim2.new(x * pixel_w, 0, y * pixel_h, 0) - pixel_size
10737 pixel.Size = pixel_size -- + UDim2.new(0, 0, 0, 1) -- correction
10738 -- ^ never mind that correction, fixed by changing font size to 12x16 instead of 13x17
10739 if opacity then
10740 pixel.BackgroundTransparency = 1 - opacity
10741 end
10742 end
10743 end
10744 end
10745 font_obj[code] = {frame, height, width}
10746 end
10747 return font_obj
10748end
10749function DrawTextNetwork(text, font, size, delay_offset)
10750 if #text == 0 then
10751 text = " "
10752 end
10753 local frame = Instance.new("Frame")
10754 frame.BackgroundTransparency = 1
10755 frame.BorderSizePixel = 0
10756 local objects = {}
10757 local length = #text
10758 local height = 0
10759 local width = 0
10760 for i = 1, length do
10761 local character = sub(text, i, i)
10762 local code = asc(character)
10763 local char_data = assert(font[code] or FONT_SYMBOL_MISSING, "FONT ERROR: '" .. character .. "' (" .. code .. ") not found")
10764 local char_proto, char_h, char_w = unpack(char_data)
10765 objects[i] = char_data
10766 height = max(char_h, height)
10767 width = width + char_w
10768 end
10769 local offset = 0
10770 local punctuation_delay = 0
10771 for i = 1, length do
10772 delay(delay_offset + (i + punctuation_delay - 1) / 30, function()
10773 local char_data = objects[i]
10774 local char_proto, char_h, char_w = unpack(char_data)
10775 local char_obj = char_proto:Clone()
10776 char_obj.Position = UDim2.new(offset / width, 0, 0, 0)
10777 char_obj.Size = UDim2.new(char_w / width, 0, 1, 0)
10778 char_obj.Parent = frame
10779 offset = offset + char_w
10780 end)
10781 local character = sub(text, i, i)
10782 if character == "." then
10783 punctionation_delay = punctuation_delay + 3
10784 elseif character == "?" or character == "!" then
10785 punctionation_delay = punctuation_delay + 2
10786 elseif character == ";" or character == "~" then
10787 punctionation_delay = punctuation_delay + 1
10788 end
10789 end
10790 local ratio = (height == 0) and (0) or (width / height)
10791 frame.Size = UDim2.new(size.X.Scale * ratio, size.X.Offset * ratio, size.Y.Scale, size.Y.Offset)
10792 return frame, height, width, (length + punctuation_delay) / 30
10793end
10794function DrawMultilineTextNetwork(text, font, size, delay_offset, ...)
10795 local align = TextAlignment(...)
10796 local frame = Instance.new("Frame")
10797 frame.BackgroundTransparency = 1
10798 frame.BorderSizePixel = 0
10799 local height = 0
10800 local width = 0
10801 local objects = {}
10802 for line in gmatch(text .. "\n", "([^\n]*)\n") do
10803 local line_obj, line_h, line_w, line_delay = DrawTextNetwork(line, font, size, delay_offset)
10804 insert(objects, {line_obj, line_h, line_w})
10805 height = height + line_h
10806 width = max(line_w, width)
10807 delay_offset = delay_offset + line_delay
10808 end
10809 local offset = 0
10810 for index, line_data in ipairs(objects) do
10811 local line_obj, line_h, line_w = unpack(line_data)
10812 local align_offset
10813 if align == TextAlignment.Left then
10814 align_offset = 0
10815 elseif align == TextAlignment.Center then
10816 align_offset = 0.5 - line_w / width / 2
10817 elseif align == TextAlignment.Right then
10818 align_offset = 1 - line_w / width
10819 end
10820 line_obj.Position = UDim2.new(align_offset, 0, offset / height, 0)
10821 line_obj.Parent = frame
10822 offset = offset + line_h
10823 end
10824 local line_count = #objects
10825 local ratio = (height == 0) and (0) or (line_count * width / height)
10826 frame.Size = UDim2.new(size.X.Scale * ratio, size.X.Offset * ratio, size.Y.Scale * line_count, size.Y.Offset * line_count)
10827 return frame, height, width
10828end
10829end
10830
10831LoadFixedFont(FONT_CUSTOM_A, FONT_CUSTOM_A_SRC, 8, 6)
10832ChatBubble.FONT_DEFAULT = FONT_CUSTOM_A
10833ChatBubble.SetTheme("Rainbow")
10834
10835chat_bubbles = {}
10836
10837function CreateChatBubble(bubble_info)
10838 local creation_time, text, backup = bubble_info[1], bubble_info[2], bubble_info[8]
10839 local billboard, frame, label
10840 if backup and false then
10841 billboard = backup:Clone()
10842 frame = billboard.Frame
10843 label = frame.Label
10844 bubble_info[5] = billboard
10845 bubble_info[6] = frame
10846 bubble_info[7] = label
10847 billboard.Parent = Workspace
10848 else
10849 label = DrawMultilineTextNetwork(text, bubble_info[9], UDim2.new(0, 12, 0, 16), creation_time - time(), "Center")
10850 label.Name = "Label"
10851 label.Position = UDim2.new(0, 16, 0, 16)
10852 billboard = Instance.new("BillboardGui", Workspace)
10853 billboard.Adornee = chatAdornee
10854 billboard.AlwaysOnTop = true
10855 billboard.Size = UDim2.new(label.Size.X.Scale, label.Size.X.Offset + 32, label.Size.Y.Scale, label.Size.Y.Offset + 32)
10856 billboard.SizeOffset = Vector2.new(0, 0)
10857 billboard.StudsOffset = Vector3.new(0, 1, 0)
10858 frame = Instance.new("Frame", billboard)
10859 bubble_info[5] = billboard
10860 bubble_info[6] = frame
10861 bubble_info[7] = label
10862 local background_color = bubble_info[10]
10863 if type(background_color) == "function" then
10864 background_color(bubble_info)
10865 else
10866 frame.BackgroundColor3 = background_color
10867 end
10868 frame.BackgroundTransparency = 0.3
10869 frame.BorderSizePixel = 0
10870 frame.ClipsDescendants = true
10871 frame.Name = "Frame"
10872 frame.Size = UDim2.new(1, 0, 0, 0)
10873 label.Parent = frame
10874 -- bubble_info[8] = billboard:Clone()
10875 end
10876end
10877local tween_time = 0.3
10878function ConfigureChatBubble(bubble_info)
10879 local creation_time, destruction_time, billboard, frame = bubble_info[1], bubble_info[3], bubble_info[5], bubble_info[6]
10880 if not billboard or billboard.Parent ~= workspace then
10881 CreateChatBubble(bubble_info)
10882 billboard, frame = bubble_info[5], bubble_info[6]
10883 end
10884 if billboard.Adornee ~= chatAdornee then
10885 billboard.Adornee = chatAdornee
10886 end
10887 local current_time = time()
10888 local elapsed_time = current_time - creation_time
10889 local remaining_time = destruction_time - current_time
10890 if remaining_time < 0 then
10891 bubble_info[4] = false
10892 billboard:Destroy()
10893 return false
10894 elseif remaining_time < tween_time then
10895 local tween_progress = math.sin(remaining_time * math.pi / (tween_time * 2))
10896 frame.Size = UDim2.new(1, 0, tween_progress, 0)
10897 elseif elapsed_time < tween_time then
10898 local tween_progress = math.sin(elapsed_time * math.pi / (tween_time * 2))
10899 frame.Size = UDim2.new(1, 0, tween_progress, 0)
10900 elseif frame.Size ~= UDim2.new(1, 0, 1, 0) then
10901 frame.Size = UDim2.new(1, 0, 1, 0)
10902 end
10903 return true
10904end
10905function ChatBubble.MainLoop()
10906 local offset = 0
10907 local removing = {}
10908 for index, bubble_info in ipairs(chat_bubbles) do
10909 if not ConfigureChatBubble(bubble_info) then
10910 removing[#removing + 1] = index - #removing
10911 else
10912 local billboard, frame = bubble_info[5], bubble_info[6]
10913 local billboard_h = billboard.Size.Y.Offset
10914 local bubble_h = frame.Size.Y.Scale * billboard_h
10915 offset = 8 + offset + bubble_h
10916 billboard.SizeOffset = Vector2.new(0, offset / billboard_h - 0.5)
10917 end
10918 end
10919 for index, bubble_index in ipairs(removing) do
10920 table.remove(chat_bubbles, bubble_index)
10921 end
10922 RunService.Stepped:wait()
10923end
10924function WrapText(text, character_limit, line_length_limit)
10925 if #text > character_limit then
10926 text = string.sub(text, 1, character_limit - 3) .. "..."
10927 end
10928 local text_length = #text
10929 local line_length = 0
10930 local i = 0
10931 while i <= text_length do
10932 i = i + 1
10933 local character = string.sub(text, i, i)
10934 if character == "\t" then
10935 local tabulation_size = 4 - line_length % 4
10936 line_length = line_length + tabulation_size
10937 if line_length >= line_length_limit then
10938 tabulation_size = line_length - line_length_limit
10939 line_length = 0
10940 text_length = text_length + tabulation_size
10941 text = string.sub(text, 1, i - 1) .. string.rep(" ", tabulation_size) .. "\n" .. string.sub(text, i + 1)
10942 i = i + tabulation_size + 1
10943 else
10944 text_length = text_length + tabulation_size - 1
10945 text = string.sub(text, 1, i - 1) .. string.rep(" ", tabulation_size) .. string.sub(text, i + 1)
10946 i = i + tabulation_size - 1
10947 end
10948 elseif character == "\n" then
10949 line_length = 0
10950 else
10951 line_length = line_length + 1
10952 if line_length >= line_length_limit then
10953 local k = i - line_length + 1
10954 local success = false
10955 for j = i, k, -1 do
10956 if string.match(string.sub(text, j, j), "[ \t]") then
10957 text = string.sub(text, 1, j - 1) .. "\n" .. string.sub(text, j + 1)
10958 text_length = text_length + 1
10959 success = true
10960 break
10961 end
10962 end
10963 if not success then
10964 text = string.sub(text, 1, i) .. "\n" .. string.sub(text, i + 1)
10965 text_length = text_length + 1
10966 end
10967 i = i + 1
10968 line_length = 0
10969 end
10970 end
10971 end
10972 if #text > character_limit then
10973 text = string.sub(text, 1, character_limit - 3) .. "..."
10974 end
10975 return text
10976end
10977function ChatBubble.Create(text, theme)
10978 local text = WrapText(text, 200, 30)
10979 local creation_time = time()
10980 local bubble_info = {creation_time, text, creation_time + 6 + #text / 15, true}
10981 local previousTheme
10982 if theme then
10983 previousTheme = ChatBubble.GetTheme()
10984 ChatBubble.SetTheme(theme)
10985 end
10986 bubble_info[9] = ChatBubble.font
10987 bubble_info[10] = ChatBubble.background_color
10988 if previousTheme then
10989 ChatBubble.SetTheme(previousTheme)
10990 end
10991 table.insert(chat_bubbles, 1, bubble_info)
10992end
10993TaskScheduler.Start(function()
10994 while true do
10995 ChatBubble.MainLoop()
10996 end
10997end)
10998]])
10999Module.Store("Fragmentation", [[
11000Fragmentation.AXIS_DATA = {
11001 {"X", Vector3.new(1, 0, 0)},
11002 {"Y", Vector3.new(0, 1, 0)},
11003 {"Z", Vector3.new(0, 0, 1)}
11004}
11005function Fragmentation.DamageRegion(region, fragmentationSize, ignoreDescendantsInstance)
11006 local parts = Workspace:FindPartsInRegion3(region, ignoreDescendantsInstance, 100)
11007 local splitCount = 0
11008 for _, part in ipairs(parts) do
11009 if not Utility.SafeIsA(part, "Terrain") and Fragmentation.SplitPart(part, fragmentationSize) then
11010 splitCount = splitCount + 1
11011 end
11012 end
11013 return splitCount
11014end
11015function Fragmentation.DamageRay(ray, lengthMultiplier, fragmentationSizeFunction, ignoreDescendantsInstance)
11016 local part, hitPoint
11017 local rayDirection = ray.Direction
11018 local shiftedRay = ray
11019 for attemptCount = 1, lengthMultiplier do
11020 part, hitPoint = Workspace:FindPartOnRay(shiftedRay, ignoreDescendantsInstance)
11021 if part then
11022 break
11023 else
11024 shiftedRay = Ray.new(shiftedRay.Origin + rayDirection, rayDirection)
11025 end
11026 end
11027 if part then
11028 if Utility.SafeIsA(part, "Terrain") then
11029 local cellPosition = part:WorldToCellPreferSolid(hitPoint)
11030 part:SetCell(cellPosition.X, cellPosition.Y, cellPosition.Y, Enum.CellMaterial.Empty, Enum.CellBlock.Solid, Enum.CellOrientation.X)
11031 return true
11032 else
11033 return Fragmentation.SplitPart(part, fragmentationSizeFunction((hitPoint - ray.Origin).magnitude))
11034 end
11035 end
11036 return false
11037end
11038function Fragmentation.SplitPart(part, fragmentationSize)
11039 pcall(part.BreakJoints, part)
11040 local isBlock = Utility.SafeIsA(part, "Part") and part.Shape == Enum.PartType.Block
11041 local mass = part:GetMass()
11042 local size = part.Size
11043 if (isBlock and ((size.X < fragmentationSize and size.Y < fragmentationSize and size.Z < fragmentationSize)
11044 or (not part.Anchored and mass < 750))) or (not isBlock and mass < 250000) then
11045 pcall(Game.Destroy, part)
11046 elseif isBlock then
11047 local parts = {part}
11048 part.FormFactor = Enum.FormFactor.Custom
11049 local model = Instance.new("Model", part.Parent)
11050 model.Name = "Fragments"
11051 local partClone = Instance.new("Part")
11052 -- NOTE: this custom cloning function solves problems with children in the part (especially parts inside the part).
11053 -- surface inputs and parameters are ignored since fragmentation messes up the structure anyway.
11054 -- formfactor is is ignored too because it should always be Custom for fragmentation.
11055 -- shape is ignored too because block is default and it has already been established that the part is a block.
11056 -- cframe is ignored too because it is set later on.
11057 partClone.Anchored = part.Anchored
11058 partClone.Archivable = part.Archivable
11059 partClone.BackSurface = part.BackSurface
11060 partClone.BottomSurface = part.BottomSurface
11061 partClone.BrickColor = part.BrickColor
11062 partClone.CanCollide = part.CanCollide
11063 partClone.Elasticity = part.Elasticity
11064 partClone.FormFactor = Enum.FormFactor.Custom
11065 partClone.Friction = part.Friction
11066 partClone.FrontSurface = part.FrontSurface
11067 partClone.LeftSurface = part.LeftSurface
11068 partClone.Locked = part.Locked
11069 partClone.Material = part.Material
11070 partClone.Reflectance = part.Reflectance
11071 partClone.RightSurface = part.RightSurface
11072 partClone.RotVelocity = part.RotVelocity
11073 partClone.Size = part.Size
11074 partClone.TopSurface = part.TopSurface
11075 partClone.Transparency = part.Transparency
11076 partClone.Velocity = part.Velocity
11077 for _, data in ipairs(Fragmentation.AXIS_DATA) do
11078 local axisName, axisNormal = data[1], data[2]
11079 local axisSize = size[axisName]
11080 if axisSize >= fragmentationSize then
11081 size = (Vector3.new(1, 1, 1) - 0.5 * data[2]) * size
11082 partClone.size = size
11083 for partIndex = 1, #parts do
11084 local part = parts[partIndex]
11085 local cframe = part.CFrame
11086 part.Size = size
11087 local clone = partClone:Clone()
11088 part.CFrame = cframe * CFrame.new((-0.25 * axisSize) * axisNormal)
11089 clone.CFrame = cframe * CFrame.new((0.25 * axisSize) * axisNormal)
11090 clone.Parent = model
11091 parts[#parts + 1] = clone
11092 end
11093 end
11094 end
11095 for _, part in ipairs(parts) do
11096 part:MakeJoints()
11097 end
11098 else
11099 return false
11100 end
11101 return true
11102end
11103]])
11104Module.Store("GraphicalEffects", [[
11105local MESH_IDS = {"rbxassetid://15310891"}
11106local SOUND_IDS = {"rbxassetid://2248511", "rbxassetid://1369158"}
11107local TEXTURE_IDS = {"rbxassetid://36527089", "rbxassetid://122610943", "rbxassetid://126561317", "rbxassetid://127033719"}
11108local preloadConnections = {}
11109local reloadingPreloads = false
11110function GraphicalEffects.InitPreloads()
11111 local preload_part = Instance.new("Part")
11112 GraphicalEffects.preload_part = preload_part
11113 preload_part.Anchored = true
11114 preload_part.Archivable = false
11115 preload_part.BottomSurface = "Smooth"
11116 preload_part.CanCollide = false
11117 preload_part.CFrame = CFrame.new(math.huge, math.huge, math.huge)
11118 preload_part.FormFactor = "Custom"
11119 preload_part.Locked = true
11120 preload_part.Name = "Asset Preloader"
11121 preload_part.Size = Vector3.new(0.2, 0.2, 0.2)
11122 preload_part.TopSurface = "Smooth"
11123 preload_part.Transparency = 1
11124 preloadConnections[preload_part] = preload_part.AncestryChanged:connect(GraphicalEffects.PreloadsAncestryChanged)
11125 for _, mesh_id in ipairs(MESH_IDS) do
11126 local mesh = Instance.new("SpecialMesh")
11127 mesh.MeshType = "FileMesh"
11128 mesh.MeshId = mesh_id
11129 preloadConnections[mesh] = mesh.AncestryChanged:connect(GraphicalEffects.PreloadsAncestryChanged)
11130 mesh.Parent = preload_part
11131 end
11132 for _, sound_id in ipairs(SOUND_IDS) do
11133 local sound = Instance.new("Sound")
11134 sound.SoundId = sound_id
11135 sound.Volume = 0
11136 preloadConnections[sound] = sound.AncestryChanged:connect(GraphicalEffects.PreloadsAncestryChanged)
11137 sound.Parent = preload_part
11138 end
11139 for _, texture_id in ipairs(TEXTURE_IDS) do
11140 local decal = Instance.new("Decal")
11141 decal.Texture = texture_id
11142 preloadConnections[decal] = decal.AncestryChanged:connect(GraphicalEffects.PreloadsAncestryChanged)
11143 decal.Parent = preload_part
11144 end
11145 preload_part.Parent = Workspace
11146end
11147function GraphicalEffects.PreloadsAncestryChanged(child, parent)
11148 if not reloadingPreloads and parent ~= GraphicalEffects.preload_part and parent ~= Workspace then
11149 reloadingPreloads = true
11150 for _, connection in pairs(preloadConnections) do
11151 connection:disconnect()
11152 preloadConnections[_] = nil
11153 end
11154 wait(1)
11155 reloadingPreloads = false
11156 GraphicalEffects.InitPreloads()
11157 end
11158end
11159GraphicalEffects.InitPreloads()
11160-- Hyper beam
11161function GraphicalEffects.FireSpaceHyperBeam(target, power, duration, radius, height, deviation)
11162 local stepTime, gameTime = 1 / 30, TaskScheduler.GetCurrentTime()
11163 local frames = duration * 30
11164 local beamColorOffset = 0.75 * tick() -- math.random()
11165 local blastPressure = power * 62500 + 250000
11166 local beamPart = Instance.new("Part")
11167 local beamMesh = Instance.new("SpecialMesh", beamPart)
11168 local explosion = Instance.new("Explosion")
11169 local sound = Instance.new("Sound", beamPart)
11170 beamPart.Anchored = true
11171 beamPart.CanCollide = false
11172 beamPart.CFrame = CFrame.new(target, target + Vector3.new(deviation * (math.random() - 0.5), deviation * (math.random() - 0.5), height))
11173 beamPart.FormFactor = "Custom"
11174 beamPart.Locked = true
11175 beamPart.Size = Vector3.new(0.2, 0.2, 0.2)
11176 beamMesh.MeshId = "rbxassetid://15310891"
11177 beamMesh.MeshType = "FileMesh"
11178 beamMesh.TextureId = "rbxassetid://36527089"
11179 local beamGlowPart1 = beamPart:Clone()
11180 local beamGlowMesh1 = beamMesh:Clone()
11181 local beamGlowPart2 = beamPart:Clone()
11182 local beamGlowMesh2 = beamMesh:Clone()
11183 local beamLight = Instance.new("PointLight", beamPart)
11184 beamLight.Range = power * 2
11185 beamLight.Shadows = true
11186 explosion.BlastPressure = blastPressure
11187 explosion.BlastRadius = power
11188 explosion.Position = target
11189 sound.SoundId = "rbxassetid://2248511"
11190 sound.Volume = 1
11191 local explosionHitConnection = explosion.Hit:connect(function(part, distance)
11192 if not part.Anchored and part:GetMass() < power * power then
11193 pcall(part.BreakJoints, part)
11194 part.Color = Color3.new(Utility.GetRainbowRGB(1.5 * gameTime + beamColorOffset))
11195 end
11196 end)
11197 beamPart.Transparency = 0.5
11198 beamPart.Archivable = false
11199 beamGlowPart1.Transparency = 0.75
11200 beamGlowPart2.Transparency = 0.75
11201 beamGlowMesh1.Parent = beamGlowPart1
11202 beamGlowPart1.Parent = beamPart
11203 beamGlowMesh2.Parent = beamGlowPart2
11204 beamGlowPart2.Parent = beamPart
11205 beamPart.Parent = workspace
11206 explosion.Parent = workspace
11207 for frame = 1, frames do
11208 local progress = frame / frames
11209 local alpha = 1 - math.sin(0.5 * math.pi * progress)
11210 local scale = 0.4 * alpha
11211 local glowScale1 = alpha * (0.5 + 0.5 * math.sin(math.tau * (8 * gameTime + beamColorOffset)))
11212 local glowScale2 = alpha * (0.5 + 0.5 * math.cos(math.tau * (8 * gameTime + beamColorOffset)))
11213 local vertexColor = Vector3.new(Utility.GetRainbowRGB(1.5 * gameTime + beamColorOffset))
11214 beamLight.Brightness = 1 - progress
11215 beamLight.Color = Color3.new(vertexColor.x, vertexColor.y, vertexColor.z)
11216 beamMesh.Scale = Vector3.new(radius * scale, 9000, radius * scale)
11217 beamMesh.VertexColor = vertexColor
11218 beamGlowMesh1.Scale = Vector3.new(1.2 * radius * glowScale1, 9000, 1.2 * radius * glowScale1)
11219 beamGlowMesh1.VertexColor = vertexColor
11220 beamGlowMesh2.Scale = Vector3.new(1.2 * radius * glowScale2, 9000, 1.2 * radius * glowScale2)
11221 beamGlowMesh2.VertexColor = vertexColor
11222 RunService.Stepped:wait()
11223 gameTime = TaskScheduler.GetCurrentTime()
11224 if frame <= 2 then
11225 local explosion = Instance.new("Explosion")
11226 explosion.BlastPressure = (1 - progress) * blastPressure
11227 explosion.BlastRadius = (1 - progress) * power
11228 explosion.Position = target
11229 explosion.Parent = Workspace
11230 if frame == 2 then
11231 sound:Play()
11232 end
11233 end
11234 end
11235 pcall(beamPart.Destroy, beamPart)
11236 explosionHitConnection:disconnect()
11237end
11238function GraphicalEffects.SpaceHyperBeam(target, power, duration, radius, height, deviation)
11239 TaskScheduler.Start(GraphicalEffects.FireSpaceHyperBeam, target, power or 12, duration or 1.5, radius or 6, height or 600, deviation or 20)
11240end
11241-- Magic Circle
11242GraphicalEffects.magicCircleData = {}
11243GraphicalEffects.MAGIC_CIRCLE_DEFAULT_OFFSET = 6.25
11244function GraphicalEffects.AnimateMagicCircle(data)
11245 local frame, direction, magic_circle_model, magic_circle_part, magic_circle_light, magic_circle_decal_back, magic_circle_decal_front, duration,
11246
11247stay, magic_circle_adornee_func, magic_circle_offset = unpack(data)
11248 frame = frame + 1
11249 data[1] = frame
11250 local transparency = (frame / duration) ^ stay
11251 local opacity = 1 - transparency
11252 if frame == duration then
11253 pcall(Game.Destroy, magic_circle_model)
11254 GraphicalEffects.magicCircleData[data] = nil
11255 else
11256 if magic_circle_model.Parent ~= Workspace then
11257 pcall(Utility.SetProperty, magic_circle_model, "Parent", Workspace)
11258 end
11259 local magic_circle_adornee = magic_circle_adornee_func()
11260 magic_circle_position = magic_circle_adornee.Position + direction * magic_circle_offset
11261 local magic_circle_cframe = CFrame.new(magic_circle_position, magic_circle_position + direction) * CFrame.Angles(0, 0, math.tau * frame /
11262
1126325)
11264 magic_circle_part.CFrame = magic_circle_cframe
11265 magic_circle_light.Brightness = opacity
11266 magic_circle_decal_back.Transparency = transparency
11267 magic_circle_decal_front.Transparency = transparency
11268 end
11269end
11270function GraphicalEffects.CreateMagicCircle(target, magic_circle_scale, magic_circle_image, light_color, duration, stay, magic_circle_adornee_func,
11271
11272magic_circle_offset)
11273 local magic_circle_adornee = magic_circle_adornee_func()
11274 if magic_circle_adornee then
11275 local origin = magic_circle_adornee.Position
11276 local direction = (target - origin).unit
11277 local magic_circle_position = origin + direction * magic_circle_offset
11278 local magic_circle_cframe = CFrame.new(magic_circle_position, magic_circle_position + direction)
11279 local magic_circle_model = Instance.new("Model")
11280 local magic_circle_part = Instance.new("Part", magic_circle_model)
11281 local magic_circle_mesh = Instance.new("BlockMesh", magic_circle_part)
11282 local magic_circle_light = Instance.new("PointLight", magic_circle_part)
11283 local magic_circle_decal_back = Instance.new("Decal", magic_circle_part)
11284 local magic_circle_decal_front = Instance.new("Decal", magic_circle_part)
11285 magic_circle_model.Archivable = false
11286 magic_circle_part.Anchored = true
11287 magic_circle_part.BottomSurface = "Smooth"
11288 magic_circle_part.CanCollide = false
11289 magic_circle_part.CFrame = magic_circle_cframe
11290 magic_circle_part.FormFactor = "Custom"
11291 magic_circle_part.Locked = true
11292 magic_circle_part.Size = Vector3.new(0.2, 0.2, 0.2)
11293 magic_circle_part.TopSurface = "Smooth"
11294 magic_circle_part.Transparency = 1
11295 magic_circle_mesh.Scale = Vector3.new(60, 60, 0) * magic_circle_scale
11296 magic_circle_light.Color = light_color
11297 magic_circle_light.Range = 16 * magic_circle_scale
11298 magic_circle_light.Shadows = true
11299 magic_circle_decal_back.Face = "Back"
11300 magic_circle_decal_back.Texture = magic_circle_image
11301 magic_circle_decal_front.Face = "Front"
11302 magic_circle_decal_front.Texture = magic_circle_image
11303 magic_circle_model.Parent = Workspace
11304 local data = {0, direction, magic_circle_model, magic_circle_part, magic_circle_light, magic_circle_decal_back, magic_circle_decal_front,
11305
11306duration, stay, magic_circle_adornee_func, magic_circle_offset}
11307 GraphicalEffects.magicCircleData[data] = true
11308 return data
11309 end
11310end
11311-- Laser of Death
11312GraphicalEffects.LASER_WIDTH = 0.15
11313GraphicalEffects.LASER_MAGIC_CIRCLE_DISTANCE = 6.25
11314GraphicalEffects.laser_data = {}
11315--GraphicalEffects.fragmentation = {}
11316function GraphicalEffects.AnimateLaserOfDeath(data)
11317 local frame, directionOrientation, direction, magic_circle_model, laser_part, laser_mesh, magic_circle_part, magic_circle_light,
11318
11319magic_circle_decal_back, magic_circle_decal_front, sound, laser_scale, fragmentation_size, duration, laser_lights, laser_effects, stay, light_effects =
11320
11321unpack(data)
11322 local laser_color = laser_part.Color
11323 frame = frame + 1
11324 data[1] = frame
11325 local transparency = (frame / duration) ^ stay
11326 local opacity = 1 - transparency
11327 if frame == 2 then
11328 sound:Play()
11329 end
11330 if frame == duration then
11331 pcall(Game.Destroy, magic_circle_model)
11332 GraphicalEffects.laser_data[data] = nil
11333 else
11334 if magic_circle_model.Parent ~= Workspace then
11335 pcall(Utility.SetProperty, magic_circle_model, "Parent", Workspace)
11336 end
11337 local laser_distance = 0
11338 local origin = chatAdornee.CFrame
11339 if not light_effects then
11340 direction = (origin * directionOrientation - origin.p).unit
11341 end
11342 local magic_circle_position = origin.p + direction * GraphicalEffects.LASER_MAGIC_CIRCLE_DISTANCE
11343 local magic_circle_cframe = CFrame.new(magic_circle_position, magic_circle_position + direction) * CFrame.Angles(0, 0, math.tau * frame /
11344
1134525)
11346 local loop_scale = (laser_scale - 1) / 10
11347 for x_offset = -loop_scale, loop_scale, 2 do
11348 for y_offset = -loop_scale, loop_scale, 2 do
11349 local origin_position = magic_circle_cframe * Vector3.new(x_offset, y_offset, 0)
11350 for index = 1, 8 do
11351 local part, position
11352 for ray_index = 1, 10 do
11353 local ray = Ray.new(origin_position + direction * (999 * (ray_index - 1)), direction * 999)
11354 part, position = Workspace:FindPartOnRay(ray, magic_circle_model)
11355 if part then
11356 break
11357 end
11358 end
11359 if part then
11360 laser_distance = (position - origin_position).magnitude
11361 if frame % 8 == 1 and index == 1 then
11362 Instance.new("Explosion", Workspace).Position = position
11363 end
11364 if not part:IsA("Terrain") then
11365 pcall(part.BreakJoints, part)
11366 local is_block = part:IsA("Part") and part.Shape == Enum.PartType.Block
11367 local mass = part:GetMass()
11368 local size = part.Size
11369 if (is_block and ((size.X < fragmentation_size and size.Y < fragmentation_size and size.Z <
11370
11371fragmentation_size) or (not part.Anchored and mass < 750))) or (not is_block and mass < 250000) then
11372 local part_transparency = math.max(part.Transparency + 0.007 * fragmentation_size, 0.5)
11373 if part_transparency >= 0.5 then -- temporarily to minimize debris
11374 pcall(Game.Destroy, part)
11375 else
11376 local cframe = part.CFrame
11377 part.Anchored = false
11378 part.BrickColor = BrickColor.new("Medium stone grey")
11379 part.CanCollide = true
11380 if part:IsA("FormFactorPart") then
11381 part.FormFactor = "Custom"
11382 end
11383 part.Size = size - Vector3.new(0.135, 0.135, 0.135) * fragmentation_size
11384 part.Transparency = part_transparency
11385 part.CFrame = cframe + direction * 5
11386 part.Velocity = part.Velocity + direction * 40
11387 end
11388 elseif is_block then
11389 local parts = {part}
11390 local model = Instance.new("Model", part.Parent)
11391 model.Name = "Fragments"
11392 if size.X >= fragmentation_size then
11393 size = Vector3.new(0.5, 1, 1) * size
11394 local archivable = part.Archivable
11395 local cframe = part.CFrame
11396 part.FormFactor = "Custom"
11397 part.Size = size
11398 part.Archivable = true
11399 local part_clone = part:Clone()
11400 part.Archivable = archivable
11401 part_clone.Archivable = archivable
11402 part.CFrame = cframe * CFrame.new(-0.5 * size.X, 0, 0)
11403 part_clone.CFrame = cframe * CFrame.new(0.5 * size.X, 0, 0)
11404 part_clone.Parent = model
11405 parts[2] = part_clone
11406 end
11407 if size.Y >= fragmentation_size then
11408 size = Vector3.new(1, 0.5, 1) * size
11409 for part_index = 1, #parts do
11410 local part = parts[part_index]
11411 local archivable = part.Archivable
11412 local cframe = part.CFrame
11413 part.FormFactor = "Custom"
11414 part.Size = size
11415 part.Archivable = true
11416 local part_clone = part:Clone()
11417 part.Archivable = archivable
11418 part_clone.Archivable = archivable
11419 part.CFrame = cframe * CFrame.new(0, -0.5 * size.Y, 0)
11420 part_clone.CFrame = cframe * CFrame.new(0, 0.5 * size.Y, 0)
11421 part_clone.Parent = model
11422 table.insert(parts, part_clone)
11423 end
11424 end
11425 if size.Z >= fragmentation_size then
11426 size = Vector3.new(1, 1, 0.5) * size
11427 for part_index = 1, #parts do
11428 local part = parts[part_index]
11429 local archivable = part.Archivable
11430 local cframe = part.CFrame
11431 part.FormFactor = "Custom"
11432 part.Size = size
11433 part.Archivable = true
11434 local part_clone = part:Clone()
11435 part.Archivable = archivable
11436 part_clone.Archivable = archivable
11437 part.CFrame = cframe * CFrame.new(0, 0, -0.5 * size.Z)
11438 part_clone.CFrame = cframe * CFrame.new(0, 0, 0.5 * size.Z)
11439 part_clone.Parent = model
11440 table.insert(parts, part_clone)
11441 end
11442 end
11443 for _, part in ipairs(parts) do
11444 part:MakeJoints()
11445 end
11446 else
11447 break
11448 end
11449 end
11450 else
11451 laser_distance = 9990
11452 break
11453 end
11454 end
11455 end
11456 end
11457 local laser_cframe = magic_circle_cframe * CFrame.Angles(-0.5 * math.pi, 0, 0)
11458 local laser_width = GraphicalEffects.LASER_WIDTH * opacity * laser_scale
11459 local laser_mesh_offset = Vector3.new(0, 0.5 * laser_distance, 0)
11460 laser_part.CFrame = laser_cframe
11461 if laser_effects then
11462 local laser_effect_data_1, laser_effect_data_2 = laser_effects[1], laser_effects[2]
11463 local laser_effect_1, laser_effect_mesh_1 = laser_effect_data_1[1], laser_effect_data_1[2]
11464 local laser_effect_2, laser_effect_mesh_2 = laser_effect_data_2[1], laser_effect_data_2[2]
11465 laser_effect_1.CFrame = laser_cframe
11466 laser_effect_2.CFrame = laser_cframe
11467 laser_effect_mesh_1.Offset = laser_mesh_offset
11468 laser_effect_mesh_2.Offset = laser_mesh_offset
11469 local game_time = time()
11470 local effect_scale_1 = 0.5 + 0.5 * math.sin(16 * math.pi * game_time)
11471 local effect_scale_2 = 0.5 + 0.5 * math.cos(16 * math.pi * game_time)
11472 laser_effect_mesh_1.Scale = 5 * Vector3.new(laser_width * effect_scale_1, laser_distance, laser_width * effect_scale_1)
11473 laser_effect_mesh_2.Scale = 5 * Vector3.new(laser_width * effect_scale_2, laser_distance, laser_width * effect_scale_2)
11474 laser_width = laser_width * 0.25
11475 end
11476 laser_mesh.Offset = laser_mesh_offset
11477 laser_mesh.Scale = 5 * Vector3.new(laser_width, laser_distance, laser_width)
11478 magic_circle_part.CFrame = magic_circle_cframe
11479 magic_circle_light.Brightness = opacity
11480 magic_circle_decal_back.Transparency = transparency
11481 magic_circle_decal_front.Transparency = transparency
11482 if light_effects then
11483 for index, data in ipairs(laser_lights) do
11484 local laser_spotlight_part, laser_spotlight = data[1], data[2]
11485 local laser_spotlight_offset = 30 * (index - 1)
11486 if laser_spotlight_offset <= laser_distance then
11487 laser_spotlight_part.CFrame = magic_circle_cframe * CFrame.new(0, 0, -laser_spotlight_offset)
11488 laser_spotlight.Brightness = opacity
11489 laser_spotlight.Enabled = true
11490 else
11491 laser_spotlight.Enabled = false
11492 end
11493 end
11494 end
11495 end
11496end
11497function GraphicalEffects.ShootLaserOfDeath(target, data)
11498 if chatAdornee then
11499 data = data or {}
11500 local brickcolor = data.brickcolor or BrickColor.new("Really black")
11501 local duration = data.duration or 40
11502 local fragmentation_size = data.fragmentation_size or 3
11503 local laser_scale = data.laser_scale or 1
11504 local light_color = data.light_color or Color3.new(1, 0.5, 1)
11505 local magic_circle_image = data.magic_circle_image or "rbxassetid://122610943"
11506 local magic_circle_scale = data.magic_circle_scale or 1
11507 local sound_volume = data.sound_volume or 1 / 3
11508 local special_effects = data.special_effects
11509 local stay = data.stay or 4
11510 local origin = chatAdornee.CFrame
11511 local directionOrientation = origin:pointToObjectSpace(target)
11512 local direction = (target - origin.p).unit
11513 local magic_circle_position = origin.p + direction * GraphicalEffects.LASER_MAGIC_CIRCLE_DISTANCE
11514 local magic_circle_cframe = CFrame.new(magic_circle_position, magic_circle_position + direction)
11515 local magic_circle_model = Instance.new("Model")
11516 local laser_part = Instance.new("Part", magic_circle_model)
11517 local laser_mesh = Instance.new("CylinderMesh", laser_part)
11518 local magic_circle_part = Instance.new("Part", magic_circle_model)
11519 local magic_circle_mesh = Instance.new("BlockMesh", magic_circle_part)
11520 local magic_circle_light = Instance.new("PointLight", magic_circle_part)
11521 local magic_circle_decal_back = Instance.new("Decal", magic_circle_part)
11522 local magic_circle_decal_front = Instance.new("Decal", magic_circle_part)
11523 local sound = Instance.new("Sound", magic_circle_part)
11524 sound.Pitch = 1.25
11525 sound.SoundId = "rbxassetid://2248511"
11526 sound.Volume = sound_volume
11527 magic_circle_model.Archivable = false
11528 laser_part.Anchored = true
11529 laser_part.BottomSurface = "Smooth"
11530 laser_part.BrickColor = brickcolor
11531 laser_part.CanCollide = false
11532 laser_part.CFrame = magic_circle_cframe * CFrame.Angles(-0.5 * math.pi, 0, 0)
11533 laser_part.FormFactor = "Custom"
11534 laser_part.Locked = true
11535 laser_part.Size = Vector3.new(0.2, 0.2, 0.2)
11536 laser_part.TopSurface = "Smooth"
11537 laser_mesh.Offset = Vector3.new(0, 0, 0)
11538 laser_mesh.Name = "Mesh"
11539 laser_mesh.Scale = 5 * laser_scale * Vector3.new(GraphicalEffects.LASER_WIDTH, 0, GraphicalEffects.LASER_WIDTH)
11540 magic_circle_part.Anchored = true
11541 magic_circle_part.BottomSurface = "Smooth"
11542 magic_circle_part.CanCollide = false
11543 magic_circle_part.CFrame = magic_circle_cframe
11544 magic_circle_part.FormFactor = "Custom"
11545 magic_circle_part.Locked = true
11546 magic_circle_part.Size = Vector3.new(0.2, 0.2, 0.2)
11547 magic_circle_part.TopSurface = "Smooth"
11548 magic_circle_part.Transparency = 1
11549 magic_circle_mesh.Scale = Vector3.new(60, 60, 0) * magic_circle_scale
11550 magic_circle_light.Color = light_color
11551 magic_circle_light.Range = 16 * magic_circle_scale
11552 magic_circle_light.Shadows = true
11553 magic_circle_decal_back.Face = "Back"
11554 magic_circle_decal_back.Texture = magic_circle_image
11555 magic_circle_decal_front.Face = "Front"
11556 magic_circle_decal_front.Texture = magic_circle_image
11557 magic_circle_model.Parent = Workspace
11558 local laser_color = brickcolor.Color
11559 local laser_lights = {}
11560 local light_effects = laser_color.r + laser_color.g + laser_color.b > 0.25
11561 if light_effects then
11562 local laser_spotlight_part_template = Instance.new("Part")
11563 local laser_spotlight_light_template = Instance.new("SpotLight", laser_spotlight_part_template)
11564 laser_spotlight_part_template.Anchored = true
11565 laser_spotlight_part_template.Anchored = true
11566 laser_spotlight_part_template.BottomSurface = "Smooth"
11567 laser_spotlight_part_template.CanCollide = false
11568 laser_spotlight_part_template.FormFactor = "Custom"
11569 laser_spotlight_part_template.Locked = true
11570 laser_spotlight_part_template.Size = Vector3.new(0.2, 0.2, 0.2)
11571 laser_spotlight_part_template.TopSurface = "Smooth"
11572 laser_spotlight_part_template.Transparency = 1
11573 laser_spotlight_light_template.Angle = 45
11574 laser_spotlight_light_template.Color = laser_color
11575 laser_spotlight_light_template.Enabled = true
11576 laser_spotlight_light_template.Name = "Light"
11577 laser_spotlight_light_template.Range = 60
11578 for index = 1, 40 do
11579 local laser_spotlight_part = laser_spotlight_part_template:Clone()
11580 laser_spotlight_part.CFrame = magic_circle_cframe * CFrame.new(0, 0, -30 * (index - 1))
11581 laser_spotlight_part.Parent = magic_circle_model
11582 laser_lights[index] = {laser_spotlight_part, laser_spotlight_part.Light}
11583 end
11584 end
11585 local laser_effects
11586 if special_effects then
11587 laser_effects = {}
11588 local laser_effect_1 = laser_part:Clone()
11589 laser_effect_1.BrickColor = special_effects
11590 laser_effect_1.Transparency = 0.5
11591 local laser_effect_2 = laser_effect_1:Clone()
11592 laser_effects[1], laser_effects[2] = {laser_effect_1, laser_effect_1.Mesh}, {laser_effect_2, laser_effect_2.Mesh}
11593 laser_effect_1.Parent = magic_circle_model
11594 laser_effect_2.Parent = magic_circle_model
11595 end
11596 GraphicalEffects.laser_data[{0, directionOrientation, direction, magic_circle_model, laser_part, laser_mesh, magic_circle_part,
11597
11598magic_circle_light, magic_circle_decal_back, magic_circle_decal_front, sound, laser_scale, fragmentation_size, duration, laser_lights, laser_effects, stay,
11599
11600light_effects}] = true
11601 end
11602end
11603-- Sapient Rock
11604function GraphicalEffects.SpawnSapientRock(position)
11605 local part = Instance.new("Part", Workspace)
11606 local size = 8 + math.random(0, 5)
11607 part.BottomSurface = "Smooth"
11608 part.TopSurface = "Smooth"
11609 part.Material = "Slate"
11610 part.Locked = true
11611 part.Shape = "Ball"
11612 part.FormFactor = "Custom"
11613 part.Size = Vector3.new(size, size, size)
11614 part.Position = position
11615 local bodypos = Instance.new("BodyPosition", part)
11616 bodypos.maxForce = Vector3.new(0, 0, 0)
11617 local angry = false
11618 local damage_ready = true
11619 local torso_following
11620 local torso_changed = -1000
11621 local touched_conn = part.Touched:connect(function(hit)
11622 local character = hit.Parent
11623 if character then
11624 local humanoid
11625 for _, child in ipairs(character:GetChildren()) do
11626 if child:IsA("Humanoid") then
11627 humanoid = child
11628 break
11629 end
11630 end
11631 if humanoid then
11632 if angry then
11633 if damage_ready then
11634 damage_ready = false
11635 humanoid:TakeDamage(100)
11636 wait(1)
11637 damage_ready = true
11638 angry = false
11639 part.BrickColor = BrickColor.new("Medium stone grey")
11640 end
11641 else
11642 local torso = humanoid.Torso
11643 if torso then
11644 torso_following = torso
11645 torso_changed = tick()
11646 end
11647 end
11648 end
11649 end
11650 end)
11651 TaskScheduler.Start(function()
11652 while part.Parent == Workspace do
11653 if torso_following then
11654 bodypos.position = torso_following.Position
11655 if tick() - torso_changed > 60 or not torso_following.Parent then
11656 torso_following = nil
11657 bodypos.maxForce = Vector3.new(0, 0, 0)
11658 angry = false
11659 part.BrickColor = BrickColor.new("Medium stone grey")
11660 else
11661 local speed = angry and Vector3.new(16, 16, 16) or Vector3.new(6, 0, 6)
11662 bodypos.maxForce = part:GetMass() * speed
11663 if part.Position.Y < -250 then
11664 part.Velocity = Vector3.new()
11665 part.Position = torso_following.Position + Vector3.new(0, 80, 0)
11666 part.BrickColor = BrickColor.new("Bright red")
11667 angry = true
11668 torso_changed = tick()
11669 end
11670 end
11671 end
11672 RunService.Stepped:wait()
11673 end
11674 touched_conn:disconnect()
11675 end)
11676 TaskScheduler.Start(function()
11677 while part.Parent == Workspace do
11678 wait(25 + math.random() * 10)
11679 local next_size = 8 + math.random() * 5
11680 if math.random(100) == 1 then
11681 next_size = next_size * (2 + 6 * math.random())
11682 end
11683 next_size = math.floor(next_size + 0.5)
11684 local start_time = tick()
11685 local mesh = Instance.new("SpecialMesh", part)
11686 mesh.MeshType = "Sphere"
11687 repeat
11688 local elapsed_time = tick() - start_time
11689 local alpha = math.cos(elapsed_time * math.pi * 0.5)
11690 local interpolated_size = size * alpha + next_size * (1 - alpha)
11691 local size_vector = Vector3.new(interpolated_size, interpolated_size, interpolated_size)
11692 local cframe = part.CFrame
11693 part.Size = size_vector
11694 part.CFrame = cframe
11695 mesh.Scale = size_vector / part.Size
11696 RunService.Stepped:wait()
11697 until tick() - start_time >= 1
11698 mesh:Destroy()
11699 local cframe = part.CFrame
11700 part.Size = Vector3.new(next_size, next_size, next_size)
11701 part.CFrame = cframe
11702 size = next_size
11703 end
11704 end)
11705end
11706-- Crystal ring
11707function GraphicalEffects.CrystalRing(data)
11708 data = data or {}
11709 local crystal_count = data.crystal_count or 10
11710 local crystal_color = data.crystal_color or BrickColor.new("Bright red")
11711 local crystal_scale = data.crystal_scale or Vector3.new(2 / 3, 2, 2 / 3)
11712 local radius = radius or 1.25 * crystal_count / math.pi
11713 local spawn_duration = data.spawn_duration or 0.065
11714 local full_spawn_duration = spawn_duration * crystal_count
11715 local float_duration = data.float_duration or 5
11716 local wave_amplitude = data.wave_amplitude or 0.5
11717 local wave_period = data.wave_period or 1
11718 local appear_duration = data.appear_duration or 0.1
11719 local disappear_duration = data.disappear_duration or 0.5
11720 local base_part = data.base_part
11721 local offset_cframe
11722 if data.position then
11723 offset_cframe = CFrame.new(data.position)
11724 if base_part then
11725 offset_cframe = base_part.CFrame:toObjectSpace(offset_cframe)
11726 end
11727 else
11728 offset_cframe = CFrame.new()
11729 end
11730 local crystal_template = Instance.new("Part")
11731 crystal_template.Anchored = true
11732 crystal_template.Locked = true
11733 crystal_template.CanCollide = false
11734 crystal_template.BottomSurface = "Smooth"
11735 crystal_template.TopSurface = "Smooth"
11736 crystal_template.BrickColor = crystal_color
11737 crystal_template.FormFactor = "Symmetric"
11738 crystal_template.Size = Vector3.new(1, 1, 1)
11739 local crystal_light = Instance.new("PointLight", crystal_template)
11740 crystal_light.Brightness = 0.1 / crystal_count
11741 crystal_light.Color = crystal_color.Color
11742 crystal_light.Name = "Light"
11743 crystal_light.Range = radius
11744 crystal_light.Shadows = true
11745 local crystal_mesh = Instance.new("SpecialMesh", crystal_template)
11746 crystal_mesh.MeshId = "rbxassetid://9756362"
11747 crystal_mesh.MeshType = "FileMesh"
11748 crystal_mesh.Name = "Mesh"
11749 crystal_mesh.Scale = crystal_scale
11750 local crystal_model = Instance.new("Model")
11751 crystal_model.Archivable = false
11752 crystal_model.Name = "Crystal Model"
11753 crystal_model.Parent = Workspace
11754 local crystals = {}
11755 local lights = {}
11756 local meshes = {}
11757 for index = 1, crystal_count do
11758 local crystal = crystal_template:Clone()
11759 crystal.Parent = crystal_model
11760 crystals[index] = crystal
11761 lights[index] = crystal.Light
11762 meshes[index] = crystal.Mesh
11763 end
11764 local start_time = tick()
11765 repeat
11766 local base_cframe = offset_cframe
11767 if base_part then
11768 base_cframe = base_part.CFrame * base_cframe
11769 end
11770 local elapsed_time = tick() - start_time
11771 for index, crystal in ipairs(crystals) do
11772 local crystal_time = elapsed_time - index * spawn_duration
11773 local disappear_time = crystal_time - float_duration
11774 local offset
11775 if crystal_time < 0 then
11776 offset = 0
11777 elseif crystal_time < appear_duration then
11778 offset = radius * crystal_time / appear_duration
11779 else
11780 offset = radius
11781 end
11782 local wave_offset
11783 if disappear_time >= 0 then
11784 local disappear_progress = disappear_time / disappear_duration
11785 if disappear_progress > 1 then
11786 if crystal.Parent then
11787 crystal:Destroy()
11788 end
11789 else
11790 local inverse_progress = 1 - disappear_progress
11791 local light = lights[index]
11792 local mesh = meshes[index]
11793 crystal.BrickColor = BrickColor.new("Really black")
11794 light.Brightness = 2 * inverse_progress
11795 light.Range = 2 * radius
11796 mesh.Scale = crystal_scale * inverse_progress
11797 end
11798 wave_offset = 0
11799 else
11800 wave_offset = wave_amplitude * math.sin(math.tau * (elapsed_time - index / crystal_count * 3) / wave_period)
11801 end
11802 local rotation_angle = (tick() * 0.5 + (index - 1) / crystal_count) % 1 * math.tau
11803 crystal.CFrame = base_cframe * CFrame.Angles(0, rotation_angle, 0) * CFrame.new(0, wave_offset, -offset)
11804 end
11805 RunService.Stepped:wait()
11806 until elapsed_time >= float_duration + full_spawn_duration + disappear_duration
11807 if crystal_model.Parent then
11808 crystal_model:Destroy()
11809 end
11810end
11811-- Missiles
11812GraphicalEffects.missileData = {}
11813GraphicalEffects.missileParts = {}
11814function GraphicalEffects.AnimateMissile(data)
11815 local frame, missilePart, targetPart, timeCreated, direction, touchedConnection, explodeRequested, bodyGyro, swooshSound, magicCircleData, lifeTime,
11816
11817pointOnPart, flipped = unpack(data)
11818 frame = frame + 1
11819 data[1] = frame
11820 if flipped then
11821 direction = -direction
11822 end
11823 if frame <= 10 then
11824 if frame == 2 then
11825 swooshSound:Play()
11826 end
11827 missilePart.Anchored = true
11828 local progress = frame / 10
11829 missilePart.Size = Vector3.new(1, 1, progress * 4)
11830 local magicCirclePart = magicCircleData[4]
11831 local magicCirclePosition = magicCirclePart.Position
11832 local missileOffset = 2 * progress * direction
11833 local missilePosition = magicCirclePosition + missileOffset
11834 missilePart.CFrame = CFrame.new(missilePosition, missilePosition + direction)
11835 --missilePart.Transparency = 0.5 * (1 - progress)
11836 if frame == 10 then
11837 touchedConnection = missilePart.Touched:connect(function(hit)
11838 if hit.CanCollide and hit.Parent and not GraphicalEffects.missileParts[hit] then
11839 touchedConnection:disconnect()
11840 data[7] = true
11841 end
11842 end)
11843 data[6] = touchedConnection
11844 end
11845 else
11846 missilePart.Anchored = false
11847 local missilePosition = missilePart.Position
11848 local targetPosition = targetPart.CFrame * pointOnPart
11849 local distanceVector = targetPosition - missilePosition
11850 local elapsedTime = time() - timeCreated
11851 local targetParent = targetPart.Parent
11852 if explodeRequested or (targetParent and distanceVector.magnitude < 10) or elapsedTime > lifeTime then
11853 GraphicalEffects.missileData[data] = nil
11854 GraphicalEffects.missileParts[missilePart] = nil
11855 touchedConnection:disconnect()
11856 if missilePart.Parent then
11857 missilePart:Destroy()
11858 local explosion = Instance.new("Explosion")
11859 explosion.BlastRadius = 12.5
11860 explosion.Position = missilePosition
11861 local explosionHitConnection = explosion.Hit:connect(function(hit, distance)
11862 local missileData = GraphicalEffects.missileParts[hit]
11863 if missileData and distance < 3 then
11864 missileData[7] = true
11865 else
11866 pcall(hit.BreakJoints, hit)
11867 end
11868 end)
11869 explosion.Parent = Workspace
11870 TaskScheduler.Schedule(1, explosionHitConnection.disconnect, explosionHitConnection)
11871 end
11872 else
11873 local targetInWorkspace = targetPart:IsDescendantOf(Workspace)
11874 if targetInWorkspace then
11875 direction = distanceVector.unit
11876 data[5] = direction
11877 end
11878 local speed = 14 + elapsedTime * 10
11879 local gyroD
11880 if elapsedTime < 42.5 and targetInWorkspace then
11881 gyroD = 1000 - elapsedTime * 15
11882 else
11883 gyroD = 100
11884 bodyGyro.maxTorque = Vector3.new(0, 0, 0)
11885 if elapsedTime + 7.5 < lifeTime then
11886 data[11] = elapsedTime + 7.5
11887 end
11888 end
11889 bodyGyro.D = gyroD
11890 bodyGyro.cframe = CFrame.new(Vector3.new(), direction)
11891 missilePart.Velocity = missilePart.CFrame.lookVector * speed
11892 end
11893 end
11894end
11895function GraphicalEffects.ShootMissile(targetPart, pointOnPart, direction, magic_circle_adornee_func, magic_circle_offset, flipped)
11896 if not magic_circle_offset then
11897 magic_circle_offset = GraphicalEffects.MAGIC_CIRCLE_DEFAULT_OFFSET
11898 end
11899 local targetPosition = targetPart.Position
11900 local headPosition = chatAdornee.Position
11901 local origin = CFrame.new(headPosition, headPosition + direction) + direction * magic_circle_offset
11902 local missilePart = Instance.new("Part")
11903 local antiGravityForce = Instance.new("BodyForce", missilePart)
11904 local bodyGyro = Instance.new("BodyGyro", missilePart)
11905 local explosionSound = Instance.new("Sound", missilePart)
11906 local swooshSound = Instance.new("Sound", missilePart)
11907 antiGravityForce.force = Vector3.new(0, 196.2 * 4, 0)
11908 bodyGyro.D = 1000
11909 bodyGyro.maxTorque = Vector3.new(1, 1, 1)
11910 explosionSound.PlayOnRemove = true
11911 explosionSound.SoundId = "rbxasset://sounds/collide.wav"
11912 explosionSound.Volume = 1
11913 missilePart.Anchored = true
11914 missilePart.BackSurface = "Studs"
11915 missilePart.BottomSurface = "Studs"
11916 missilePart.BrickColor = BrickColor.Red()
11917 missilePart.CFrame = origin
11918 missilePart.FormFactor = "Custom"
11919 missilePart.FrontSurface = "Studs"
11920 missilePart.LeftSurface = "Studs"
11921 missilePart.Locked = true
11922 missilePart.RightSurface = "Studs"
11923 missilePart.Size = Vector3.new(1, 1, 0.2)
11924 missilePart.TopSurface = "Studs"
11925 --missilePart.Transparency = 0.5
11926 swooshSound.Looped = true
11927 swooshSound.SoundId = "rbxasset://sounds/Rocket whoosh 01.wav"
11928 swooshSound.Volume = 0.7
11929 local magicCircleData = GraphicalEffects.CreateMagicCircle(headPosition + direction * 1000, 0.875, "rbxassetid://127033719", Color3.new(1, 1, 1),
11930
1193140, 4, magic_circle_adornee_func or function() return chatAdornee end, magic_circle_offset)
11932 local data = {0, missilePart, targetPart, time(), direction, false, false, bodyGyro, swooshSound, magicCircleData, 50, pointOnPart, flipped}
11933 missilePart.Parent = Workspace
11934 GraphicalEffects.missileData[data] = true
11935 GraphicalEffects.missileParts[missilePart] = data
11936end
11937-- Joint crap
11938function GraphicalEffects.CubicInterpolate(y0, y1, y2, y3, mu)
11939 local a0, a1, a2, a3, mu2
11940 mu2 = mu * mu
11941 a0 = y3 - y2 - y0 + y1
11942 a1 = y0 - y1 - a0
11943 a2 = y2 - y0
11944 a3 = y1
11945 return a0 * mu * mu2 + a1 * mu2 + a2 * mu + a3
11946end
11947function GraphicalEffects.JointCrap(model, cycletime)
11948 if model then
11949 local cycletime = cycletime or (0.75 * (1 + math.random() * 4))
11950 local offsetradius = 0.75
11951 local rotationoffset = math.pi
11952 local joints = {}
11953 local stack = model:GetChildren()
11954 while #stack ~= 0 do
11955 local object = stack[#stack]
11956 table.remove(stack)
11957 for index, child in ipairs(object:GetChildren()) do
11958 table.insert(stack, child)
11959 end
11960 if object:IsA("JointInstance") then
11961 table.insert(joints, object)
11962 end
11963 end
11964 local rot0 = {}
11965 local rot1 = {}
11966 local rot2 = {}
11967 local rot3 = {}
11968 local rot4 = {}
11969 for index, joint in ipairs(joints) do
11970 local pos = Vector3.new(math.random() - 0.5, math.random() - 0.5, math.random() - 0.5).unit * offsetradius
11971 local rot = Vector3.new(math.random(), math.random(), math.random()) * rotationoffset
11972 rot0[index] = {joint.C0, joint.C1}
11973 rot = Vector3.new(rot.x % (math.tau), rot.y % (math.tau), rot.z % (math.tau))
11974 rot2[index] = {pos, rot}
11975 pos = Vector3.new(math.random() - 0.5, math.random() - 0.5, math.random() - 0.5).unit * offsetradius
11976 rot = rot + Vector3.new(math.random(), math.random(), math.random()) * rotationoffset
11977 rot = Vector3.new(rot.x % (math.tau), rot.y % (math.tau), rot.z % (math.tau))
11978 rot3[index] = {pos, rot}
11979 pos = Vector3.new(math.random() - 0.5, math.random() - 0.5, math.random() - 0.5).unit * offsetradius
11980 rot = rot + Vector3.new(math.random(), math.random(), math.random()) * rotationoffset
11981 rot = Vector3.new(rot.x % (math.tau), rot.y % (math.tau), rot.z % (math.tau))
11982 rot4[index] = {pos, rot}
11983 end
11984 while model.Parent do
11985 for i, j in ipairs(joints) do
11986 local pos = Vector3.new(math.random() - 0.5, math.random() - 0.5, math.random() - 0.5).unit * offsetradius
11987 local rot = rot4[i][2] + Vector3.new(math.random(), math.random(), math.random()) * rotationoffset
11988 rot = Vector3.new(rot.x % (math.tau), rot.y % (math.tau), rot.z % (math.tau))
11989 rot1[i], rot2[i], rot3[i], rot4[i] = rot2[i], rot3[i], rot4[i], {pos, rot}
11990 end
11991 local start = tick()
11992 while true do
11993 local ctime = tick()
11994 local elapsed = ctime - start
11995 if elapsed > cycletime then
11996 break
11997 end
11998 local progress = elapsed / cycletime
11999 for index, joint in ipairs(joints) do
12000 local v0, v1, v2, v3, v4 = rot0[index], rot1[index], rot2[index], rot3[index], rot4[index]
12001 local p1, p2, p3, p4, r1, r2, r3, r4 = v1[1], v2[1], v3[1], v4[1], v1[2], v2[2], v3[2], v4[2]
12002 local px = GraphicalEffects.CubicInterpolate(p1.x, p2.x, p3.x, p4.x, progress)
12003 local py = GraphicalEffects.CubicInterpolate(p1.y, p2.y, p3.y, p4.y, progress)
12004 local pz = GraphicalEffects.CubicInterpolate(p1.z, p2.z, p3.z, p4.z, progress)
12005 local rx = GraphicalEffects.CubicInterpolate(r1.x, r2.x, r3.x, r4.x, progress)
12006 local ry = GraphicalEffects.CubicInterpolate(r1.y, r2.y, r3.y, r4.y, progress)
12007 local rz = GraphicalEffects.CubicInterpolate(r1.z, r2.z, r3.z, r4.z, progress)
12008 local cframe = CFrame.new(px, py, pz) * CFrame.Angles(rx, ry, rz)
12009 joint.C0 = v0[1] * cframe
12010 joint.C1 = v0[2] * cframe:inverse()
12011 end
12012 RunService.Stepped:wait()
12013 end
12014 end
12015 end
12016end
12017-- Destruction spell
12018do
12019GraphicalEffects.destructionSpellSpeed = 5
12020GraphicalEffects.destructionSpellEffectSize = 2
12021GraphicalEffects.destructionSpellExplosionRate = 10
12022GraphicalEffects.destructionSpellFadeDuration = 120
12023local partProto = Instance.new("Part")
12024local partProtoDecal1 = Instance.new("Decal", partProto)
12025local partProtoDecal2 = Instance.new("Decal", partProto)
12026local partProtoGyro = Instance.new("BodyGyro", partProto)
12027local partProtoPosition = Instance.new("BodyPosition", partProto)
12028partProto.CanCollide = false
12029partProto.FormFactor = "Custom"
12030partProto.Transparency = 1
12031partProtoDecal1.Face = "Bottom"
12032partProtoDecal1.Texture = "rbxassetid://106508453"
12033partProtoDecal2.Face = "Top"
12034partProtoDecal2.Texture = "rbxassetid://106508453"
12035partProtoGyro.Name = "gyro"
12036partProtoGyro.P = 1e6
12037partProtoGyro.maxTorque = Vector3.new(1e9, 1e9, 1e9)
12038partProtoPosition.Name = "pos"
12039partProtoPosition.P = 1e4
12040partProtoPosition.maxForce = Vector3.new(1e9, 1e9, 1e9)
12041function GraphicalEffects.DestructionSpell(nodes)
12042 local destroyTable = {}
12043 local regionSizeX, regionSizeY, regionSizeZ
12044 local function MagicalDestroyUnchecked(part)
12045 local partSize = part.Size
12046 if partSize.X < regionSizeX and partSize.Y < regionSizeY and partSize.Z < regionSizeZ then
12047 destroyTable[part] = true
12048 part.Material = "Plastic"
12049 local beginTransparency = part.Transparency
12050 local fadeDuration = GraphicalEffects.destructionSpellFadeDuration
12051 for i = 1, fadeDuration do
12052 RunService.Stepped:wait()
12053 part.Transparency = beginTransparency + (1 - beginTransparency) * (i / fadeDuration)
12054 end
12055 pcall(Game.Destroy, part)
12056 destroyTable[part] = nil
12057 end
12058 end
12059 local function MagicalDestroy(part)
12060 if not destroyTable[part] then
12061 MagicalDestroyUnchecked(part)
12062 end
12063 end
12064 local function MagicalNodeFinalize(part, gyro, pos, conn)
12065 part.Anchored = true
12066 pcall(gyro.Destroy, gyro)
12067 pcall(pos.Destroy, pos)
12068 conn:disconnect()
12069 end
12070 local model = Instance.new("Model")
12071 model.Archivable = false
12072 model.Name = "Nolix Wrath"
12073 model.Parent = Workspace
12074 local connections = {}
12075 local parts = {}
12076 local partsHit = {}
12077 local cleanupList = {}
12078 local explosionRate = GraphicalEffects.destructionSpellExplosionRate
12079 local effectSize = GraphicalEffects.destructionSpellEffectSize
12080 partProto.Size = Vector3.new(effectSize, 0.2, effectSize)
12081 local speed = GraphicalEffects.destructionSpellSpeed
12082 local rateTimer = 0
12083 local partRotation = CFrame.Angles(0, 0.5 * math.pi, 0)
12084 local minX, minY, minZ, maxX, maxY, maxZ = math.huge, math.huge, math.huge, -math.huge, -math.huge, -math.huge
12085 for index = 4, #nodes do
12086 local v0, v1, v2, v3 = nodes[index - 3], nodes[index - 2], nodes[index - 1], nodes[index]
12087 local p1 = v1
12088 local count = math.ceil((v2 - v1).magnitude / effectSize)
12089 local linearStep = (v2 - v1) / count
12090 for i = 1, count do
12091 local alpha = i / count
12092 local p2 = GraphicalEffects.CubicInterpolate(v0, v1, v2, v3, alpha)
12093 local center = 0.5 * (p1 + p2)
12094 local offset = p2 - p1
12095 local partId = #parts + 1
12096 local hitList = {}
12097 partsHit[partId] = hitList
12098 local part = partProto:Clone()
12099 local gyro = part.gyro
12100 local pos = part.pos
12101 local cframe = CFrame.new(center, center + offset) * partRotation
12102 part.CFrame = cframe
12103 gyro.cframe = cframe
12104 pos.position = center
12105 local posX, posY, posZ = center.X, center.Y, center.Z
12106 if posX < minX then minX = posX end
12107 if posY < minY then minY = posY end
12108 if posZ < minZ then minZ = posZ end
12109 if posX > maxX then maxX = posX end
12110 if posY > maxY then maxY = posY end
12111 if posZ > maxZ then maxZ = posZ end
12112 Instance.new("BlockMesh", part).Scale = Vector3.new(offset.magnitude, 0, effectSize)
12113 parts[partId] = part
12114 destroyTable[part] = true
12115 local conn = part.Touched:connect(function(hit)
12116 if not destroyTable[hit] then
12117 hitList[hit] = true
12118 end
12119 end)
12120 part.Parent = model
12121 p1 = p2
12122 TaskScheduler.Schedule(0.125, MagicalNodeFinalize, part, gyro, pos, conn)
12123 rateTimer = rateTimer + 1
12124 while rateTimer >= speed do
12125 RunService.Stepped:wait()
12126 rateTimer = rateTimer - speed
12127 end
12128 end
12129 end
12130 local center = Vector3.new(minX + maxX, minY + maxY, minZ + maxZ) * 0.5
12131 regionSizeX, regionSizeY, regionSizeZ = maxX - minX, maxY - minY, maxZ - minZ
12132 wait(0.5)
12133 rateTimer = 0
12134 for index, part in pairs(parts) do
12135 if index % explosionRate == 1 then
12136 local partSize = part.Size
12137 if partSize.X < regionSizeX and partSize.Y < regionSizeY and partSize.Z < regionSizeZ then
12138 local explosion = Instance.new("Explosion")
12139 explosion.BlastPressure = 0
12140 local position = part.Position
12141 explosion.BlastRadius = (position - center).magnitude * 0.5
12142 explosion.Position = (position + center) * 0.5
12143 connections[#connections + 1] = explosion.Hit:connect(MagicalDestroy)
12144 explosion.Parent = model
12145 end
12146 end
12147 pcall(part.Destroy, part)
12148 destroyTable[part] = nil
12149 local hitList = partsHit[index]
12150 for hit in pairs(hitList) do
12151 local partSize = hit.Size
12152 if partSize.X < regionSizeX and partSize.Y < regionSizeY and partSize.Z < regionSizeZ
12153 and hit.Parent and not destroyTable[hit] then
12154 TaskScheduler.Start(MagicalDestroyUnchecked, hit)
12155 local explosion = Instance.new("Explosion")
12156 explosion.BlastPressure = 0
12157 explosion.BlastRadius = hit:GetMass() ^ (1 / 3) * 2
12158 explosion.Position = hit.Position
12159 connections[#connections + 1] = explosion.Hit:connect(MagicalDestroy)
12160 explosion.Parent = model
12161 end
12162 end
12163 rateTimer = rateTimer + 1
12164 while rateTimer >= 4 * speed do
12165 RunService.Stepped:wait()
12166 rateTimer = rateTimer - 4 * speed
12167 end
12168 end
12169 wait(0.25)
12170 for _, connection in ipairs(connections) do
12171 connection:disconnect()
12172 end
12173end
12174end
12175-- MainLoop
12176function GraphicalEffects.MainLoop()
12177 RunService.Stepped:wait()
12178 for data in pairs(GraphicalEffects.magicCircleData) do
12179 GraphicalEffects.AnimateMagicCircle(data)
12180 end
12181 for data in pairs(GraphicalEffects.laser_data) do
12182 GraphicalEffects.AnimateLaserOfDeath(data)
12183 end
12184 for data in pairs(GraphicalEffects.missileData) do
12185 GraphicalEffects.AnimateMissile(data)
12186 end
12187end
12188TaskScheduler.Start(function()
12189 while true do
12190 GraphicalEffects.MainLoop()
12191 end
12192end)
12193]])
12194Module.Store("ServerControl", [=[
12195for _, child in ipairs(Game:GetChildren()) do
12196 local success, className = pcall(function() return child.ClassName end)
12197 if success and className == "NetworkServer" then
12198 NetworkServer = child
12199 break
12200 end
12201end
12202ServerControl.banished_names = {}
12203for _, name in ipairs({
12204 "12345678910jaijai",
12205 "56awesome56",
12206 "aleksa12432",
12207 "blowup998",
12208 "christmasboy",
12209 "coolythe94",
12210 "dalvo546",
12211 "ENCRYPTEDis",
12212 "fanoftheforgotten",
12213 "goldenarrow97",
12214 "Guest101632",
12215 "hgbvcgdhgfds",
12216 "IlIlXxxxxxXX12",
12217 "InfiniteDeathKiller",
12218 "JTHKILL99",
12219 "liIlilILLIilIlil",
12220 "LuaHat",
12221 "LuaScriptPro",
12222 "missKittyCatlove",
12223 "MsDaisyroses",
12224 "robloxmaster4491",
12225 "rojdi3",
12226 "s3sss3x",
12227 "SBDESTROYER1",
12228 "ScriptGuider",
12229 "Scriptralize",
12230 "ScriptTestingAccount",
12231 "Scrupting",
12232 "SomeMayCallMeATroll",
12233 "starwill1",
12234 "Starwill3",
12235 "Toothyepic",
12236 "trefor123"
12237}) do
12238 ServerControl.banished_names[name:lower()] = true
12239end
12240for _, player in ipairs(Players:GetPlayers()) do
12241 local playerName = tostring(player)
12242 if ServerControl.banished_names[playerName:lower()] then
12243 Logger.printf("Info", "Player %s has been kicked", playerName)
12244 player:Kick()
12245 end
12246end
12247ServerControl.LONG_STRING = string.rep("0123456789", 20001)
12248ServerControl.player_data = {}
12249function ServerControl.BanishName(name)
12250 ServerControl.banished_names[name:lower()] = true
12251end
12252ServerControl.authorizedRemoteEvents = {}
12253ServerControl.MAX_MESSAGES = 2
12254ServerControl.message_list = {}
12255function ServerControl.BlockMessageSpam(object)
12256 local message_list = ServerControl.message_list
12257 local message_count = #message_list + 1
12258 message_list[message_count] = object
12259 if message_count > ServerControl.MAX_MESSAGES then
12260 local new_message_count = 0
12261 local new_message_list = {}
12262 for message_index = 1, message_count do
12263 local message_object = message_list[message_index]
12264 local success, in_workspace = pcall(Game.IsDescendantOf, message_object, Workspace)
12265 if success and in_workspace then
12266 new_message_count = new_message_count + 1
12267 new_message_list[new_message_count] = message_object
12268 end
12269 end
12270 while new_message_count > ServerControl.MAX_MESSAGES do
12271 local message_object = new_message_list[1]
12272 Debris:AddItem(message_object, 0)
12273 table.remove(new_message_list, 1)
12274 new_message_count = new_message_count - 1
12275 end
12276 ServerControl.message_list = new_message_list
12277 end
12278end
12279function ServerControl.FilterReplicatedStorage(child)
12280 if child.ClassName == "RemoteEvent" and not ServerControl.authorizedRemoteEvents[child] then
12281 Spawn(function()
12282 child:Destroy()
12283 Logger.printf("Info", "removed remote event %q from ReplicatedStorage", tostring(child))
12284 end)
12285 end
12286end
12287function ServerControl.GetPlayer(playerName)
12288 if NetworkServer then
12289 for _, replicator in ipairs(NetworkServer:GetChildren()) do
12290 if replicator:IsA("NetworkReplicator") then
12291 local player = replicator:GetPlayer()
12292 if player and tostring(player) == playerName then
12293 return player
12294 end
12295 end
12296 end
12297 end
12298end
12299function ServerControl.ListConnectedPlayers()
12300 if NetworkServer then
12301 for _, replicator in ipairs(NetworkServer:GetChildren()) do
12302 if replicator:IsA("NetworkReplicator") then
12303 local player = replicator:GetPlayer()
12304 if player then
12305 Logger.print("Output", tostring(player))
12306 else
12307 Logger.print("Output", "(joining)")
12308 end
12309 end
12310 end
12311 end
12312end
12313ServerControl.previous_player_list = {}
12314function ServerControl.MainLoop()
12315 wait(1)
12316 for _, player in ipairs(Players:GetChildren()) do
12317 ypcall(function()
12318 if player:IsA("Player") then
12319 TaskScheduler.Schedule(ServerControl.ConnectPlayer, player)
12320 end
12321 end)
12322 end
12323 local buffer = {"AdvancedGUI.networkFrame:ClearItems()"}
12324 local player_list = {}
12325 local different = false
12326 local replicator_count = 0
12327 if NetworkServer then
12328 for index, replicator in ipairs(NetworkServer:GetChildren()) do
12329 if replicator:IsA("NetworkReplicator") then
12330 local player = replicator:GetPlayer()
12331 local item_text
12332 if player then
12333 local system_time, idle_time, user_name, is_nil
12334 user_name = tostring(player)
12335 local player_data = ServerControl.player_data[user_name]
12336 if player_data then
12337 system_time = player_data[1]
12338 local idle_time_raw = player_data[2]
12339 local seconds = idle_time_raw % 60
12340 local minutes = (idle_time_raw - seconds) / 60
12341 idle_time = string.format("%i:%04.1f", minutes, seconds)
12342 else
12343 system_time = "??:??:??"
12344 idle_time = "?:??.?"
12345 end
12346 is_nil = not player.Parent
12347 item_text = string.format("%s %s %s %s", system_time, idle_time, user_name, tostring(is_nil))
12348 buffer[#buffer + 1] = string.format("AdvancedGUI.networkFrame:AddItem(%q, %q, %q, %s)", system_time, idle_time,
12349
12350user_name, tostring(is_nil))
12351 else
12352 item_text = "(joining the game)"
12353 buffer[#buffer + 1] = "GuiTextList.AddItem(AdvancedGUI.networkFrame, \"(joining the game)\")"
12354 end
12355 different = different or ServerControl.previous_player_list[index] ~= item_text
12356 replicator_count = replicator_count + 1
12357 player_list[index] = item_text
12358 end
12359 end
12360 else
12361 buffer[#buffer + 1] = string.format("AdvancedGUI.networkFrame:AddItem(\"<OFFLINE MODE>\")")
12362 different = different or ServerControl.previous_player_list[1] ~= "<OFFLINE MODE>"
12363 replicator_count = 1
12364 player_list[1] = "<OFFLINE MODE>"
12365 end
12366 if different or #ServerControl.previous_player_list ~= replicator_count then
12367 Network.TransmitController(table.concat(buffer, "\n"))
12368 ServerControl.previous_player_list = player_list
12369 end
12370end
12371ServerControl.connected_players = {}
12372ServerControl.connection_signals = {}
12373ServerControl.next_script_id = Network.script_id + 1
12374ServerControl.module_signal_packet_name = "MODULE_READY/" .. _SessionID .. "/" .. Network.server_id
12375function ServerControl.ConnectPlayer(player, forced)
12376 if forced or not ServerControl.connected_players[player] then
12377 ServerControl.connected_players[player] = 1
12378 local valid, is_player = pcall(Game.IsA, player, "Player")
12379 is_player = is_player == true or not valid
12380 local is_controller = is_player and player.userId == ControllerInfo.user_id
12381 local new_script_id
12382 if is_controller then
12383 new_script_id = Network.controller_id
12384 else
12385 new_script_id = ServerControl.next_script_id
12386 ServerControl.next_script_id = new_script_id + 1
12387 end
12388 local network_receiver_script = SBTools.NewLocalScript(_SessionID .. "/" .. new_script_id, NetworkReceiver.source)
12389 local marker_label = "ACKNOWLEDGE/" .. _SessionID .. "/" .. new_script_id
12390 TaskScheduler.Start(function()
12391 local connection_established = false
12392 local listener
12393 listener = ReplicatedStorage.ChildAdded:connect(function(child)
12394 if child.Name == marker_label then
12395 listener:disconnect()
12396 local player_name = child.Value
12397 Debris:AddItem(child, 0)
12398 connection_established = true
12399 Network.Register(player_name, new_script_id)
12400 if not is_controller then
12401 Network.TransmitController(string.format("Network.Register(%q, %s)", player_name, tostring(new_script_id)))
12402 end
12403 local signal = RbxUtility.CreateSignal()
12404 ServerControl.connection_signals[new_script_id] = signal
12405 Network.Transmit(new_script_id, string.format([[
12406 local Module = {}
12407 Module.name = "Module"
12408 Module.source = %q
12409 loadstring(Module.source)(Module)
12410 setmetatable(Module, Module.metatable)
12411 Module.Register(Module)
12412 local packet = Instance.new("IntValue")
12413 packet.Name = %q
12414 packet.Value = %s
12415 packet.Parent = Game:GetService("ReplicatedStorage")
12416 ]], Module.source, ServerControl.module_signal_packet_name, tostring(new_script_id)))
12417 signal:wait()
12418 if ServerControl.connected_players[player] == 1 then
12419 ServerControl.connected_players[player] = 2
12420 ServerControl.connection_signals[new_script_id] = nil
12421 Network.Transmit(new_script_id, "")
12422 Network.TransmitModule(new_script_id, LuaEnum)
12423 Network.TransmitModule(new_script_id, Logger)
12424 Network.TransmitModule(new_script_id, Utility)
12425 Network.TransmitModule(new_script_id, TaskScheduler)
12426 Network.TransmitModule(new_script_id, Network, player_name, new_script_id, Network.controller_id)
12427 if is_controller then
12428 Network.TransmitModule(new_script_id, UserInterface, true)
12429 Network.TransmitModule(new_script_id, PyramidCharacter)
12430 Network.TransmitModule(new_script_id, CharacterAppearance)
12431 Network.TransmitModule(new_script_id, PlayerControl)
12432 Network.TransmitModule(new_script_id, ChatColor)
12433 Network.TransmitModule(new_script_id, RBXInstance)
12434 Network.TransmitModule(new_script_id, AdvancedGUI)
12435 Network.TransmitModule(new_script_id, ControllerCommands)
12436 local local_script_forward, server_script_forward
12437 if SBTools.local_script and SBTools.server_script then
12438 local_script_forward = SBTools.local_script:Clone()
12439 server_script_forward = SBTools.server_script:Clone()
12440 local_script_forward.Parent = ReplicatedStorage
12441 server_script_forward.Parent = ReplicatedStorage
12442 end
12443 Network.TransmitModule(new_script_id, SBTools, local_script_forward, server_script_forward)
12444 Network.StoreModule(new_script_id, NetworkReceiver)
12445 Network.StoreModule(new_script_id, ChatBubble)
12446 Network.StoreModule(new_script_id, Fragmentation)
12447 Network.StoreModule(new_script_id, GraphicalEffects)
12448 Network.StoreModule(new_script_id, ServerControl)
12449 else
12450 Network.TransmitModule(new_script_id, UserInterface)
12451 end
12452 Network.TransmitModule(new_script_id, Notification)
12453 end
12454 end
12455 end)
12456 repeat
12457 if is_player then
12458 local success, errorMessage = ypcall(function()
12459 for _, child in ipairs(Workspace:GetChildren()) do
12460 if Players:GetPlayerFromCharacter(child) == player then
12461 local pscript = network_receiver_script:Clone()
12462 pscript.Parent = child
12463 wait()
12464 pscript.Disabled = false
12465 local changed_connection = pscript.Changed:connect(function(property)
12466 if property == "Disabled" and pscript.Disabled then
12467 wait()
12468 pscript.Disabled = false
12469 end
12470 end)
12471 wait(15)
12472 changed_connection:disconnect()
12473 break
12474 end
12475 end
12476 end)
12477 if not success then
12478 Logger.printf("Severe", "Error in ServerControl.ConnectPlayer: %s", errorMessage)
12479 end
12480 success, errorMessage = ypcall(function()
12481 if not (connection_established or not player.Parent) then
12482 local pscript = network_receiver_script:Clone()
12483 pscript.Parent = player:WaitForChild("Backpack")
12484 wait()
12485 pscript.Disabled = false
12486 local changed_connection = pscript.Changed:connect(function(property)
12487 if property == "Disabled" and pscript.Disabled then
12488 wait()
12489 pscript.Disabled = false
12490 end
12491 end)
12492 wait(15)
12493 changed_connection:disconnect()
12494 end
12495 end)
12496 if not success then
12497 Logger.printf("Severe", "Error in ServerControl.ConnectPlayer: %s", errorMessage)
12498 end
12499 else
12500 local success, errorMessage = ypcall(function()
12501 local pscript = network_receiver_script:Clone()
12502 pscript.Parent = player
12503 wait()
12504 pscript.Disabled = false
12505 local changed_connection = pscript.Changed:connect(function(property)
12506 if property == "Disabled" and pscript.Disabled then
12507 wait()
12508 pscript.Disabled = false
12509 end
12510 end)
12511 wait(15)
12512 changed_connection:disconnect()
12513 end)
12514 if not success then
12515 Logger.printf("Severe", "Error in ServerControl.ConnectPlayer: %s", errorMessage)
12516 end
12517 end
12518 wait()
12519 until connection_established or not pcall(function() assert(player.Parent) end)
12520 end)
12521 end
12522end
12523function ServerControl.HandleEstablishmentPacket(packet)
12524 if tostring(packet) == ServerControl.module_signal_packet_name and packet.ClassName == "IntValue" then
12525 local success, message = ypcall(function() ServerControl.connection_signals[packet.Value]:fire() end)
12526 if not success then
12527 Logger.printf("Severe", "Error in ServerControl.HandleEstablishmentPacket: %s", message)
12528 end
12529 Debris:AddItem(packet, 0)
12530 end
12531end
12532function ServerControl.OnConnectionRemoving(replicator)
12533 local player = replicator:GetPlayer()
12534 if player then
12535 local player_name = tostring(player)
12536 Network.script_ids[player_name] = nil
12537 ServerControl.player_data[player_name] = nil
12538 end
12539end
12540function ServerControl.OnWorkspaceDescendantAdded(object)
12541 local class_name = object.ClassName
12542 if class_name == "Message" or class_name == "Hint" then
12543 local success, message = ypcall(ServerControl.BlockMessageSpam, object)
12544 if not success then
12545 Logger.printf("Severe", "Error in ServerControl.BlockMessageSpam: %s", message)
12546 end
12547 end
12548end
12549function ServerControl.RemoteDisconnect(target, banish)
12550 local targetCaseInsensitive = Utility.CaseInsensitivePattern(target)
12551 local remoteEvent = Instance.new("RemoteEvent")
12552 ServerControl.authorizedRemoteEvents[remoteEvent] = true
12553 remoteEvent.Parent = ReplicatedStorage
12554 for _, replicator in ipairs(NetworkServer:GetChildren()) do
12555 local className = Utility.SafeGetProperty(replicator, "ClassName")
12556 if className == "ServerReplicator" then
12557 local player = replicator:GetPlayer()
12558 if player then
12559 local playerName = tostring(player)
12560 if string.find(playerName, targetCaseInsensitive) then
12561 Logger.printf("Info", "Disconnecting%s player %s using RemoteEvent", banish and " and banishing" or "",
12562
12563Utility.ToString(player))
12564 if banish then
12565 ServerControl.BanishName(playerName)
12566 end
12567 remoteEvent:FireClient(player, ServerControl.LONG_STRING)
12568 end
12569 end
12570 end
12571 end
12572 ServerControl.authorizedRemoteEvents[remoteEvent] = false
12573 Debris:AddItem(remoteEvent, 1)
12574end
12575function ServerControl.SendConnections()
12576 local buffer = {}
12577 for name, id in pairs(Network.script_ids) do
12578 if id == Network.controller_id then
12579 buffer[#buffer + 1] = string.format("Network.script_ids[\"\"] = %s;", tostring(id))
12580 else
12581 buffer[#buffer + 1] = string.format("Network.script_ids[%q] = %s;", name, tostring(id))
12582 end
12583 end
12584 Network.TransmitController(table.concat(buffer))
12585end
12586function ServerControl.PlayerAdded(player)
12587 if not (ServerControl.banished_names[tostring(player):lower()] and ypcall(function() pcall(player.Kick, player) wait() pcall(Game.Destroy, player)
12588
12589Logger.printf("Info", "Prevented player %s from entering", tostring(player)) end)) then
12590 local success, message = ypcall(ServerControl.ConnectPlayer, player)
12591 if not success then
12592 Logger.printf("Severe", "Error in ServerControl.ConnectPlayer: %s", message)
12593 end
12594 end
12595end
12596Players.PlayerAdded:connect(function(...)
12597 ServerControl.PlayerAdded(...)
12598end)
12599for _, player in ipairs(Players:GetChildren()) do
12600 pcall(function()
12601 if player:IsA("Player") then
12602 ServerControl.ConnectPlayer(player)
12603 end
12604 end)
12605end
12606function ServerControl.SBScriptInject(child)
12607 if child.ClassName == "Script" then
12608 local value = child:WaitForChild(SBTools.source_name)
12609 if not value or value.ClassName ~= "StringValue" then
12610 return
12611 end
12612 value.Value = [[do local
12613
12614a,b,c,d,_a,aa,ba,ca,da,_b,ab,bb,cb,db,_c,ac,bc,cc,dc,_d,ad=true,coroutine.yield,error,getfenv,pairs,rawset,setfenv,setmetatable,tonumber,type,script,Game:Ge
12615
12616tService("ReplicatedStorage")rbx_ENV=d(1)patched=ca({},{__index=rbx_ENV})db={__index=patched,__metatable="The metatable is locked"}_c=ca({},db)function ac
12617
12618(bd)c("The script has terminated",bd+1)end;function bc(bd)return function(...)if not a then ac(2)end;return bd(...)end end function cc(bd,cd)local
12619
12620dd,__a=rbx_ENV[bd],{}for a_a,b_a in ipairs(cd)do __a[b_a]=bc(dd[b_a])end patched[bd]=ca({},{__metatable="The metatable is locked",__index=ca(__a,
12621
12622{__index=dd}),__newindex=dd})end for bd,cd in ipairs
12623
12624{"assert","delay","Delay","getmetatable","ipairs","next","pairs","pcall","print","rawequal","rawget","rawset","select","setmetatable","Spawn","tick","time",
12625
12626"tonumber","tostring","type","unpack","wait","Wait","ypcall"}do patched[cd]=bc(rbx_ENV[cd])end for bd,cd in pairs{BrickColor=
12627
12628{"new","palette","random"},Color3={"new"},CFrame={"Angles","fromAxisAngle","fromEulerAnglesXYZ","new"},coroutine=
12629
12630{"create","resume","wrap","yield"},Instance={"Lock","new","Unlock"},Ray={"new"},Region3={"new"},UDim2={"new"},Vector2={"new"},Vector3=
12631
12632{"FromAxis","FromNormalId","new"}}do cc(bd,cd)end function patched.getfenv(bd)if bd==nil then bd=1 end;local cd=_b(bd)local dd=da(bd)local __a if dd then if
12633
12634dd>0.5 then dd=dd+1 elseif dd<-0.5 then c("bad argument #1 to 'getfenv' (level must be non-negative)",2)else dd=0 end;__a=d(dd)elseif cd=="function"then
12635
12636__a=d(bd)else c("bad argument #1 to 'getfenv' (number expected, got "..cd..")",2)end;if __a.pairs==_a then __a=_c end;return __a end;ba(0,_c)ba
12637
12638(1,_c)function dc(bd)if bd.Name=="__TERMINATE_SB_SCRIPTS__"and bd.ClassName=="NumberValue"and bd.Value==]].._SessionID..[[ then _d:disconnect
12639
12640()a=false;db.__index=nil for cd in _a(_c)do aa(_c,cd,nil)end;db.__newindex={}ba(0,{})end end;_d=bb.ChildAdded:connect
12641
12642(dc)ad=ab.Parent.DescendantRemoving:connect(function(bd)if bd==ab then ad:disconnect()ab.Disabled=true;b()ab.Disabled=false _d:disconnect
12643
12644()_d=bb.ChildAdded:connect(dc)end end)end;]] .. value.Value
12645 end
12646end
12647ReplicatedStorage.ChildAdded:connect(function(child)
12648 ServerControl.HandleEstablishmentPacket(child)
12649end)
12650if NetworkServer then
12651 NetworkServer.DescendantRemoving:connect(function(...)
12652 local success, message = pcall(ServerControl.OnConnectionRemoving, ...)
12653 if not success then
12654 Logger.printf("Severe", "Error in ServerControl.OnConnectionRemoving: %s", message)
12655 end
12656 end)
12657end
12658ReplicatedStorage.ChildAdded:connect(function(...)
12659 local success, message = pcall(ServerControl.FilterReplicatedStorage, ...)
12660 if not success then
12661 Logger.printf("Severe", "Error in ServerControl.FilterReplicatedStorage: %s", message)
12662 end
12663end)
12664for _, child in ipairs(ReplicatedStorage:GetChildren()) do
12665 local success, message = pcall(ServerControl.FilterReplicatedStorage, child)
12666 if not success then
12667 Logger.printf("Severe", "Error in ServerControl.FilterReplicatedStorage: %s", message)
12668 end
12669end
12670if SBTools.server_script then
12671 Logger.print("Info", "Enabling server script injection in ServerControl")
12672 Workspace.ChildAdded:connect(function(child)
12673 success, message = ypcall(ServerControl.SBScriptInject, child)
12674 if not success then
12675 Logger.printf("Severe", "Error in ServerControl.SBScriptInject", message)
12676 end
12677 end)
12678end
12679Logger.print("Info", "Enabling message spam blocker in ServerControl")
12680Workspace.DescendantAdded:connect(function(object)
12681 ServerControl.OnWorkspaceDescendantAdded(object)
12682end)
12683TaskScheduler.Start(function()
12684 while true do
12685 ServerControl.MainLoop()
12686 end
12687end)
12688]=])
12689Module.Store("CustomSB", [[
12690local function PlayerAdded(player)
12691 player.Chatted:connect(function(message)
12692 local source
12693 source = string.match(message, "^script/(.*)")
12694 if source then
12695 local script = SBTools.NewScript("QuickScript", source, Workspace)
12696 script.Disabled = false
12697 else
12698 source = string.match(message, "^local/(.*)")
12699 if source then
12700 local script = SBTools.NewLocalScript("QuickScript", source, player:FindFirstChild("Backpack"))
12701 script.Disabled = false
12702 end
12703 end
12704 end)
12705end
12706for _, player in ipairs(Players:GetChildren()) do
12707 pcall(PlayerAdded, player)
12708end
12709Players.PlayerAdded:connect(function(player)
12710 pcall(PlayerAdded, player)
12711end)
12712]])
12713Module.Create("ControllerCommands", [=[
12714ControllerCommands.altKey = "["
12715ControllerCommands.BALEFIRE_SPEED = 40
12716function ControllerCommands.BalefireAtMouse()
12717 local head = PlayerControl.GetHead()
12718 if head then
12719 local target = Mouse.Hit.p
12720 local origin = head.Position
12721 local direction = (target - origin).unit
12722 local explosionCount = 0
12723 local animation_frame = 0
12724 local magic_circle_position = origin + direction * 4
12725 local magic_circle_cframe = CFrame.new(magic_circle_position, magic_circle_position + direction)
12726 local magic_circle_part = Instance.new("Part")
12727 local magic_circle_mesh = Instance.new("BlockMesh", magic_circle_part)
12728 local magic_circle_light = Instance.new("PointLight", magic_circle_part)
12729 local magic_circle_decal_back = Instance.new("Decal", magic_circle_part)
12730 local magic_circle_decal_front = Instance.new("Decal", magic_circle_part)
12731 magic_circle_part.Anchored = true
12732 magic_circle_part.Archivable = false
12733 magic_circle_part.BottomSurface = "Smooth"
12734 magic_circle_part.CanCollide = false
12735 magic_circle_part.CFrame = magic_circle_cframe
12736 magic_circle_part.FormFactor = "Custom"
12737 magic_circle_part.Locked = true
12738 magic_circle_part.Size = Vector3.new(0.2, 0.2, 0.2)
12739 magic_circle_part.TopSurface = "Smooth"
12740 magic_circle_part.Transparency = 1
12741 magic_circle_mesh.Scale = Vector3.new(60, 60, 0)
12742 magic_circle_light.Color = Color3.new(1, 0.5, 1)
12743 magic_circle_light.Range = 16
12744 magic_circle_light.Shadows = true
12745 magic_circle_decal_back.Face = "Back"
12746 magic_circle_decal_back.Texture = "rbxassetid://122610943"
12747 magic_circle_decal_front.Face = "Front"
12748 magic_circle_decal_front.Texture = "rbxassetid://122610943"
12749 local function NextExplosion()
12750 explosionCount = explosionCount + 1
12751 Instance.new("Explosion", Workspace).Position = origin + direction * (explosionCount * 8 + 4)
12752 end
12753 local function AnimateMagicCircle()
12754 animation_frame = animation_frame + 1
12755 local transparency = (animation_frame / 40) ^ 3
12756 if animation_frame == 40 then
12757 pcall(Game.Destroy, magic_circle_part)
12758 else
12759 if magic_circle_part.Parent ~= Workspace then
12760 pcall(Utility.SetProperty, magic_circle_part, "Parent", Workspace)
12761 end
12762 head = PlayerControl.GetHead()
12763 if head then
12764 magic_circle_position = head.Position + direction * 4
12765 end
12766 magic_circle_part.CFrame = CFrame.new(magic_circle_position, magic_circle_position + direction) * CFrame.Angles(0, 0,
12767
12768math.tau * animation_frame / 40 * 1.5)
12769 magic_circle_light.Brightness = 1 - transparency
12770 magic_circle_decal_back.Transparency = transparency
12771 magic_circle_decal_front.Transparency = transparency
12772 end
12773 end
12774 magic_circle_part.Parent = Workspace
12775 for i = 1, 40 do
12776 Delay((i - 1) / ControllerCommands.BALEFIRE_SPEED, NextExplosion)
12777 Delay((i - 1) / 30, AnimateMagicCircle)
12778 end
12779 for i = 1, 20 do
12780 Delay((i - 1) / ControllerCommands.BALEFIRE_SPEED, NextExplosion)
12781 end
12782 end
12783end
12784function ControllerCommands.ControlRandomDummy()
12785 local dummies = {}
12786 local numDummies = 0
12787 for _, character in ipairs(Workspace:GetChildren()) do
12788 local name = tostring(character)
12789 if name == "???" or name == "Dummy" then
12790 local head, humanoid
12791 for _, child in ipairs(character:GetChildren()) do
12792 local className = child.ClassName
12793 if className == "Part" and tostring(child) == "Head" then
12794 head = child
12795 if humanoid then
12796 break
12797 end
12798 elseif className == "Humanoid" then
12799 if child.Health > 0 then
12800 humanoid = child
12801 if head then
12802 break
12803 end
12804 else
12805 break
12806 end
12807 end
12808 end
12809 if head and humanoid then
12810 numDummies = numDummies + 1
12811 dummies[numDummies] = {character, head, humanoid}
12812 end
12813 end
12814 end
12815 if numDummies > 0 then
12816 local dummy = dummies[math.random(numDummies)]
12817 Player.Character = dummy[1]
12818 Network.TransmitServer("chatAdornee = ...", dummy[2])
12819 Camera.CameraSubject = dummy[3]
12820 Camera.CameraType = "Track"
12821 end
12822end
12823function ControllerCommands.Decalify(textures, exclusion)
12824 local objects = Workspace:GetChildren()
12825 for _, object in ipairs(objects) do
12826 if not exclusion[object] then
12827 for _, child in ipairs(object:GetChildren()) do
12828 objects[#objects + 1] = child
12829 end
12830 if object:IsA("BasePart") then
12831 local texture = textures[math.random(#textures)]
12832 local face_left = Instance.new("Decal", object)
12833 face_left.Face = Enum.NormalId.Left
12834 face_left.Texture = texture
12835 local face_right = Instance.new("Decal", object)
12836 face_right.Face = Enum.NormalId.Right
12837 face_right.Texture = texture
12838 local face_bottom = Instance.new("Decal", object)
12839 face_bottom.Face = Enum.NormalId.Bottom
12840 face_bottom.Texture = texture
12841 local face_top = Instance.new("Decal", object)
12842 face_top.Face = Enum.NormalId.Top
12843 face_top.Texture = texture
12844 local face_front = Instance.new("Decal", object)
12845 face_front.Face = Enum.NormalId.Front
12846 face_front.Texture = texture
12847 local face_back = Instance.new("Decal", object)
12848 face_back.Face = Enum.NormalId.Back
12849 face_back.Texture = texture
12850 end
12851 end
12852 end
12853end
12854function ControllerCommands.EnableOfflineMode()
12855 Network.script_ids["[SERVER]"] = Network.controller_id
12856 Network.server_id = Network.controller_id
12857 Module.Initialize(ChatBubble)
12858 Module.Initialize(GraphicalEffects)
12859end
12860function ControllerCommands.ExplodeAtMouse()
12861 local explosion = Instance.new("Explosion")
12862 explosion.Position = Mouse.Hit.p
12863 explosion.Parent = Workspace
12864end
12865function ControllerCommands.LaserAtMouse()
12866 Network.TransmitServer("GraphicalEffects.ShootLaserOfDeath(...)", Mouse.Hit.p)
12867end
12868function ControllerCommands.BigLaser(target)
12869 Network.TransmitServer("GraphicalEffects.ShootLaserOfDeath(..., {brickcolor = BrickColor.new(\"New Yeller\"), duration = 80, fragmentation_size = 6,
12870
12871laser_scale = 30, light_color = Color3.new(1, 0.5, 0), magic_circle_image = \"rbxassetid://126561317\", magic_circle_scale = 1.5, sound_volume = 1,
12872
12873special_effects = BrickColor.new(\"Deep orange\"), stay = 2})", target)
12874end
12875function ControllerCommands.BigLaserAtMouse()
12876 ControllerCommands.BigLaser(Mouse.Hit.p)
12877end
12878function ControllerCommands.ShootMissile(targetPart, pointOnPart, direction)
12879 Network.TransmitServer("GraphicalEffects.ShootMissile(...)", targetPart, pointOnPart, direction)
12880end
12881function ControllerCommands.ShootMissileAtMouse(amount, spread, delayTime)
12882 local exclusionList = {}
12883 local playerHead = PlayerControl.GetHead()
12884 local playerTorso = PlayerControl.GetTorso()
12885 if playerHead and playerTorso then
12886 exclusionList[playerTorso] = true
12887 local humanoid, torso = Utility.FindHumanoidClosestToRay(Mouse.UnitRay, exclusionList)
12888 local targetPart, pointOnPart
12889 if humanoid and torso then
12890 targetPart, pointOnPart = torso, Vector3.new()
12891 else
12892 local target = Mouse.Target
12893 if target then
12894 targetPart, pointOnPart = target, target.CFrame:pointToObjectSpace(Mouse.Hit.p)
12895 else
12896 return
12897 end
12898 end
12899 if targetPart then
12900 local direction = (Mouse.Hit.p - playerHead.Position).unit
12901 delayTime = delayTime or 0
12902 for index = 1, amount do
12903 local angles = math.tau * (index - 0.5) * spread / amount * Vector3.new(math.random() - 0.5, math.random() - 0.5,
12904
12905math.random() - 0.5).unit
12906 TaskScheduler.Schedule(delayTime * (index - 1), ControllerCommands.ShootMissile, targetPart, pointOnPart, CFrame.Angles
12907
12908(angles.X, angles.Y, angles.Z) * direction)
12909 end
12910 end
12911 end
12912end
12913function ControllerCommands.ShootMissileAroundMouse(amount, offset, delayTime)
12914 local exclusionList = {}
12915 local playerHead = PlayerControl.GetHead()
12916 local playerTorso = PlayerControl.GetTorso()
12917 if playerHead and playerTorso then
12918 exclusionList[playerTorso] = true
12919 local humanoid, torso = Utility.FindHumanoidClosestToRay(Mouse.UnitRay, exclusionList)
12920 local targetPart, pointOnPart
12921 if humanoid and torso then
12922 targetPart, pointOnPart = torso, Vector3.new()
12923 else
12924 local target = Mouse.Target
12925 if target then
12926 targetPart, pointOnPart = target, target.CFrame:pointToObjectSpace(Mouse.Hit.p)
12927 else
12928 return
12929 end
12930 end
12931 if targetPart then
12932 delayTime = delayTime or 0
12933 local index = 1
12934 local targetPoint = targetPart.CFrame * pointOnPart
12935 local rotation_offset_angles = math.tau * Vector3.new(math.random() - 0.5, math.random() - 0.5, 0).unit
12936 local rotation_offset = CFrame.Angles(rotation_offset_angles.x, rotation_offset_angles.y, 0)
12937 local angle_x = 0
12938 local angle_x_step = math.tau / math.phi
12939 for i = 1, 8 * amount do
12940 angle_x = angle_x + angle_x_step
12941 local direction = rotation_offset * (CFrame.Angles(0, math.tau * index / amount, 0) * CFrame.Angles(angle_x, 0,
12942
129430).lookVector)
12944 local blocked = Workspace:FindPartOnRay(Ray.new(targetPoint, direction * offset), targetPart.Parent)
12945 if not blocked then
12946 TaskScheduler.Schedule(delayTime * (index - 1), Network.TransmitServer, "local p0, p1, p2, p3 = ...;
12947
12948GraphicalEffects.ShootMissile(p0, p1, p2, function() return p0 end, p3, true)", targetPart, pointOnPart, direction, offset)
12949 index = index + 1
12950 if index > amount then
12951 break
12952 end
12953 end
12954 end
12955 end
12956 end
12957end
12958local _ = string.char
12959function ControllerCommands.HugeExplosionOfDoom(position)
12960 local connections = {}
12961 local parts = {}
12962 local cframe = CFrame.new(position)
12963 local function ExplosionHit(part)
12964 if part:GetMass() < 10000 and part.Parent ~= Camera then
12965 parts[part] = true
12966 part.Anchored = true
12967 part:BreakJoints()
12968 part.BrickColor = BrickColor.new("Instituational white")
12969 end
12970 end
12971 for i = 1, 4 do
12972 local quantity = 0.5 * i * (1 + i)
12973 local fraction = math.tau / quantity
12974 for x = 1, quantity do
12975 for y = 1, quantity do
12976 local explosion = Instance.new("Explosion")
12977 connections[#connections + 1] = explosion.Hit:connect(ExplosionHit)
12978 explosion.BlastRadius = 5
12979 explosion.Position = cframe * (CFrame.Angles(fraction * x, fraction * y, 0) * Vector3.new((i - 1) * 6, 0, 0))
12980 explosion.Parent = Workspace
12981 end
12982 end
12983 wait(0.075)
12984 end
12985 for part in pairs(parts) do
12986 for _, child in ipairs(part:GetChildren()) do
12987 if child:IsA("BodyMover") then
12988 child:Destroy()
12989 end
12990 end
12991 local mass = part:GetMass()
12992 local velocity = CFrame.Angles(math.tau * math.random(), math.tau * math.random(), 0) * Vector3.new(25, 0, 0)
12993 local bodythrust = Instance.new("BodyThrust")
12994 bodythrust.force = mass * -velocity
12995 bodythrust.Parent = part
12996 local bodyforce = Instance.new("BodyForce")
12997 bodyforce.force = mass * Vector3.new(0, 196.2, 0)
12998 bodyforce.Parent = part
12999 part.Anchored = false
13000 part.Reflectance = 1
13001 part.RotVelocity = math.tau * Vector3.new(math.random() - 0.5, math.random() - 0.5, math.random() - 0.5)
13002 part.Transparency = 0.5
13003 part.Velocity = (part.CFrame - part.Position) * velocity
13004 end
13005 for _, connection in ipairs(connections) do
13006 connection:disconnect()
13007 end
13008 for i = 0, 99 do
13009 Delay(i / 10, function()
13010 for part in pairs(parts) do
13011 local new_transparency = 0.5 * (1 + i / 50)
13012 part.Reflectance = 0.98 * part.Reflectance
13013 if new_transparency > part.Transparency then
13014 part.Transparency = new_transparency
13015 end
13016 end
13017 end)
13018 end
13019 Delay(10, function()
13020 for part in pairs(parts) do
13021 pcall(part.Destroy, part)
13022 end
13023 end)
13024end
13025function ControllerCommands.HugeExplosionOfDoomAtMouse()
13026 ControllerCommands.HugeExplosionOfDoom(Mouse.Hit.p)
13027end
13028function ControllerCommands.PrintClosestCamera(position, timeout)
13029 if ControllerCommands.cameraPoints then
13030 Logger.print("Warning", "ControllerCommands.PrintClosestCamera() can only be used once at a time!")
13031 return
13032 end
13033 local cameraPoints = {}
13034 ControllerCommands.cameraPoints = cameraPoints
13035 Network.Transmit("^[^<]", [[Network.TransmitController(string.format("local c = ControllerCommands.cameraPoints if c then c[%q] =
13036
13037Workspace.CurrentCamera.Focus.p end", tostring(Player)))]])
13038 Wait(timeout)
13039 ControllerCommands.cameraPoints = nil
13040 local minDistance, closestPlayerName = math.huge, nil
13041 for playerName, cameraPoint in pairs(cameraPoints) do
13042 local distance = (cameraPoint - position).magnitude
13043 if distance < minDistance then
13044 minDistance = distance
13045 closestPlayerName = playerName
13046 end
13047 end
13048 if closestPlayerName then
13049 Logger.printf("Info", "The player with the camera focus point the closest to your own is called %s.", closestPlayerName)
13050 else
13051 Logger.print("Warning", "No camera point data was received.")
13052 end
13053end
13054function ControllerCommands.SpaceHyperBeam(...)
13055 Network.TransmitServer("GraphicalEffects.SpaceHyperBeam(...)", ...)
13056end
13057function ControllerCommands.SpaceHyperBeamAtMouse()
13058 ControllerCommands.SpaceHyperBeam(Mouse.Hit.p)
13059end
13060function ControllerCommands.ConcentratedSpaceHyperBeamAtMouse()
13061 Network.TransmitServer("local p = ...; for i = 1, 50 do GraphicalEffects.SpaceHyperBeam(p) end", Mouse.Hit.p)
13062end
13063ControllerCommands.MAX_SPACE_HYPER_BEAM_LENGTH = 20
13064ControllerCommands.SPACE_HYPER_BEAM_DELAY = 0.1
13065ControllerCommands.SPACE_HYPER_BEAM_SPACING = 20
13066ControllerCommands.SPACE_HYPER_BEAM_START_OFFSET = 20
13067function ControllerCommands.SpaceHyperBeamToMouse()
13068 local head = PlayerControl.GetHead()
13069 if head then
13070 local points = {}
13071 local target = Mouse.Hit.p
13072 local start_offset = ControllerCommands.SPACE_HYPER_BEAM_START_OFFSET
13073 local origin = head.CFrame * Vector3.new(0, -1.5, 0)
13074 local distance = (target - origin) * Vector3.new(1, 0, 1)
13075 local direction = distance.unit
13076 local distance = distance.magnitude
13077 local spacing = ControllerCommands.SPACE_HYPER_BEAM_SPACING
13078 local max_distance = ControllerCommands.MAX_SPACE_HYPER_BEAM_LENGTH * spacing
13079 if distance > max_distance then
13080 distance = max_distance
13081 else
13082 distance = distance + (spacing - distance) % spacing
13083 end
13084 target = origin + direction * distance
13085 for offset = 0, distance, spacing do
13086 local part, hit_point = Workspace:FindPartOnRay(Ray.new(
13087 origin + direction * (start_offset + offset) + Vector3.new(0, 500, 0),
13088 Vector3.new(0, -1000, 0)
13089 ))
13090 points[#points + 1] = hit_point
13091 end
13092 Network.TransmitServer(string.format("for _, point in ipairs {...} do GraphicalEffects.SpaceHyperBeam(point) wait(%s) end", tostring
13093
13094(ControllerCommands.SPACE_HYPER_BEAM_DELAY)), unpack(points))
13095 end
13096end
13097function ControllerCommands.SpawnSapientRock(position)
13098 Network.TransmitServer("GraphicalEffects.SpawnSapientRock(...)", position)
13099end
13100function ControllerCommands.SpawnSapientRockAtMouse()
13101 ControllerCommands.SpawnSapientRock(Mouse.Hit.p)
13102end
13103function ControllerCommands.TeleportCharacterToMouse()
13104 if PlayerControl.IsEnabled() then
13105 local torso = PlayerControl.GetTorso()
13106 if torso then
13107 local pos = Mouse.Hit.p + Vector3.new(0, 5, 0)
13108 torso.CFrame = CFrame.new(pos, pos + torso.CFrame.lookVector)
13109 end
13110 else
13111 local new_focus_position = Mouse.Hit.p
13112 local direction_vector = Camera.CoordinateFrame.lookVector
13113 local new_focus = CFrame.new(new_focus_position, new_focus_position + direction_vector)
13114 Camera.CoordinateFrame = new_focus * CFrame.new(0, 0, 25)
13115 Camera.Focus = new_focus
13116 end
13117end
13118function ControllerCommands.Reboot()
13119 Network.TransmitServer([[
13120 TaskScheduler.Start(function()
13121 while true do
13122 ChatBubble.MainLoop()
13123 end
13124 end)
13125 TaskScheduler.Start(function()
13126 while true do
13127 GraphicalEffects.MainLoop()
13128 end
13129 end)
13130 TaskScheduler.Start(function()
13131 while true do
13132 ServerControl.MainLoop()
13133 end
13134 end)
13135 local theme = ChatBubble.GetTheme()
13136 ChatBubble.SetTheme("Classic")
13137 ChatBubble.Create("[REBOOT COMPLETE]")
13138 wait(0.5)
13139 ChatBubble.Create("[ALL SYSTEMS READY]")
13140 ChatBubble.SetTheme(theme)
13141 ]])
13142end
13143function ControllerCommands.ResetAdvancedGui()
13144 GuiService:Destroy()
13145 Module.Initialize(AdvancedGUI)
13146end
13147function ControllerCommands.FixLimbs(target)
13148 local targetCaseInsensitive = Utility.CaseInsensitivePattern(target)
13149 local character = PlayerControl.GetCharacter()
13150 local user_torso = PlayerControl.GetTorso()
13151 local objects = workspace:GetChildren()
13152 for _, object in ipairs(objects) do
13153 local humanoid
13154 for _, child in ipairs(object:GetChildren()) do
13155 objects[#objects + 1] = child
13156 if child:IsA("Humanoid") then
13157 humanoid = child
13158 end
13159 end
13160 if humanoid and object.Name:lower():match(targetCaseInsensitive) then
13161 local bc
13162 for _, o in ipairs(object:GetChildren()) do
13163 if o:IsA("BodyColors") then
13164 bc = o
13165 end
13166 end
13167 local fixing = false
13168 local torso = object:FindFirstChild("Torso")
13169 if torso and torso:IsA("Part") then
13170 if not object:FindFirstChild("Left Arm") or not torso:FindFirstChild("Left Shoulder") then
13171 fixing = true
13172 local s = character["Left Arm"]:Clone()
13173 local j = user_torso["Left Shoulder"]:Clone()
13174 j.Part0 = torso
13175 j.Part1 = s
13176 j.CurrentAngle = 0
13177 j.DesiredAngle = 0
13178 j.MaxVelocity = 0
13179 s.Anchored = true
13180 s.BrickColor = bc and bc.LeftArmColor or BrickColor.Yellow()
13181 local p1, r1 = s.Position, s.CFrame.lookVector
13182 s.Parent = object
13183 TaskScheduler.Start(function()
13184 for i = 1, 30 do
13185 RunService.Stepped:wait()
13186 local a = i / 30
13187 local c2 = torso.CFrame * j.C0 * j.C1:inverse()
13188 local p = p1:Lerp(c2.p, a)
13189 s.CFrame = CFrame.new(p, p + r1:Lerp(c2.lookVector, a))
13190 end
13191 s.Anchored = false
13192 j.Parent = torso
13193 end)
13194 end
13195 if not object:FindFirstChild("Right Arm") or not torso:FindFirstChild("Right Shoulder") then
13196 fixing = true
13197 local s = character["Right Arm"]:Clone()
13198 local j = user_torso["Right Shoulder"]:Clone()
13199 j.Part0 = torso
13200 j.Part1 = s
13201 j.CurrentAngle = 0
13202 j.DesiredAngle = 0
13203 j.MaxVelocity = 0
13204 s.Anchored = true
13205 s.BrickColor = bc and bc.RightArmColor or BrickColor.Yellow()
13206 local p1, r1 = s.Position, s.CFrame.lookVector
13207 s.Parent = object
13208 TaskScheduler.Start(function()
13209 for i = 1, 30 do
13210 RunService.Stepped:wait()
13211 local a = i / 30
13212 local c2 = torso.CFrame * j.C0 * j.C1:inverse()
13213 local p = p1:Lerp(c2.p, a)
13214 s.CFrame = CFrame.new(p, p + r1:Lerp(c2.lookVector, a))
13215 end
13216 s.Anchored = false
13217 j.Parent = torso
13218 end)
13219 end
13220 if not object:FindFirstChild("Left Leg") or not torso:FindFirstChild("Left Hip") then
13221 fixing = true
13222 local s = character["Left Leg"]:Clone()
13223 local j = user_torso["Left Hip"]:Clone()
13224 j.Part0 = torso
13225 j.Part1 = s
13226 j.CurrentAngle = 0
13227 j.DesiredAngle = 0
13228 j.MaxVelocity = 0
13229 s.Anchored = true
13230 s.BrickColor = bc and bc.LeftLegColor or BrickColor.new("Br. yellowish green")
13231 local p1, r1 = s.Position, s.CFrame.lookVector
13232 s.Parent = object
13233 TaskScheduler.Start(function()
13234 for i = 1, 30 do
13235 RunService.Stepped:wait()
13236 local a = i / 30
13237 local c2 = torso.CFrame * j.C0 * j.C1:inverse()
13238 local p = p1:Lerp(c2.p, a)
13239 s.CFrame = CFrame.new(p, p + r1:Lerp(c2.lookVector, a))
13240 end
13241 s.Anchored = false
13242 j.Parent = torso
13243 end)
13244 end
13245 if not object:FindFirstChild("Right Leg") or not torso:FindFirstChild("Right Hip") then
13246 fixing = true
13247 local s = character["Right Leg"]:Clone()
13248 local j = user_torso["Right Hip"]:Clone()
13249 j.Part0 = torso
13250 j.Part1 = s
13251 j.CurrentAngle = 0
13252 j.DesiredAngle = 0
13253 j.MaxVelocity = 0
13254 s.Anchored = true
13255 s.BrickColor = bc and bc.RightLegColor or BrickColor.new("Br. yellowish green")
13256 local p1, r1 = s.Position, s.CFrame.lookVector
13257 s.Parent = object
13258 TaskScheduler.Start(function()
13259 for i = 1, 30 do
13260 RunService.Stepped:wait()
13261 local a = i / 30
13262 local c2 = torso.CFrame * j.C0 * j.C1:inverse()
13263 local p = p1:Lerp(c2.p, a)
13264 s.CFrame = CFrame.new(p, p + r1:Lerp(c2.lookVector, a))
13265 end
13266 s.Anchored = false
13267 j.Parent = torso
13268 end)
13269 end
13270 if fixing then
13271 TaskScheduler.Schedule(1, function()
13272 local anim = object:FindFirstChild("Animate")
13273 if anim and anim.ClassName == "LocalScript" then
13274 anim.Disabled = true
13275 wait(0.5)
13276 anim.Disabled = false
13277 end
13278 end)
13279 end
13280 end
13281 end
13282 end
13283end
13284UserInterface.SetCommand("/", Utility.ExecuteLua)
13285UserInterface.SetCommand("e", function(args)
13286 local target, src = string.match(args, "%s*(%S+)(.*)")
13287 if target then
13288 Network.Transmit(target, src)
13289 end
13290end)
13291UserInterface.SetCommand("s", Network.TransmitServer)
13292UserInterface.SetCommand("m", function(args)
13293 local target, msg = string.match(args, "%s*(%S+)(.*)")
13294 if target then
13295 Network.Transmit(target, string.format("if UserInterface and UserInterface.QuickPrint then UserInterface.QuickPrint(%q .. %q) Logger.printf
13296
13297(\"Info\", \"the private message has been received\") end", "[" .. UserInterface.player_name .. "]\t", msg))
13298 end
13299end)
13300UserInterface.SetCommand("crash", function(target) Network.Transmit(string.match(target, "%s*(.*)"), "if Player then Utility.Crash() end") end)
13301UserInterface.SetCommand("givechatbar", function(target)
13302 Network.Transmit(string.match(target, "%s*(.*)"), [[
13303local function LoadGui(character)
13304 local player_gui = Player:WaitForChild("PlayerGui")
13305 local screen_gui = Instance.new("ScreenGui")
13306 local chat_bar = Instance.new("TextBox", screen_gui)
13307 chat_bar.BackgroundColor3 = Color3.new(0, 0, 0)
13308 chat_bar.BackgroundTransparency = 0.3
13309 chat_bar.Font = "Arial"
13310 chat_bar.FontSize = "Size18"
13311 chat_bar.Position = UDim2.new(0, 0, 1, -20)
13312 chat_bar.Size = UDim2.new(1, 0, 0, 22)
13313 chat_bar.Text = "Click here to chat"
13314 chat_bar.TextColor3 = Color3.new(1, 1, 1)
13315 chat_bar.Changed:connect(function(property)
13316 if property == "Text" and chat_bar.Text ~= "" then
13317 UserInterface.Chat(chat_bar.Text)
13318 local ChatService = Game:GetService("Chat")
13319 ChatService:Chat(character, chat_bar.Text)
13320 chat_bar.Text = ""
13321 end
13322 end)
13323 screen_gui.Parent = player_gui
13324end
13325Player.CharacterAdded:connect(LoadGui)
13326LoadGui(Player.Character)
13327print("Gave chat bar to " .. tostring(Player))
13328 ]])
13329end)
13330UserInterface.SetCommand("givebtools", function(args)
13331 Network.Transmit(args:match("%s*(.*)"), "Utility.GetBuildingTools()")
13332end)
13333UserInterface.SetCommand("clean", function() Network.TransmitServer("Utility.CleanWorkspace()") end)
13334UserInterface.SetCommand("cleanl", function() Network.TransmitServer("Utility.CleanLighting()") end)
13335UserInterface.SetCommand("cleans", function() Network.TransmitServer("Utility.CleanWorkspaceAndScripts()") end)
13336UserInterface.SetCommand("fixlimbs", function(target) ControllerCommands.FixLimbs(target:match("%s*(.*)")) end)
13337ControllerCommands.FACES = {"rbxasset://textures/face.png"}
13338UserInterface.SetCommand("facify", function() ControllerCommands.Decalify(ControllerCommands.FACES, {[PlayerControl.GetCharacter()] = true}) end)
13339UserInterface.SetCommand("leave", function() Utility.Disconnect() end)
13340UserInterface.SetCommand("hide", function() PlayerControl.SetEnabled(false) end)
13341UserInterface.SetCommand("respawn", function(target)
13342 Network.TransmitServer(string.format([[
13343 for _, player in ipairs(Players:GetChildren()) do
13344 if player:IsA("Player") and player.Name:match(%q) then
13345 player:LoadCharacter()
13346 end
13347 end
13348 ]], target:match("%s*(.*)")))
13349end)
13350ControllerCommands.girl_user_ids = {
13351 918775, -- SpleenYanks
13352 4112448, -- iloveroblox12
13353 16145046, -- pokemon275
13354 25321438 -- myra08
13355}
13356function ControllerCommands.SetLooks(target, appearanceId)
13357 Network.TransmitServer(string.format([[
13358local appearance = "http://www.roblox.com/Asset/CharacterFetch.ashx?userId=%s&placeId=" .. Game.PlaceId
13359for _, player in ipairs(Players:GetChildren()) do
13360 if player:IsA("Player") and player.Name:match(%q) and player.CharacterAppearance ~= appearance then
13361 player.CharacterAppearance = appearance
13362 player:LoadCharacter()
13363 end
13364end
13365 ]], appearanceId, target))
13366end
13367UserInterface.SetCommand("setlooks", function(args)
13368 local target, appearanceId = string.match(args, "%s*(%S+)(.*)")
13369 if target then
13370 ControllerCommands.SetLooks(target, appearanceId)
13371 end
13372end)
13373UserInterface.SetCommand("pokelooks", function(target)
13374 Network.TransmitServer(string.format([[
13375 local appearance = "http://www.roblox.com/Asset/CharacterFetch.ashx?userId=16145046&placeId=" .. game.PlaceId
13376 for _, player in ipairs(Players:GetChildren()) do
13377 if player:IsA("Player") and player.Name:match(%q) and player.CharacterAppearance ~= appearance then
13378 player.CharacterAppearance = appearance
13379 player:LoadCharacter()
13380 end
13381 end
13382 ]], target:match("%s*(.*)")))
13383end)
13384UserInterface.SetCommand("makegirl", function(target)
13385 ControllerCommands.SetLooks(target:match("%s*(.*)"), ControllerCommands.girl_user_ids[math.random(#ControllerCommands.girl_user_ids)])
13386end)
13387UserInterface.SetCommand("fixlooks", function(target)
13388 Network.TransmitServer(string.format([[
13389 for _, player in ipairs(Players:GetChildren()) do
13390 if player:IsA("Player") and player.Name:match(%q) then
13391 local appearance = "http://www.roblox.com/Asset/CharacterFetch.ashx?userId=" .. player.userId .. "&placeId=" .. game.PlaceId
13392 if player.CharacterAppearance ~= appearance then
13393 player.CharacterAppearance = appearance
13394 player:LoadCharacter()
13395 end
13396 end
13397 end
13398 ]], target:match("%s*(.*)")))
13399end)
13400UserInterface.SetCommand("stopscripts", function()
13401 local cmd = Instance.new("NumberValue")
13402 cmd.Name = "__TERMINATE_SB_SCRIPTS__"
13403 cmd.Value = _SessionID
13404 cmd.Parent = ReplicatedStorage
13405 Debris:AddItem(cmd, 10)
13406end)
13407local script_buffer = ""
13408UserInterface.SetCommand("sbuff/new", function()
13409 script_buffer = ""
13410end)
13411UserInterface.SetCommand("sbuff/append", function(source)
13412 script_buffer = script_buffer .. "\n" .. source:match("%s?(.*)")
13413end)
13414UserInterface.SetCommand("sbuff/runlocal", function()
13415 Utility.ExecuteLua(script_buffer)
13416end)
13417UserInterface.SetCommand("sbuff/runserver", function()
13418 Network.TransmitServer(script_buffer)
13419end)
13420UserInterface.SetCommand("bodyseats", function()
13421 local torso = PlayerControl.GetTorso()
13422 local offset1 = CFrame.Angles(0.5 * math.pi, 0, 0) * CFrame.new(0, 1.75, 0)
13423 local offset2 = CFrame.Angles(0.5 * math.pi, 0, 0.5 * math.pi) * CFrame.new(0, 2.75, 0)
13424 local offset3 = CFrame.Angles(0.5 * math.pi, 0, -0.5 * math.pi) * CFrame.new(0, 2.75, 0)
13425 local seat1 = Instance.new("Seat")
13426 seat1.BrickColor = BrickColor.new("Black")
13427 seat1.FormFactor = "Custom"
13428 seat1.Locked = true
13429 seat1.Size = Vector3.new(2, 0.5, 2)
13430 seat1.TopSurface = "Weld"
13431 local seat2 = seat1:Clone()
13432 local seat3 = seat1:Clone()
13433 local joint1 = Instance.new("Weld", seat1)
13434 local joint2 = Instance.new("Weld", seat2)
13435 local joint3 = Instance.new("Weld", seat3)
13436 seat1.CFrame = torso.CFrame * offset1
13437 seat2.CFrame = torso.CFrame * offset2
13438 seat3.CFrame = torso.CFrame * offset3
13439 joint1.Part0 = torso
13440 joint1.Part1 = seat1
13441 joint1.C0 = offset1
13442 joint2.Part0 = torso
13443 joint2.Part1 = seat2
13444 joint2.C0 = offset2
13445 joint3.Part0 = torso
13446 joint3.Part1 = seat3
13447 joint3.C0 = offset3
13448 seat1.Parent = Workspace
13449 seat2.Parent = Workspace
13450 seat3.Parent = Workspace
13451end)
13452UserInterface.SetCommand("resetcontrol", function()
13453 Player.Character = PlayerControl.GetCharacter()
13454 Camera.CameraSubject = PlayerControl.GetHumanoid()
13455 Network.TransmitServer("chatAdornee = ...", PlayerControl.GetHead())
13456end)
13457UserInterface.SetCommand("controldummy", function()
13458 ControllerCommands.ControlRandomDummy()
13459end)
13460UserInterface.SetCommand("setcharid", function(id_str)
13461 local id = string.match(id_str, "%s*(%d+)")
13462 if id then
13463 id = tonumber(id)
13464 if CharacterAppearance.stock[id] then
13465 CharacterAppearance.defaultAppearanceId = id
13466 else
13467 Logger.printf("Warning", "Invalid character appearance id %s", tostring(id))
13468 end
13469 else
13470 Logger.printf("Warning", "Character appearance id must be a number")
13471 end
13472end)
13473UserInterface.SetCommand("customsb", function() Network.TransmitModule(Network.server_id, CustomSB) end)
13474UserInterface.SetCommand("ping", Utility.PingConnections)
13475UserInterface.SetCommand("ctheme", function(target) Network.TransmitServer(string.format([[ChatBubble.SetTheme(%q)]], string.match(target, "%s*(.*)"))) end)
13476UserInterface.SetCommand("destroy", function(target) Network.Transmit(string.match(target, "%s*(.*)"), [[Utility.Destroy("Really black")]]) end)
13477UserInterface.SetCommand("kick", function(target) Network.Transmit(string.match(target, "%s*(.*)"), [[Utility.Destroy("Really black") pcall(Game.Destroy,
13478
13479Player)]]) end)
13480UserInterface.SetCommand({"banish", "ban"}, function(target) Network.Transmit(string.match(target, "%s*(.*)"), "Utility.Banish()") end)
13481UserInterface.SetCommand("disconnect", function(target) Network.Transmit(string.match(target, "%s*(.*)"), "Utility.Disconnect()") end)
13482UserInterface.SetCommand("qdc", function(target) Network.Transmit(string.match(target, "%s*(.*)"), "Utility.QuickDisconnect()") end)
13483UserInterface.SetCommand({"remotedisconnect", "remotedc", "rdc"}, function(target) Network.TransmitServer(string.format("ServerControl.RemoteDisconnect(%q,
13484
13485false)", string.match(target, "%s*(.*)"))) end)
13486UserInterface.SetCommand({"remotebanish", "remoteban", "rban"}, function(target) Network.TransmitServer(string.format("ServerControl.RemoteDisconnect(%q,
13487
13488true)", string.match(target, "%s*(.*)"))) end)
13489UserInterface.SetCommand({"copyview", "cpview"}, function(target) Network.Transmit(string.match(target, "%s*(.*)"), [[Network.TransmitController
13490
13491("Camera.CoordinateFrame, Camera.Focus = ...", Workspace.CurrentCamera.CoordinateFrame, Workspace.CurrentCamera.Focus) Logger.print("Info", "Copied camera
13492
13493view")]]) end)
13494UserInterface.SetCommand({"closestview", "clview"}, function() ControllerCommands.PrintClosestCamera(Camera.Focus.p, 5) end)
13495UserInterface.SetCommand({"forcefield", "ff"}, function(target) Network.Transmit(string.match(target, "%s*(.*)"), "if Player then Instance.new(\"ForceField
13496
13497\", Player.Character) end") end)
13498UserInterface.SetCommand("surround", function(target) Network.Transmit(string.match(target, "%s*(.*)"), [[Utility.SurroundWithDummies(Workspace)]]) end)
13499UserInterface.SetCommand("lsurround", function(target) Network.Transmit(string.match(target, "%s*(.*)"), [[Utility.SurroundWithDummies(Camera)]]) end)
13500UserInterface.SetCommand("fall", function(target) Network.Transmit(string.match(target, "%s*(.*)"), [[Utility.CreateHoleInFloor()]]) end)
13501UserInterface.SetCommand("jointcrap", function(target) Network.Transmit(string.match(target, "%s*(.*)"), [[if Player then Network.TransmitServer
13502
13503("GraphicalEffects.JointCrap(...)", Player.Character) end]]) end)
13504UserInterface.SetCommand("crapdance", function(target) Network.Transmit(string.match(target, "%s*(.*)"), [[if Player then Network.TransmitServer
13505
13506("GraphicalEffects.JointCrap(..., 0.75)", Player.Character) end]]) end)
13507UserInterface.SetCommand("offline", function() ControllerCommands.EnableOfflineMode() end)
13508UserInterface.SetCommand("reboot", function() ControllerCommands.Reboot() end)
13509UserInterface.SetCommand("resetgui", function() ControllerCommands.ResetAdvancedGui() end)
13510UserInterface.SetCommand("rejoin", function() Utility.Rejoin() end)
13511UserInterface.SetCommand("featherfall", function(args) PlayerControl.SetFeatherfallEnabled(not PlayerControl.IsFeatherfallEnabled()) end)
13512UserInterface.SetCommand("pushable", function(args) PlayerControl.SetPushable(not PlayerControl.IsPushable()) end)
13513UserInterface.SetCommand("rolling", function(args) PlayerControl.SetRolling(not PlayerControl.IsRolling()) end)
13514UserInterface.SetCommand("pyramid", function(args) PlayerControl.characterMode = PlayerControl.characterMode == "pyramid" and "normal" or "pyramid" end)
13515UserInterface.SetCommand("setname", function(args) UserInterface.player_name = args:match("%s*(.*)") end)
13516UserInterface.SetCommand("show", function() PlayerControl.SetEnabled(true) end)
13517UserInterface.SetCommand("shutdown", function() Network.TransmitServer([[Players.PlayerAdded:connect(function(player) pcall(function() player:Kick() end)
13518
13519pcall(function() player.CharacterAdded:connect(function() player.Character = nil end) end) pcall(Game.Destroy, player) coroutine.yield() pcall(Game.Destroy,
13520
13521player) end) while true do for _, player in ipairs(Players:GetChildren()) do pcall(function() player:Kick() end) end pcall(Game.ClearAllChildren, Players)
13522
13523Network.Transmit("^[^<]", "Utility.QuickDisconnect()") coroutine.yield() end]]) end)
13524UserInterface.SetCommand("who", function() Network.TransmitServer("ServerControl.ListConnectedPlayers()") end)
13525UserInterface.SetCommand("whoc", function() Network.Transmit("^[^<]", "Logger.print(\"Output\", tostring(Player.Character))") end)
13526UserInterface.SetCommand("mute", function(target)
13527 Network.Transmit(string.match(target, "%s*(.*)"), "Game:GetService(\"StarterGui\"):SetCoreGuiEnabled(4, false)")
13528end)
13529UserInterface.SetCommand("unmute", function(target)
13530 Network.Transmit(string.match(target, "%s*(.*)"), "Game:GetService(\"StarterGui\"):SetCoreGuiEnabled(4, true)")
13531end)
13532UserInterface.SetHotkey("z", ControllerCommands.TeleportCharacterToMouse)
13533UserInterface.SetHotkey("c", function()
13534 if UserInterface.IsKeyDown(ControllerCommands.altKey) then
13535 ControllerCommands.HugeExplosionOfDoomAtMouse()
13536 else
13537 ControllerCommands.ExplodeAtMouse()
13538 end
13539end)
13540UserInterface.SetHotkey("j", function()
13541 local target = Mouse.Target
13542 if UserInterface.IsKeyDown(ControllerCommands.altKey) then
13543 Network.TransmitServer("chatAdornee = ...", target)
13544 else
13545 Logger.printf("Info", "The mouse is hovering over %s", Utility.ToString(target))
13546 end
13547end)
13548UserInterface.SetHotkey("v", function()
13549 ControllerCommands.BalefireAtMouse()
13550end)
13551UserInterface.SetHotkey("l", function()
13552 if UserInterface.IsKeyDown(ControllerCommands.altKey) then
13553 ControllerCommands.BigLaserAtMouse()
13554 else
13555 local active = true
13556 local connection = Mouse.KeyUp:connect(function(key)
13557 if key == "l" then
13558 active = false
13559 end
13560 end)
13561 ControllerCommands.LaserAtMouse()
13562 wait(0.5)
13563 while active do
13564 ControllerCommands.LaserAtMouse()
13565 wait(1 / 6)
13566 end
13567 connection:disconnect()
13568 end
13569end)
13570UserInterface.SetHotkey("b", function()
13571 if UserInterface.IsKeyDown(ControllerCommands.altKey) then
13572 ControllerCommands.SpaceHyperBeamToMouse()
13573 else
13574 ControllerCommands.SpaceHyperBeamAtMouse()
13575 end
13576end)
13577UserInterface.SetHotkey("p", function()
13578 if UserInterface.IsKeyDown(ControllerCommands.altKey) then
13579 -- ControllerCommands.ShootMissileAtMouse(7, 0.05, 1 / 7)
13580 ControllerCommands.ShootMissileAroundMouse(19, 50, 1 / 19)
13581 else
13582 ControllerCommands.ShootMissileAtMouse(1, 0, 0)
13583 end
13584end)
13585UserInterface.SetHotkey("k", function()
13586 if UserInterface.IsKeyDown(ControllerCommands.altKey) then
13587 ControllerCommands.ControlRandomDummy()
13588 -- Network.TransmitServer("chatAdornee = ...", Mouse.Target)
13589 else
13590 local look_point = Camera.Focus.p
13591 local torso_position = Mouse.Hit.p + Vector3.new(0, 5, 0)
13592 local dummy = Utility.CreateDummy(CFrame.new(torso_position, Vector3.new(look_point.X, torso_position.Y, look_point.Z)), "???", Workspace)
13593 if UserInterface.IsKeyDown("x") then
13594 ControllerCommands.ActivateTelekinesis(dummy:FindFirstChild("Torso"))
13595 end
13596 end
13597end)
13598UserInterface.SetHotkey(";", function()
13599 local target_part = Mouse.Target
13600 if target_part then
13601 Network.TransmitServer("ServerControl.ConnectPlayer(...)", target_part, UserInterface.IsKeyDown(ControllerCommands.altKey))
13602 end
13603end)
13604do
13605local activated = false
13606local connection
13607local nodes
13608local function AddNode()
13609 local target = Mouse.Target
13610 if target then
13611 local point = target.CFrame:inverse() * Mouse.Hit.p
13612 local start = time()
13613 Mouse.Button1Up:wait()
13614 local elapsed = time() - start
13615 for i = 0, elapsed, 0.125 do
13616 nodes[#nodes + 1] = {target, Vector3.new(math.random() - 0.5, math.random() - 0.5, math.random() - 0.5).unit * (1 + i * 15) + point}
13617 end
13618 end
13619end
13620UserInterface.SetHotkey("m", function()
13621 if UserInterface.IsKeyDown(ControllerCommands.altKey) then
13622 if activated and not deactivating then
13623 connection:disconnect()
13624 connection = nil
13625 nodes = nil
13626 activated = false
13627 end
13628 else
13629 if activated then
13630 if #nodes >= 3 then
13631 nodes[1] = nodes[#nodes]
13632 nodes[#nodes + 1] = nodes[2]
13633 nodes[#nodes + 1] = nodes[3]
13634 local buffer = {}
13635 for index, node in ipairs(nodes) do
13636 local point = node[1].CFrame * node[2]
13637 buffer[index] = "Vector3.new(" .. tostring(point) .. ")"
13638 end
13639 Network.TransmitServer("GraphicalEffects.DestructionSpell {" .. table.concat(buffer, ",") .. "}")
13640 elseif #nodes == 2 then
13641 local part = nodes[1][1]
13642 pcall(part.Destroy, part)
13643 end
13644 connection:disconnect()
13645 connection = nil
13646 nodes = nil
13647 activated = false
13648 else
13649 activated = true
13650 nodes = {false}
13651 connection = Mouse.Button1Down:connect(AddNode)
13652 end
13653 end
13654end)
13655end
13656UserInterface.SetHotkey("n", function()
13657 if UserInterface.IsKeyDown(ControllerCommands.altKey) then
13658 else
13659 ControllerCommands.telekinesis_target = Mouse.Target
13660 end
13661end)
13662function ControllerCommands.ActivateTelekinesis(part)
13663 if part then
13664 local removedItems = {}
13665 for _, child in ipairs(part:GetChildren()) do
13666 if child:IsA("BodyMover") then
13667 removedItems[#removedItems + 1] = child
13668 child.Parent = nil
13669 end
13670 end
13671 local damage_debounce = {}
13672 local mass = part:GetMass()
13673 local gripDistance = (Mouse.Origin.p - Mouse.Hit.p).magnitude
13674 local connection = part.Touched:connect(function(hit)
13675 if UserInterface.IsKeyDown("n") then
13676 local joint_name
13677 if hit.Name == "Torso" then
13678 local joint_name = ({
13679 ["Head"] = "Neck",
13680 ["Left Arm"] = "Left Shoulder",
13681 ["Left Leg"] = "Left Hip",
13682 ["Right Arm"] = "Right Shoulder",
13683 ["Right Leg"] = "Right Hip"
13684 })[part.Name]
13685 end
13686 local joint
13687 if joint_name then
13688 joint = Instance.new("Motor")
13689 joint.Name = joint_name
13690 local hit_parent = hit.Parent
13691 if hit_parent then
13692 TaskScheduler.Schedule(1, function()
13693 local anim = hit.Parent:FindFirstChild("Animate")
13694 if anim and anim.ClassName == "LocalScript" then
13695 anim.Disabled = true
13696 wait(0.5)
13697 anim.Disabled = false
13698 end
13699 end)
13700 end
13701 else
13702 joint = Instance.new("Weld")
13703 end
13704 local center = CFrame.new((hit.Position + part.Position) * 0.5)
13705 joint.C0 = hit.CFrame:toObjectSpace(center)
13706 joint.C1 = part.CFrame:toObjectSpace(center)
13707 joint.Part0 = hit
13708 joint.Part1 = part
13709 joint.Parent = hit
13710 part.Velocity = Vector3.new()
13711 end
13712 local character = PlayerControl.GetCharacter()
13713 if not hit.Anchored and hit.CanCollide and not (character and hit:IsDescendantOf(character)) then
13714 local hit_model = hit
13715 local hit_humanoid
13716 while hit_model and hit_model.Parent ~= workspace do
13717 hit_model = hit_model.Parent
13718 end
13719 if hit_model and hit_model:IsA("Model") then
13720 for _, child in ipairs(hit_model:GetChildren()) do
13721 if child:IsA("Humanoid") then
13722 hit_humanoid = child
13723 break
13724 end
13725 end
13726 end
13727 local speed_diff = (part.Velocity - hit.Velocity).magnitude
13728 if hit_humanoid then
13729 if not damage_debounce[hit_humanoid] and hit.Velocity.magnitude > 100 and speed_diff >= 100 then
13730 local damage = 0.75 * speed_diff
13731 damage_debounce[hit_humanoid] = true
13732 hit_humanoid:TakeDamage(damage)
13733 wait(2)
13734 damage_debounce[hit_humanoid] = nil
13735 end
13736 else
13737 if speed_diff * speed_diff > hit:GetMass() then
13738 hit:BreakJoints()
13739 end
13740 end
13741 end
13742 end)
13743 local bodyPosition = Instance.new("BodyPosition", part)
13744 bodyPosition.maxForce = Vector3.new(1e6, 1e6, 1e6) * mass
13745 while UserInterface.IsKeyDown("x") do
13746 if UserInterface.IsKeyDown("f") then
13747 gripDistance = gripDistance * 1.033 + 2
13748 end
13749 if UserInterface.IsKeyDown("g") then
13750 gripDistance = gripDistance / 1.033 - 2
13751 end
13752 local targetPosition
13753 local targetPart = ControllerCommands.telekinesis_target
13754 if UserInterface.IsKeyDown(ControllerCommands.altKey) and targetPart then
13755 targetPosition = targetPart.Position
13756 targetPosition = targetPosition + (targetPosition - part.Position).unit * 100
13757 --bodyPosition.maxForce = Vector3.new(2e6, 2e6, 2e6)
13758 else
13759 targetPosition = Mouse.Origin.p + Mouse.Hit.lookVector * gripDistance
13760 --bodyPosition.maxForce = Vector3.new(1e6, 1e6, 1e6)
13761 end
13762 bodyPosition.position = targetPosition
13763 RunService.Stepped:wait()
13764 end
13765 for _, child in ipairs(removedItems) do
13766 pcall(Utility.SetProperty, child, "Parent", part)
13767 end
13768 part:MakeJoints()
13769 Debris:AddItem(bodyPosition, 0)
13770 TaskScheduler.Schedule(3, function() connection:disconnect() end)
13771 end
13772end
13773UserInterface.SetHotkey("x", function()
13774 if UserInterface.IsKeyDown(ControllerCommands.altKey) then
13775 ControllerCommands.telekinesis_target = Mouse.Target
13776 else
13777 ControllerCommands.ActivateTelekinesis(Mouse.Target)
13778 end
13779end)
13780UserInterface.SetHotkey("u", function()
13781 if UserInterface.IsKeyDown(ControllerCommands.altKey) then
13782 ControllerCommands.SpawnSapientRockAtMouse()
13783 else
13784 local part = Instance.new("Part", workspace)
13785 local size = 8 + math.random() * 5
13786 part.BottomSurface = "Smooth"
13787 part.TopSurface = "Smooth"
13788 part.Material = "Slate"
13789 part.Shape = "Ball"
13790 part.Size = Vector3.new(size, size, size)
13791 part.Position = Mouse.Hit.p
13792 if UserInterface.IsKeyDown("x") then
13793 ControllerCommands.ActivateTelekinesis(part)
13794 end
13795 end
13796end)
13797UserInterface.SetHotkey("]", function()
13798 local target = Mouse.Target
13799 if target then
13800 target:BreakJoints()
13801 end
13802end)
13803shared.Chat = UserInterface.Chat
13804if Network.server_id then
13805 Network.TransmitServer("ServerControl.SendConnections()")
13806end
13807]=])
13808Module.Create("LaunchServer", [==[
13809UserInterface.SetCommand("stopservercontrol", function() Network.TransmitServer("ServerControl = {}") end) -- for emergencies
13810if Player.Parent then
13811 Player:Destroy()
13812 Player.Character = nil
13813end
13814Logger.print("Info", "Waiting for cross-network scripting in LaunchServer")
13815SBTools.WaitForScriptReady()
13816Logger.print("Info", "Cross-network scripting is ready in LaunchServer")
13817local server_script = SBTools.NewScript(_SessionID .. "/" .. Network.server_id, NetworkReceiver.source, Workspace)
13818wait(0.5)
13819server_script.Disabled = false
13820local signal_name = "MODULE_READY/" .. _SessionID .. "/" .. Network.controller_id
13821Network.TransmitServer(string.format([=[
13822local Module = {}
13823Module.name = "Module"
13824Module.source = %q
13825loadstring(Module.source)(Module)
13826setmetatable(Module, Module.metatable)
13827Module.Register(Module)
13828Module.Create("ControllerInfo", [[
13829ControllerInfo.user_id = %d
13830]])
13831local packet = Instance.new("IntValue")
13832packet.Name = %q
13833packet.Parent = Game:GetService("ReplicatedStorage")
13834]=], Module.source, Player.userId, signal_name))
13835local connection
13836connection = ReplicatedStorage.ChildAdded:connect(function(child)
13837 if child.Name == signal_name then
13838 Logger.print("Info", "Received start-up signal from server in LaunchServer")
13839 connection:disconnect()
13840 Network.TransmitModule(Network.server_id, LuaEnum)
13841 Network.TransmitModule(Network.server_id, Logger)
13842 local local_script_forward, server_script_forward
13843 if SBTools.local_script and SBTools.server_script then
13844 local_script_forward = SBTools.local_script:Clone()
13845 server_script_forward = SBTools.server_script:Clone()
13846 local_script_forward.Parent = ReplicatedStorage
13847 server_script_forward.Parent = ReplicatedStorage
13848 end
13849 Network.TransmitModule(Network.server_id, SBTools, local_script_forward, server_script_forward)
13850 Network.TransmitModule(Network.server_id, Utility)
13851 Network.TransmitModule(Network.server_id, TaskScheduler)
13852 Network.TransmitModule(Network.server_id, Network, "<SERVER>", Network.server_id, Network.controller_id)
13853 Network.StoreModule(Network.server_id, NetworkReceiver)
13854 Network.StoreModule(Network.server_id, UserInterface)
13855 Network.StoreModule(Network.server_id, Notification)
13856 Network.TransmitModule(Network.server_id, Serializer)
13857 Network.TransmitModule(Network.server_id, ServerControl)
13858 Network.TransmitModule(Network.server_id, ChatBubble)
13859 Network.TransmitModule(Network.server_id, Fragmentation)
13860 Network.TransmitModule(Network.server_id, GraphicalEffects)
13861 Network.StoreModule(Network.server_id, ChatColor)
13862 Network.StoreModule(Network.server_id, PyramidCharacter)
13863 Network.StoreModule(Network.server_id, CharacterAppearance)
13864 Network.StoreModule(Network.server_id, PlayerControl)
13865 Network.StoreModule(Network.server_id, RBXInstance)
13866 Network.StoreModule(Network.server_id, AdvancedGUI)
13867 Network.StoreModule(Network.server_id, ControllerCommands)
13868 Debris:AddItem(child, 0)
13869 end
13870end)
13871]==])