· 2 years ago · Jul 02, 2023, 02:05 PM
1-- services
2local runService = game:GetService("RunService");
3local players = game:GetService("Players");
4local workspace = game:GetService("Workspace");
5
6-- variables
7local localPlayer = players.LocalPlayer;
8local camera = workspace.CurrentCamera;
9local viewportSize = camera.ViewportSize;
10local container = Instance.new("Folder",
11 gethui and gethui() or game:GetService("CoreGui"));
12
13-- locals
14local floor = math.floor;
15local round = math.round;
16local sin = math.sin;
17local cos = math.cos;
18local clear = table.clear;
19local unpack = table.unpack;
20local find = table.find;
21local create = table.create;
22local fromMatrix = CFrame.fromMatrix;
23
24-- methods
25local wtvp = camera.WorldToViewportPoint;
26local isA = workspace.IsA;
27local getPivot = workspace.GetPivot;
28local findFirstChild = workspace.FindFirstChild;
29local findFirstChildOfClass = workspace.FindFirstChildOfClass;
30local getChildren = workspace.GetChildren;
31local toOrientation = CFrame.identity.ToOrientation;
32local pointToObjectSpace = CFrame.identity.PointToObjectSpace;
33local lerpColor = Color3.new().Lerp;
34local min2 = Vector2.zero.Min;
35local max2 = Vector2.zero.Max;
36local lerp2 = Vector2.zero.Lerp;
37local min3 = Vector3.zero.Min;
38local max3 = Vector3.zero.Max;
39
40-- constants
41local HEALTH_BAR_OFFSET = Vector2.new(5, 0);
42local HEALTH_TEXT_OFFSET = Vector2.new(3, 0);
43local HEALTH_BAR_OUTLINE_OFFSET = Vector2.new(0, 1);
44local NAME_OFFSET = Vector2.new(0, 2);
45local DISTANCE_OFFSET = Vector2.new(0, 2);
46local VERTICES = {
47 Vector3.new(-1, -1, -1),
48 Vector3.new(-1, 1, -1),
49 Vector3.new(-1, 1, 1),
50 Vector3.new(-1, -1, 1),
51 Vector3.new(1, -1, -1),
52 Vector3.new(1, 1, -1),
53 Vector3.new(1, 1, 1),
54 Vector3.new(1, -1, 1)
55};
56
57-- functions
58local function isBodyPart(name)
59 return name == "Head" or name:find("Torso") or name:find("Leg") or name:find("Arm");
60end
61
62local function getBoundingBox(parts)
63 local min, max;
64 for i = 1, #parts do
65 local part = parts[i];
66 local cframe, size = part.CFrame, part.Size;
67
68 min = min3(min or cframe.Position, (cframe - size*0.5).Position);
69 max = max3(max or cframe.Position, (cframe + size*0.5).Position);
70 end
71
72 local center = (min + max)*0.5;
73 local front = Vector3.new(center.X, center.Y, max.Z);
74 return CFrame.new(center, front), max - min;
75end
76
77local function worldToScreen(world)
78 local screen, inBounds = wtvp(camera, world);
79 return Vector2.new(screen.X, screen.Y), inBounds, screen.Z;
80end
81
82local function calculateCorners(cframe, size)
83 local corners = create(#VERTICES);
84 for i = 1, #VERTICES do
85 corners[i] = worldToScreen((cframe + size*0.5*VERTICES[i]).Position);
86 end
87
88 local min = min2(viewportSize, unpack(corners));
89 local max = max2(Vector2.zero, unpack(corners));
90 return {
91 corners = corners,
92 topLeft = Vector2.new(floor(min.X), floor(min.Y)),
93 topRight = Vector2.new(floor(max.X), floor(min.Y)),
94 bottomLeft = Vector2.new(floor(min.X), floor(max.Y)),
95 bottomRight = Vector2.new(floor(max.X), floor(max.Y))
96 };
97end
98
99local function rotateVector(vector, radians)
100 -- https://stackoverflow.com/questions/28112315/how-do-i-rotate-a-vector
101 local x, y = vector.X, vector.Y;
102 local c, s = cos(radians), sin(radians);
103 return Vector2.new(x*c - y*s, x*s + y*c);
104end
105
106local function parseColor(self, color, isOutline)
107 if color == "Team Color" or (self.interface.sharedSettings.useTeamColor and not isOutline) then
108 return self.interface.getTeamColor(self.player) or Color3.new(1,1,1);
109 end
110 return color;
111end
112
113-- esp object
114local EspObject = {};
115EspObject.__index = EspObject;
116
117function EspObject.new(player, interface)
118 local self = setmetatable({}, EspObject);
119 self.player = assert(player, "Missing argument #1 (Player expected)");
120 self.interface = assert(interface, "Missing argument #2 (table expected)");
121 self:Construct();
122 return self;
123end
124
125function EspObject:_create(class, properties)
126 local drawing = Drawing.new(class);
127 for property, value in next, properties do
128 pcall(function() drawing[property] = value; end);
129 end
130 self.bin[#self.bin + 1] = drawing;
131 return drawing;
132end
133
134function EspObject:Construct()
135 self.charCache = {};
136 self.childCount = 0;
137 self.bin = {};
138 self.drawings = {
139 box3d = {
140 {
141 self:_create("Line", { Thickness = 1, Visible = false }),
142 self:_create("Line", { Thickness = 1, Visible = false }),
143 self:_create("Line", { Thickness = 1, Visible = false })
144 },
145 {
146 self:_create("Line", { Thickness = 1, Visible = false }),
147 self:_create("Line", { Thickness = 1, Visible = false }),
148 self:_create("Line", { Thickness = 1, Visible = false })
149 },
150 {
151 self:_create("Line", { Thickness = 1, Visible = false }),
152 self:_create("Line", { Thickness = 1, Visible = false }),
153 self:_create("Line", { Thickness = 1, Visible = false })
154 },
155 {
156 self:_create("Line", { Thickness = 1, Visible = false }),
157 self:_create("Line", { Thickness = 1, Visible = false }),
158 self:_create("Line", { Thickness = 1, Visible = false })
159 }
160 },
161 visible = {
162 tracerOutline = self:_create("Line", { Thickness = 3, Visible = false }),
163 tracer = self:_create("Line", { Thickness = 1, Visible = false }),
164 boxFill = self:_create("Square", { Filled = true, Visible = false }),
165 boxOutline = self:_create("Square", { Thickness = 3, Visible = false }),
166 box = self:_create("Square", { Thickness = 1, Visible = false }),
167 healthBarOutline = self:_create("Line", { Thickness = 3, Visible = false }),
168 healthBar = self:_create("Line", { Thickness = 1, Visible = false }),
169 healthText = self:_create("Text", { Center = true, Visible = false }),
170 name = self:_create("Text", { Text = self.player.DisplayName, Center = true, Visible = false }),
171 distance = self:_create("Text", { Center = true, Visible = false }),
172 weapon = self:_create("Text", { Center = true, Visible = false }),
173 },
174 hidden = {
175 arrowOutline = self:_create("Triangle", { Thickness = 3, Visible = false }),
176 arrow = self:_create("Triangle", { Filled = true, Visible = false })
177 }
178 };
179
180 self.renderConnection = runService.Heartbeat:Connect(function(deltaTime)
181 self:Update(deltaTime);
182 self:Render(deltaTime);
183 end);
184end
185
186function EspObject:Destruct()
187 self.renderConnection:Disconnect();
188
189 for i = 1, #self.bin do
190 self.bin[i]:Remove();
191 end
192
193 clear(self);
194end
195
196function EspObject:Update()
197 local interface = self.interface;
198
199 self.options = interface.teamSettings[interface.isFriendly(self.player) and "friendly" or "enemy"];
200 self.character = interface.getCharacter(self.player);
201 self.health, self.maxHealth = interface.getHealth(self.player);
202 self.weapon = interface.getWeapon(self.player);
203 self.enabled = self.options.enabled and self.character and not
204 (#interface.whitelist > 0 and not find(interface.whitelist, self.player.UserId));
205
206 local head = self.enabled and findFirstChild(self.character, "Head");
207 if not head then
208 self.charCache = {};
209 self.onScreen = false;
210 return;
211 end
212
213 local _, onScreen, depth = worldToScreen(head.Position);
214 self.onScreen = onScreen;
215 self.distance = depth;
216
217 if interface.sharedSettings.limitDistance and depth > interface.sharedSettings.maxDistance then
218 self.onScreen = false;
219 end
220
221 if self.onScreen then
222 local cache = self.charCache;
223 local children = getChildren(self.character);
224 if not cache[1] or self.childCount ~= #children then
225 clear(cache);
226
227 for i = 1, #children do
228 local part = children[i];
229 if isA(part, "BasePart") and isBodyPart(part.Name) then
230 cache[#cache + 1] = part;
231 end
232 end
233
234 self.childCount = #children;
235 end
236
237 self.corners = calculateCorners(getBoundingBox(cache));
238 elseif self.options.offScreenArrow then
239 local cframe = camera.CFrame;
240 local flat = fromMatrix(cframe.Position, cframe.RightVector, Vector3.yAxis);
241 local objectSpace = pointToObjectSpace(flat, head.Position);
242 self.direction = Vector2.new(objectSpace.X, objectSpace.Z).Unit;
243 end
244end
245
246function EspObject:Render()
247 local onScreen = self.onScreen or false;
248 local enabled = self.enabled or false;
249 local visible = self.drawings.visible;
250 local hidden = self.drawings.hidden;
251 local box3d = self.drawings.box3d;
252 local interface = self.interface;
253 local options = self.options;
254 local corners = self.corners;
255
256 visible.box.Visible = enabled and onScreen and options.box;
257 visible.boxOutline.Visible = visible.box.Visible and options.boxOutline;
258 if visible.box.Visible then
259 local box = visible.box;
260 box.Position = corners.topLeft;
261 box.Size = corners.bottomRight - corners.topLeft;
262 box.Color = parseColor(self, options.boxColor[1]);
263 box.Transparency = options.boxColor[2];
264
265 local boxOutline = visible.boxOutline;
266 boxOutline.Position = box.Position;
267 boxOutline.Size = box.Size;
268 boxOutline.Color = parseColor(self, options.boxOutlineColor[1], true);
269 boxOutline.Transparency = options.boxOutlineColor[2];
270 end
271
272 visible.boxFill.Visible = enabled and onScreen and options.boxFill;
273 if visible.boxFill.Visible then
274 local boxFill = visible.boxFill;
275 boxFill.Position = corners.topLeft;
276 boxFill.Size = corners.bottomRight - corners.topLeft;
277 boxFill.Color = parseColor(self, options.boxFillColor[1]);
278 boxFill.Transparency = options.boxFillColor[2];
279 end
280
281 visible.healthBar.Visible = enabled and onScreen and options.healthBar;
282 visible.healthBarOutline.Visible = visible.healthBar.Visible and options.healthBarOutline;
283 if visible.healthBar.Visible then
284 local barFrom = corners.topLeft - HEALTH_BAR_OFFSET;
285 local barTo = corners.bottomLeft - HEALTH_BAR_OFFSET;
286
287 local healthBar = visible.healthBar;
288 healthBar.To = barTo;
289 healthBar.From = lerp2(barTo, barFrom, self.health/self.maxHealth);
290 healthBar.Color = lerpColor(options.dyingColor, options.healthyColor, self.health/self.maxHealth);
291
292 local healthBarOutline = visible.healthBarOutline;
293 healthBarOutline.To = barTo + HEALTH_BAR_OUTLINE_OFFSET;
294 healthBarOutline.From = barFrom - HEALTH_BAR_OUTLINE_OFFSET;
295 healthBarOutline.Color = parseColor(self, options.healthBarOutlineColor[1], true);
296 healthBarOutline.Transparency = options.healthBarOutlineColor[2];
297 end
298
299 visible.healthText.Visible = enabled and onScreen and options.healthText;
300 if visible.healthText.Visible then
301 local barFrom = corners.topLeft - HEALTH_BAR_OFFSET;
302 local barTo = corners.bottomLeft - HEALTH_BAR_OFFSET;
303
304 local healthText = visible.healthText;
305 healthText.Text = round(self.health) .. "hp";
306 healthText.Size = interface.sharedSettings.textSize;
307 healthText.Font = interface.sharedSettings.textFont;
308 healthText.Color = parseColor(self, options.healthTextColor[1]);
309 healthText.Transparency = options.healthTextColor[2];
310 healthText.Outline = options.healthTextOutline;
311 healthText.OutlineColor = parseColor(self, options.healthTextOutlineColor, true);
312 healthText.Position = lerp2(barTo, barFrom, self.health/self.maxHealth) - healthText.TextBounds*0.5 - HEALTH_TEXT_OFFSET;
313 end
314
315 visible.name.Visible = enabled and onScreen and options.name;
316 if visible.name.Visible then
317 local name = visible.name;
318 name.Size = interface.sharedSettings.textSize;
319 name.Font = interface.sharedSettings.textFont;
320 name.Color = parseColor(self, options.nameColor[1]);
321 name.Transparency = options.nameColor[2];
322 name.Outline = options.nameOutline;
323 name.OutlineColor = parseColor(self, options.nameOutlineColor, true);
324 name.Position = (corners.topLeft + corners.topRight)*0.5 - Vector2.yAxis*name.TextBounds.Y - NAME_OFFSET;
325 end
326
327 visible.distance.Visible = enabled and onScreen and self.distance and options.distance;
328 if visible.distance.Visible then
329 local distance = visible.distance;
330 distance.Text = round(self.distance) .. " studs";
331 distance.Size = interface.sharedSettings.textSize;
332 distance.Font = interface.sharedSettings.textFont;
333 distance.Color = parseColor(self, options.distanceColor[1]);
334 distance.Transparency = options.distanceColor[2];
335 distance.Outline = options.distanceOutline;
336 distance.OutlineColor = parseColor(self, options.distanceOutlineColor, true);
337 distance.Position = (corners.bottomLeft + corners.bottomRight)*0.5 + DISTANCE_OFFSET;
338 end
339
340 visible.weapon.Visible = enabled and onScreen and options.weapon;
341 if visible.weapon.Visible then
342 local weapon = visible.weapon;
343 weapon.Text = self.weapon;
344 weapon.Size = interface.sharedSettings.textSize;
345 weapon.Font = interface.sharedSettings.textFont;
346 weapon.Color = parseColor(self, options.weaponColor[1]);
347 weapon.Transparency = options.weaponColor[2];
348 weapon.Outline = options.weaponOutline;
349 weapon.OutlineColor = parseColor(self, options.weaponOutlineColor, true);
350 weapon.Position =
351 (corners.bottomLeft + corners.bottomRight)*0.5 +
352 (visible.distance.Visible and DISTANCE_OFFSET + Vector2.yAxis*visible.distance.TextBounds.Y or Vector2.zero);
353 end
354
355 visible.tracer.Visible = enabled and onScreen and options.tracer;
356 visible.tracerOutline.Visible = visible.tracer.Visible and options.tracerOutline;
357 if visible.tracer.Visible then
358 local tracer = visible.tracer;
359 tracer.Color = parseColor(self, options.tracerColor[1]);
360 tracer.Transparency = options.tracerColor[2];
361 tracer.To = (corners.bottomLeft + corners.bottomRight)*0.5;
362 tracer.From =
363 options.tracerOrigin == "Middle" and viewportSize*0.5 or
364 options.tracerOrigin == "Top" and viewportSize*Vector2.new(0.5, 0) or
365 options.tracerOrigin == "Bottom" and viewportSize*Vector2.new(0.5, 1);
366
367 local tracerOutline = visible.tracerOutline;
368 tracerOutline.Color = parseColor(self, options.tracerOutlineColor[1], true);
369 tracerOutline.Transparency = options.tracerOutlineColor[2];
370 tracerOutline.To = tracer.To;
371 tracerOutline.From = tracer.From;
372 end
373
374 hidden.arrow.Visible = enabled and (not onScreen) and options.offScreenArrow;
375 hidden.arrowOutline.Visible = hidden.arrow.Visible and options.offScreenArrowOutline;
376 if hidden.arrow.Visible and self.direction then
377 local arrow = hidden.arrow;
378 arrow.PointA = min2(max2(viewportSize*0.5 + self.direction*options.offScreenArrowRadius, Vector2.one*25), viewportSize - Vector2.one*25);
379 arrow.PointB = arrow.PointA - rotateVector(self.direction, 0.45)*options.offScreenArrowSize;
380 arrow.PointC = arrow.PointA - rotateVector(self.direction, -0.45)*options.offScreenArrowSize;
381 arrow.Color = parseColor(self, options.offScreenArrowColor[1]);
382 arrow.Transparency = options.offScreenArrowColor[2];
383
384 local arrowOutline = hidden.arrowOutline;
385 arrowOutline.PointA = arrow.PointA;
386 arrowOutline.PointB = arrow.PointB;
387 arrowOutline.PointC = arrow.PointC;
388 arrowOutline.Color = parseColor(self, options.offScreenArrowOutlineColor[1], true);
389 arrowOutline.Transparency = options.offScreenArrowOutlineColor[2];
390 end
391
392 local box3dEnabled = enabled and onScreen and options.box3d;
393 for i = 1, #box3d do
394 local face = box3d[i];
395 for i2 = 1, #face do
396 local line = face[i2];
397 line.Visible = box3dEnabled;
398 line.Color = parseColor(self, options.box3dColor[1]);
399 line.Transparency = options.box3dColor[2];
400 end
401
402 if box3dEnabled then
403 local line1 = face[1];
404 line1.From = corners.corners[i];
405 line1.To = corners.corners[i == 4 and 1 or i+1];
406
407 local line2 = face[2];
408 line2.From = corners.corners[i == 4 and 1 or i+1];
409 line2.To = corners.corners[i == 4 and 5 or i+5];
410
411 local line3 = face[3];
412 line3.From = corners.corners[i == 4 and 5 or i+5];
413 line3.To = corners.corners[i == 4 and 8 or i+4];
414 end
415 end
416end
417
418-- cham object
419local ChamObject = {};
420ChamObject.__index = ChamObject;
421
422function ChamObject.new(player, interface)
423 local self = setmetatable({}, ChamObject);
424 self.player = assert(player, "Missing argument #1 (Player expected)");
425 self.interface = assert(interface, "Missing argument #2 (table expected)");
426 self:Construct();
427 return self;
428end
429
430function ChamObject:Construct()
431 self.highlight = Instance.new("Highlight", container);
432 self.updateConnection = runService.Heartbeat:Connect(function()
433 self:Update();
434 end);
435end
436
437function ChamObject:Destruct()
438 self.updateConnection:Disconnect();
439 self.highlight:Destroy();
440
441 clear(self);
442end
443
444function ChamObject:Update()
445 local highlight = self.highlight;
446 local interface = self.interface;
447 local character = interface.getCharacter(self.player);
448 local options = interface.teamSettings[interface.isFriendly(self.player) and "friendly" or "enemy"];
449 local enabled = options.enabled and character and not
450 (#interface.whitelist > 0 and not find(interface.whitelist, self.player.UserId));
451
452 highlight.Enabled = enabled and options.chams;
453 if highlight.Enabled then
454 highlight.Adornee = character;
455 highlight.FillColor = parseColor(self, options.chamsFillColor[1]);
456 highlight.FillTransparency = options.chamsFillColor[2];
457 highlight.OutlineColor = parseColor(self, options.chamsOutlineColor[1], true);
458 highlight.OutlineTransparency = options.chamsOutlineColor[2];
459 highlight.DepthMode = options.chamsVisibleOnly and "Occluded" or "AlwaysOnTop";
460 end
461end
462
463-- instance class
464local InstanceObject = {};
465InstanceObject.__index = InstanceObject;
466
467function InstanceObject.new(instance, options)
468 local self = setmetatable({}, InstanceObject);
469 self.instance = assert(instance, "Missing argument #1 (Instance Expected)");
470 self.options = assert(options, "Missing argument #2 (table expected)");
471 self:Construct();
472 return self;
473end
474
475function InstanceObject:Construct()
476 local options = self.options;
477 options.enabled = options.enabled == nil and true or options.enabled;
478 options.text = options.text or "{name}";
479 options.textColor = options.textColor or { Color3.new(1,1,1), 1 };
480 options.textOutline = options.textOutline == nil and true or options.textOutline;
481 options.textOutlineColor = options.textOutlineColor or Color3.new();
482 options.textSize = options.textSize or 13;
483 options.textFont = options.textFont or 2;
484 options.limitDistance = options.limitDistance or false;
485 options.maxDistance = options.maxDistance or 150;
486
487 self.text = Drawing.new("Text");
488 self.text.Center = true;
489
490 self.renderConnection = runService.Heartbeat:Connect(function(deltaTime)
491 self:Render(deltaTime);
492 end);
493end
494
495function InstanceObject:Destruct()
496 self.renderConnection:Disconnect();
497 self.text:Remove();
498end
499
500function InstanceObject:Render()
501 local instance = self.instance;
502 if not instance or not instance.Parent then
503 return self:Destruct();
504 end
505
506 local text = self.text;
507 local options = self.options;
508 if not options.enabled then
509 text.Visible = false;
510 return;
511 end
512
513 local world = getPivot(instance).Position;
514 local position, visible, depth = worldToScreen(world);
515 if options.limitDistance and depth > options.maxDistance then
516 visible = false;
517 end
518
519 text.Visible = visible;
520 if text.Visible then
521 text.Position = position;
522 text.Color = options.textColor[1];
523 text.Transparency = options.textColor[2];
524 text.Outline = options.textOutline;
525 text.OutlineColor = options.textOutlineColor;
526 text.Size = options.textSize;
527 text.Font = options.textFont;
528 text.Text = options.text
529 :gsub("{name}", instance.Name)
530 :gsub("{distance}", round(depth))
531 :gsub("{position}", tostring(world));
532 end
533end
534
535-- interface
536local EspInterface = {
537 _hasLoaded = false,
538 _objectCache = {},
539 whitelist = {},
540 sharedSettings = {
541 textSize = 13,
542 textFont = 2,
543 limitDistance = false,
544 maxDistance = 150,
545 useTeamColor = false
546 },
547 teamSettings = {
548 enemy = {
549 enabled = true,
550 box = true,
551 boxColor = { Color3.new(1,0,0), 1 },
552 boxOutline = true,
553 boxOutlineColor = { Color3.new(), 1 },
554 boxFill = false,
555 boxFillColor = { Color3.new(1,0,0), 0.5 },
556 healthBar = false,
557 healthyColor = Color3.new(0,1,0),
558 dyingColor = Color3.new(1,0,0),
559 healthBarOutline = true,
560 healthBarOutlineColor = { Color3.new(), 0.5 },
561 healthText = false,
562 healthTextColor = { Color3.new(1,1,1), 1 },
563 healthTextOutline = true,
564 healthTextOutlineColor = Color3.new(),
565 box3d = false,
566 box3dColor = { Color3.new(1,0,0), 1 },
567 name = false,
568 nameColor = { Color3.new(1,1,1), 1 },
569 nameOutline = true,
570 nameOutlineColor = Color3.new(),
571 weapon = false,
572 weaponColor = { Color3.new(1,1,1), 1 },
573 weaponOutline = true,
574 weaponOutlineColor = Color3.new(),
575 distance = false,
576 distanceColor = { Color3.new(1,1,1), 1 },
577 distanceOutline = true,
578 distanceOutlineColor = Color3.new(),
579 tracer = false,
580 tracerOrigin = "Bottom",
581 tracerColor = { Color3.new(1,0,0), 1 },
582 tracerOutline = true,
583 tracerOutlineColor = { Color3.new(), 1 },
584 offScreenArrow = false,
585 offScreenArrowColor = { Color3.new(1,1,1), 1 },
586 offScreenArrowSize = 15,
587 offScreenArrowRadius = 150,
588 offScreenArrowOutline = true,
589 offScreenArrowOutlineColor = { Color3.new(), 1 },
590 chams = false,
591 chamsVisibleOnly = false,
592 chamsFillColor = { Color3.new(0.2, 0.2, 0.2), 0.5 },
593 chamsOutlineColor = { Color3.new(1,0,0), 0 },
594 },
595 friendly = {
596 enabled = true,
597 box = true,
598 boxColor = { Color3.new(0,1,0), 1 },
599 boxOutline = true,
600 boxOutlineColor = { Color3.new(), 1 },
601 boxFill = false,
602 boxFillColor = { Color3.new(0,1,0), 0.5 },
603 healthBar = false,
604 healthyColor = Color3.new(0,1,0),
605 dyingColor = Color3.new(1,0,0),
606 healthBarOutline = true,
607 healthBarOutlineColor = { Color3.new(), 0.5 },
608 healthText = false,
609 healthTextColor = { Color3.new(1,1,1), 1 },
610 healthTextOutline = true,
611 healthTextOutlineColor = Color3.new(),
612 box3d = false,
613 box3dColor = { Color3.new(0,1,0), 1 },
614 name = false,
615 nameColor = { Color3.new(1,1,1), 1 },
616 nameOutline = true,
617 nameOutlineColor = Color3.new(),
618 weapon = false,
619 weaponColor = { Color3.new(1,1,1), 1 },
620 weaponOutline = true,
621 weaponOutlineColor = Color3.new(),
622 distance = false,
623 distanceColor = { Color3.new(1,1,1), 1 },
624 distanceOutline = true,
625 distanceOutlineColor = Color3.new(),
626 tracer = false,
627 tracerOrigin = "Bottom",
628 tracerColor = { Color3.new(0,1,0), 1 },
629 tracerOutline = true,
630 tracerOutlineColor = { Color3.new(), 1 },
631 offScreenArrow = false,
632 offScreenArrowColor = { Color3.new(1,1,1), 1 },
633 offScreenArrowSize = 15,
634 offScreenArrowRadius = 150,
635 offScreenArrowOutline = true,
636 offScreenArrowOutlineColor = { Color3.new(), 1 },
637 chams = false,
638 chamsVisibleOnly = false,
639 chamsFillColor = { Color3.new(0.2, 0.2, 0.2), 0.5 },
640 chamsOutlineColor = { Color3.new(0,1,0), 0 }
641 }
642 }
643};
644
645function EspInterface.AddInstance(instance, options)
646 local cache = EspInterface._objectCache;
647 if cache[instance] then
648 warn("Instance handler already exists.");
649 else
650 cache[instance] = { InstanceObject.new(instance, options) };
651 end
652 return cache[instance][1];
653end
654
655function EspInterface.Load()
656 assert(not EspInterface._hasLoaded, "Esp has already been loaded.");
657
658 local function createObject(player)
659 EspInterface._objectCache[player] = {
660 EspObject.new(player, EspInterface),
661 ChamObject.new(player, EspInterface)
662 };
663 end
664
665 local function removeObject(player)
666 local object = EspInterface._objectCache[player];
667 if object then
668 for i = 1, #object do
669 object[i]:Destruct();
670 end
671 EspInterface._objectCache[player] = nil;
672 end
673 end
674
675 local plrs = players:GetPlayers();
676 for i = 2, #plrs do
677 createObject(plrs[i]);
678 end
679
680 EspInterface.playerAdded = players.PlayerAdded:Connect(createObject);
681 EspInterface.playerRemoving = players.PlayerRemoving:Connect(removeObject);
682 EspInterface._hasLoaded = true;
683end
684
685function EspInterface.Unload()
686 assert(EspInterface._hasLoaded, "Esp has not been loaded yet.");
687
688 for index, object in next, EspInterface._objectCache do
689 for i = 1, #object do
690 object[i]:Destruct();
691 end
692 EspInterface._objectCache[index] = nil;
693 end
694
695 EspInterface.playerAdded:Disconnect();
696 EspInterface.playerRemoving:Disconnect();
697 EspInterface._hasLoaded = false;
698end
699
700-- game specific functions
701function EspInterface.getWeapon(player)
702 return "Unknown";
703end
704
705function EspInterface.isFriendly(player)
706 return player.Team and player.Team == localPlayer.Team;
707end
708
709function EspInterface.getTeamColor(player)
710 return player.Team and player.Team.TeamColor and player.Team.TeamColor.Color;
711end
712
713function EspInterface.getCharacter(player)
714 for i, v in ipairs(game.Workspace:GetChildren()) do
715 if v:IsA("Model") and v:FindFirstChild("HumanoidRootPart") then
716 print(v:GetFullName())
717 return v;
718 end
719 end
720end
721
722function EspInterface.getHealth(player)
723 local character = player and EspInterface.getCharacter(player);
724 local humanoid = character and findFirstChildOfClass(character, "Humanoid");
725 if humanoid then
726 return humanoid.Health, humanoid.MaxHealth;
727 end
728 return 100, 100;
729end
730
731return EspInterface;
732
733